如何使用PHP Embed SAPI實現Opcodes查看器_php執行個體

來源:互聯網
上載者:User

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指令碼解析器了, 我的例子:

#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;}

然後就是要指明include path了,一個簡單的Makefile

CC = gccCFLAGS = -I/usr/local/include/php/ \   -I/usr/local/include/php/main \   -I/usr/local/include/php/Zend \   -I/usr/local/include/php/TSRM \   -Wall -gLDFLAGS = -lstdc++ -L/usr/local/lib -lphp5ALL: $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)

編譯成功以後, 運行,我們可以看到, stdout輸出 Hello World!

基於這個,我們就可以很容易的實現一個類似於vld的Opcodes dumper:
首先我們定義opcode的轉換函式(全部的opcodes可以查看Zend/zend_vm_opcodes.h);

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 %040s\n", 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 %040s\n", "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: %s\n", 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: %s\n", 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

呵呵,怎麼樣,是不是很好玩呢?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.