加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

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

发布时间:2020-12-13 02:55:48 所属栏目:PHP教程 来源:网络整理
导读:《:如何使用PHP Embed SAPI实现Opcodes查看器》要点: 本文介绍了:如何使用PHP Embed SAPI实现Opcodes查看器,希望对您有用。如果有疑问,可以联系我们。 PHP实例 PHP提供了一个Embed SAPI,也便是说,PHP容许你在C/C++语言中调用PHP/ZE提供的函数.本文就通

《:如何使用PHP Embed SAPI实现Opcodes查看器》要点:
本文介绍了:如何使用PHP Embed SAPI实现Opcodes查看器,希望对您有用。如果有疑问,可以联系我们。

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

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

PHP实例进入源码目次:

PHP实例?./configure --enable-embed --with-config-file-scan-dir=/etc/php.d --with-mysql? --with-config-file-path=/etc/
?./make
?./make install

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

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

PHP实例如果你对PHP的SAPI还不熟悉的话,我建议你看看我的这篇文章:深入懂得Zend SAPIs(Zend SAPI Internals)
这个时候,你就可以在你的C代码中,嵌入PHP脚本解析器了,我的例子:

PHP实例
#include "sapi/embed/php_embed.h"
int main(int argc,char * argv[]){
 PHP_EMBED_START_BLOCK(argc,argv);
 char * script = " print 'Hello World!';";
 zend_eval_string(script,NULL,"Simple Hello World App" TSRMLS_CC);
 PHP_EMBED_END_BLOCK();
 return 0;
}

PHP实例然后便是要指明include path了,一个简单的Makefile

PHP实例
CC = gcc
CFLAGS = -I/usr/local/include/php/ 

   -I/usr/local/include/php/main 

   -I/usr/local/include/php/Zend 

   -I/usr/local/include/php/TSRM 

   -Wall -g
LDFLAGS = -lstdc++ -L/usr/local/lib -lphp5
ALL:
 $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)

PHP实例编译胜利以后,运行,我们可以看到,stdout输出 Hello World!

PHP实例基于这个,我们就可以很容易的实现一个类似于vld的Opcodes dumper:
首先我们界说opcode的转换函数(全部的opcodes可以查看Zend/zend_vm_opcodes.h);

PHP实例
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;

PHP实例然后界说zval和znode的输出函数:

PHP实例
 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,"%f",z->value.dval);
   return buffer;
  case IS_STRING:
   snprintf(buffer,""%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,"$%d",n->u.var/sizeof(temp_variable));
   return buffer;
   break;
  case IS_TMP_VAR:
   snprintf(buffer,"~%d",n->u.var/sizeof(temp_variable));
   return buffer;
   break;
  default:
   return "";
   break;
 }
}

PHP实例?然后界说op_array的输出函数:

PHP实例
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);
  }
 }
}

PHP实例最后,便是程序的主函数了:

PHP实例
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;
}

PHP实例编译,运行测试剧本(sample.php):

代码如下:

sample.php:
?? echo "laruence";

PHP实例敕令:

代码如下:

./opcodes_dumper? sample.php

PHP实例得到输出成果(如果你对下面的成果很迷惑,那么建议你再看看我的这篇文章:深入理解PHP原理之Opcodes):

PHP实例Script: sample.php

PHP实例opnum?? line???????????????????????? opcode????????????????????????????????????? op1????????????????????????????????????? op2?????????????????????????????????? result
??? 0????? 2????????????????????? ZEND_ECHO?????????????????????????????? "laruence"
??? 1????? 4??????????????????? ZEND_RETURN??????????????????????????????????????? 1

PHP实例呵呵,怎样样,是不是很好玩呢?

《:如何使用PHP Embed SAPI实现Opcodes查看器》是否对您有启发,欢迎查看更多与《:如何使用PHP Embed SAPI实现Opcodes查看器》相关教程,学精学透。编程之家 52php.cn为您提供精彩教程。

(编辑:李大同)

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

    推荐文章
      热点阅读