首页建站经验 如何使用PHP Embed SAPI实现Opcodes查看器

如何使用PHP Embed SAPI实现Opcodes查看器

这篇文章主要介绍了如何使用PHP Embed SAPI实现Opcodes查看器的相关资料,需要的朋友可以参考下。PHP提供了一个Embed SAPI,也就是说,PHP容许你在C/C++语言中调用PHP/ZE提供的…

这篇文章主要介绍了如何使用PHP Embed SAPI实现Opcodes查看器的相关资料,需要的朋友可以参考下。

PHP提供了一个Embed SAPI,也就是说,PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。

首先,下载PHP源码以供编译, 我现在使用的是PHP5.3 alpha2

进入源码目录:

  1. ./configure --enable-embed --with-config-file-scan-dir=/etc/php.d --with-mysql  --with-config-file-path=/etc/ 
  2. ./make 
  3. ./make install 

最后,记得要将生成的libphp5.so复制到运行时库的目录,我直接拷贝到了/lib/, 否则会在运行你自己的embed程序的时候报错:

./embed: error while loading shared libraries: libphp5.so: cannot open shared object file: No such file or directory

如果你对PHP的SAPI还不熟悉的话,我建议你看看我的这篇文章:深入理解Zend SAPIs(Zend SAPI Internals)

这个时候,你就可以在你的C代码中,嵌入PHP脚本解析器了, 我的例子:

  1. #include "sapi/embed/php_embed.h" 
  2. int main(int argc, char * argv[]){ 
  3.  PHP_EMBED_START_BLOCK(argc,argv); 
  4.  char * script = " print 'Hello World!';"
  5.  zend_eval_string(script, NULL, 
  6.           "Simple Hello World App" TSRMLS_CC); 
  7.  PHP_EMBED_END_BLOCK(); 
  8.  return 0; 

然后就是要指明include path了,一个简单的Makefile

  1. CC = gcc 
  2. CFLAGS = -I/usr/local/include/php/ / 
  3.    -I/usr/local/include/php/main / 
  4.    -I/usr/local/include/php/Zend / 
  5.    -I/usr/local/include/php/TSRM / 
  6.    -Wall -g 
  7. LDFLAGS = -lstdc++ -L/usr/local/lib -lphp5 
  8. ALL: 
  9.  $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS) 

编译成功以后, 运行,我们可以看到, stdout输出 Hello World!

基于这个,我们就可以很容易的实现一个类似于vld的Opcodes dumper:

首先我们定义opcode的转换函数(全部的opcodes可以查看Zend/zend_vm_opcodes.h);

  1. char *opname(zend_uchar opcode){ 
  2.  switch(opcode) { 
  3.   case ZEND_NOP: return "ZEND_NOP"break
  4.   case ZEND_ADD: return "ZEND_ADD"break
  5.   case ZEND_SUB: return "ZEND_SUB"break
  6.   case ZEND_MUL: return "ZEND_MUL"break
  7.   case ZEND_DIV: return "ZEND_DIV"break
  8.   case ZEND_MOD: return "ZEND_MOD"break
  9.   case ZEND_SL: return "ZEND_SL"break
  10.   case ZEND_SR: return "ZEND_SR"break
  11.   case ZEND_CONCAT: return "ZEND_CONCAT"break
  12.   case ZEND_BW_OR: return "ZEND_BW_OR"break
  13.   case ZEND_BW_AND: return "ZEND_BW_AND"break
  14.   case ZEND_BW_XOR: return "ZEND_BW_XOR"break
  15.   case ZEND_BW_NOT: return "ZEND_BW_NOT"break
  16.   /*...省略 ....*/ 
  17.   default : return "UNKNOW"break

然后定义zval和znode的输出函数:

  1. char *format_zval(zval *z) 
  2.  static char buffer[BUFFER_LEN]; 
  3.  int len; 
  4.  switch(z->type) { 
  5.   case IS_NULL
  6.    return "NULL"
  7.   case IS_LONG
  8.   case IS_BOOL
  9.    snprintf(buffer, BUFFER_LEN, "%d", z->value.lval); 
  10.    return buffer; 
  11.   case IS_DOUBLE
  12.    snprintf(buffer, BUFFER_LEN, "%f", z->value.dval); 
  13.    return buffer; 
  14.   case IS_STRING
  15.    snprintf(buffer, BUFFER_LEN, "/"%s/"", z->value.str.val); 
  16.    return buffer; 
  17.   case IS_ARRAY
  18.   case IS_OBJECT
  19.   case IS_RESOURCE
  20.   case IS_CONSTANT: 
  21.   case IS_CONSTANT_ARRAY: 
  22.    return ""
  23.   default
  24.    return "unknown"
  25.  } 
  26. char * format_znode(znode *n){ 
  27.  static char buffer[BUFFER_LEN]; 
  28.  switch (n->op_type) { 
  29.   case IS_CONST: 
  30.    return format_zval(&n->u.constant); 
  31.    break
  32.   case IS_VAR: 
  33.    snprintf(buffer, BUFFER_LEN, "$%d", n->u.var/sizeof(temp_variable)); 
  34.    return buffer; 
  35.    break
  36.   case IS_TMP_VAR: 
  37.    snprintf(buffer, BUFFER_LEN, "~%d", n->u.var/sizeof(temp_variable)); 
  38.    return buffer; 
  39.    break
  40.   default
  41.    return ""
  42.    break
  43.  } 

然后定义op_array的输出函数:

  1. void dump_op(zend_op *op, int num){ 
  2.  printf("%5d %5d %30s %040s %040s %040s/n", num, op->lineno, 
  3.    opname(op->opcode), 
  4.    format_znode(&op->op1), 
  5.    format_znode(&op->op2), 
  6.    format_znode(&op->result)) ; 
  7. void dump_op_array(zend_op_array *op_array){ 
  8.  if(op_array) { 
  9.   int i; 
  10.   printf("%5s %5s %30s %040s %040s %040s/n""opnum""line""opcode""op1""op2""result"); 
  11.   for(i = 0; i < op_array->last; i++) { 
  12.    dump_op(&op_array->opcodes[i], i); 
  13.   } 
  14.  } 

最后,就是程序的主函数了:

  1. int main(int argc, char **argv){ 
  2.  zend_op_array *op_array; 
  3.  zend_file_handle file_handle; 
  4.  if(argc != 2) { 
  5.   printf("usage: op_dumper 
上一篇php ImageMagick windows下安装教程
下一篇 PHP使用ODBC连接数据库的方法
admin

作者: admin

这里可以再内容模板定义一些文字和说明,也可以调用对应作者的简介!或者做一些网站的描述之类的文字或者HTML!

为您推荐

评论列表()

    联系我们

    联系我们

    0898-88888888

    在线咨询: QQ交谈

    邮箱: email@wangzhan.com

    工作时间:周一至周五,9:00-17:30,节假日休息

    关注微信
    微信扫一扫关注我们

    微信扫一扫关注我们

    关注微博
    返回顶部