当前位置:Gxlcms > PHP教程 > 如何使用PHPEmbedSAPI实现Opcodes查看器,sapiopcodes_PHP教程

如何使用PHPEmbedSAPI实现Opcodes查看器,sapiopcodes_PHP教程

时间:2021-07-01 10:21:17 帮助过:18人阅读

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


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)
这个时候,你就可以在你的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;
  9. }

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

然后定义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. }
  8. void dump_op_array(zend_op_array *op_array){
  9. if(op_array) {
  10. int i;
  11. printf("%5s %5s %30s %040s %040s %040s\n", "opnum", "line", "opcode", "op1", "op2", "result");
  12. for(i = 0; i < op_array->last; i++) {
  13. dump_op(&op_array->opcodes[i], i);
  14. }
  15. }
  16. }

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

  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
  6. <div style="display:none">
  7. <div class="login-box" id="login-dialog">
  8. <div class="login-top"><a class="current" rel="nofollow" id="login1" onclick="setTab('login',1,2);">登录</a></div>
  9. <div class="login-form" id="nav-signin">
  10. <!-- <div class="login-ico"><a rel="nofollow" class="qq" id="qqlogin" target="_blank" href="/user-center-qqlogin.html"> QQ </a></div> -->
  11. <div class="login-box-form" id="con_login_1">
  12. <form id="loginform" action="/user-center-login.html" method="post" onsubmit="return false;">
  13. <p class="int-text">
  14. <input class="email" id="username" name="username" type="text" value="用户名或Email" onfocus="if(this.value=='用户名或Email'){this.value='';}" onblur="if(this.value==''){this.value='用户名或Email';};"></p>
  15. <p class="int-text">
  16. <input class="password1" type="password" id="password" name="password" value="******" onblur="if(this.value=='') this.value='******';" onfocus="if(this.value=='******') this.value='';">
  17. </p>
  18. <p class="int-info">
  19. <label class="ui-label"> </label>
  20. <label for="agreement" class="ui-label-checkbox">
  21. <input type="checkbox" value="" name="cookietime" id="cookietime" checked="checked">
  22. <input type="hidden" name="notforward" id="notforward" value="1">
  23. <input type="hidden" name="dosubmit" id="dosubmit" value="1">记住我的登录 </label>
  24. <a rel="nofollow" class="aright" href="/user-center-forgetpwd.html" target="_blank"> 忘记密码? </a></p>
  25. <p class="int-btn"><a rel="nofollow" id="loginbt" class="loginbtn"><span>登录</span></a></p>
  26. </form>
  27. </div>
  28. <form id="regform" action="/user-center-reg.html" method="post">
  29. <div class="login-reg" style="display: none;" id="con_login_2">
  30. <input type="hidden" name="t" id="t">
  31. <p class="int-text">
  32. <input id="email" name="email" type="text" value="Email" onfocus="if(this.value=='Email'){this.value='';}" onblur="if(this.value==''){this.value='Email';};"></p>
  33. <p class="int-text">
  34. <input id="uname" name="username" type="text" value="用户名或昵称" onfocus="if(this.value=='用户名或昵称'){this.value='';}" onblur="if(this.value==''){this.value='用户名或昵称';};"></p>
  35. <p class="int-text">
  36. <input type="password" id="pwd" name="password" value="******" onblur="if(this.value=='') this.value='******';" onfocus="if(this.value=='******') this.value='';"> </p>
  37. <p class="int-text1"><span class="inputbox">
  38. <input id="validate" name="validate" type="text" value="验证码" onfocus="if(this.value=='验证码'){this.value='';}" onblur="if(this.value==''){this.value='验证码';};">
  39. </span><span class="yzm-img"><img src="/user-checkcode-index" alt="看不清楚换一张" id="indexlogin"></span></p>
  40. <p class="int-info">
  41. <label>
  42. <input value="" name="agreement" id="agreement" checked="checked" type="checkbox">
  43. 我已阅读<a rel="nofollow" href="/user-center-agreement.html">用户协议</a>及<a rel="nofollow" href="/user-center-agreement.html">版权声明</a></label>
  44. </p>
  45. <p class="int-btn"><input type="hidden" name="dosubmit">
  46. <a rel="nofollow" class="loginbtn" id="register"><span>注册</span></a></p>
  47. </div>
  48. </form>
  49. </div>
  50. </div>
  51. </div>