加入收藏 | 设为首页 | 会员中心 | 我要投稿 济源站长网 (https://www.0391zz.cn/)- 数据工具、数据仓库、行业智能、CDN、运营!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

怎样使用PHP Embed SAPI实现Opcodes查看器

发布时间:2022-06-17 08:27:49 所属栏目:PHP教程 来源:互联网
导读:这篇文章主要介绍了如何使用PHP Embed SAPI实现Opcodes查看器的相关资料,需要的朋友可以参考下。 PHP提供了一个Embed SAPI,也就是说,PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。 首先,下载PHP源
  这篇文章主要介绍了如何使用PHP Embed SAPI实现Opcodes查看器的相关资料,需要的朋友可以参考下。
 
  PHP提供了一个Embed SAPI,也就是说,PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。
 
  首先,下载PHP源码以供编译, 我现在使用的是PHP5.3 alpha2
 
  进入源码目录:
 
  ./configure --enable-embed --with-config-file-scan-dir=/etc/php.d --with-mysql  --with-config-file-path=/etc/
  ./make
  ./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)
 
  首先我们定义opcode的转换函数(全部的opcodes可以查看Zend/zend_vm_opcodes.h);
 怎样使用PHP Embed SAPI实现Opcodes查看器
  char *opname(zend_uchar opcode){
   switch(opcode) {
    case ZEND_NOP: return "ZEND_NOP"; break;
    case ZEND_ADD: return "ZEND_ADD"; break;
    case ZEND_SUB: return "ZEND_SUB"; break;
    case ZEND_MUL: return "ZEND_MUL"; break;
    case ZEND_DIV: return "ZEND_DIV"; break;
    case ZEND_MOD: return "ZEND_MOD"; break;
    case ZEND_SL: return "ZEND_SL"; break;
    case ZEND_SR: return "ZEND_SR"; break;
    case ZEND_CONCAT: return "ZEND_CONCAT"; break;
    case ZEND_BW_OR: return "ZEND_BW_OR"; break;
    case ZEND_BW_AND: return "ZEND_BW_AND"; break;
    case ZEND_BW_XOR: return "ZEND_BW_XOR"; break;
    case ZEND_BW_NOT: return "ZEND_BW_NOT"; break;
    /*...省略 ....*/
    default : return "UNKNOW"; break;
  然后定义zval和znode的输出函数:
 
  char *format_zval(zval *z)
  {
   static char buffer[BUFFER_LEN];
   int len;
   switch(z->type) {
    case IS_NULL:
     return "NULL";
    case IS_LONG:
    case IS_BOOL:
     snprintf(buffer, BUFFER_LEN, "%d", z->value.lval);
     return buffer;
    case IS_DOUBLE:
     snprintf(buffer, BUFFER_LEN, "%f", z->value.dval);
     return buffer;
    case IS_STRING:
     snprintf(buffer, BUFFER_LEN, ""%s"", z->value.str.val);
     return buffer;
    case IS_ARRAY:
    case IS_OBJECT:
    case IS_RESOURCE:
    case IS_CONSTANT:
    case IS_CONSTANT_ARRAY:
     return "";
    default:
     return "unknown";
   }
  }
  char * format_znode(znode *n){
   static char buffer[BUFFER_LEN];
   switch (n->op_type) {
    case IS_CONST:
     return format_zval(&n->u.constant);
     break;
    case IS_VAR:
     snprintf(buffer, BUFFER_LEN, "$%d", n->u.var/sizeof(temp_variable));
     return buffer;
     break;
    case IS_TMP_VAR:
     snprintf(buffer, BUFFER_LEN, "~%d", n->u.var/sizeof(temp_variable));
     return buffer;
     break;
    default:
     return "";
     break;
   }
  }
  然后定义op_array的输出函数:
 
  void dump_op(zend_op *op, int num){
   printf("%5d %5d %30s %040s %040s %040sn", num, op->lineno,
     opname(op->opcode),
     format_znode(&op->op1),
     format_znode(&op->op2),
     format_znode(&op->result)) ;
  }
  void dump_op_array(zend_op_array *op_array){
   if(op_array) {
    int i;
    printf("%5s %5s %30s %040s %040s %040sn", "opnum", "line", "opcode", "op1", "op2", "result");
    for(i = 0; i < op_array->last; i++) {
     dump_op(&op_array->opcodes[i], i);
    }
   }
  }
  最后,就是程序的主函数了:
 
  int main(int argc, char **argv){
   zend_op_array *op_array;
   zend_file_handle file_handle;
   if(argc != 2) {
    printf("usage: op_dumper <script>n");
    return 1;
   }
   PHP_EMBED_START_BLOCK(argc,argv);
   printf("Script: %sn", argv[1]);
   file_handle.filename = argv[1];
   file_handle.free_filename = 0;
   file_handle.type = ZEND_HANDLE_FILENAME;
   file_handle.opened_path = NULL;
   op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);
   if(!op_array) {
    printf("Error parsing script: %sn", file_handle.filename);
    return 1;
   }
   dump_op_array(op_array);
   PHP_EMBED_END_BLOCK();
   return 0;
  }
  编译,运行测试脚本(sample.php):
 
  sample.php:
 
  echo "laruence";
 
  命令:./opcodes_dumper  sample.php
 
  得到输出结果(如果你对下面的结果很迷惑,那么建议你再看看我的这篇文章:深入理解PHP原理之Opcodes):
 
  Script: sample.php
  opnum   line                         opcode                                      op1                                      op2                                   result
      0      2                      ZEND_ECHO                               "laruence"
      1      4                    ZEND_RETURN                                        1
  呵呵,怎么样,是不是很好玩呢?
 
 

(编辑:济源站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读