• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            woaidongmao

            文章均收錄自他人博客,但不喜標題前加-[轉貼],因其丑陋,見諒!~
            隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
            數據加載中……

            使用PHP Embed SAPI實現Opcodes查看器

            http://www.laruence.com/2008/09/23/539.html

             

            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 instal

            最后,記得要將生成的libphp5.so復制到運行時庫的目錄,我直接拷貝到了/lib/, 否則會在運行你自己的embed程序的時候報錯:

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

            如果你對PHP的SAPI還不熟悉的話,我建議你看看我的這篇文章:深入理解Zend SAPIs(Zend SAPI Internals)
            這個時候,你就可以在你的C代碼中,嵌入PHP腳本解析器了, 我的例子:

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

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

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

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

            1. int main(int argc, char **argv){
            2.     zend_op_array *op_array;
            3.     zend_file_handle file_handle;
            4.  
            5.     if(argc != 2) {
            6.         printf("usage: op_dumper <script>\n");
            7.         return 1;
            8.     }
            9.     PHP_EMBED_START_BLOCK(argc,argv);
            10.     printf("Script: %s\n", argv[1]);
            11.     file_handle.filename = argv[1];
            12.     file_handle.free_filename = 0;
            13.     file_handle.type = ZEND_HANDLE_FILENAME;
            14.     file_handle.opened_path = NULL;
            15.     op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC);
            16.     if(!op_array) {
            17.         printf("Error parsing script: %s\n", file_handle.filename);
            18.         return 1;
            19.     }
            20.     dump_op_array(op_array);
            21.     PHP_EMBED_END_BLOCK();
            22.     return 0;
            23. }

            編譯,運行測試腳本(sample.php):
            sample.php:

            1.    echo "laruence";

            命令:

            1. ./opcodes_dumper sample.ph

            得到輸出結果(如果你對下面的結果很迷惑,那么建議你再看看我的這篇文章:深入理解PHP原理之Opcodes):

            1. Script: sample.php
            2. opnum line opcode op1 op2 result
            3.     0 2 ZEND_ECHO "laruence"
            4.     1 4 ZEND_RETURN

            呵呵,怎么樣,是不是很好玩呢?
            源碼地址:http://code.google.com/p/opcodesdumper/

            posted on 2011-06-19 20:53 肥仔 閱讀(516) 評論(0)  編輯 收藏 引用 所屬分類: Web-后臺

            亚洲国产精品综合久久网络| 人妻丰满AV无码久久不卡| 国产精品久久久久9999高清| 97久久香蕉国产线看观看| 精品久久一区二区| 婷婷久久五月天| 久久ww精品w免费人成| 国产精品99久久久久久董美香| 久久精品国产99久久香蕉| 久久福利资源国产精品999| 久久国产免费观看精品3| 久久午夜福利电影| 国产亚洲综合久久系列| 久久青青草原精品国产软件| 亚洲精品乱码久久久久久中文字幕| 久久99国产精品99久久| 亚洲欧洲中文日韩久久AV乱码| 国产一级持黄大片99久久| 综合久久精品色| 国产精品亚洲美女久久久| 日日躁夜夜躁狠狠久久AV| 欧美午夜A∨大片久久 | 久久高清一级毛片| 久久亚洲中文字幕精品有坂深雪| 亚洲一本综合久久| 国产精品99久久免费观看| 久久久精品国产免大香伊| 久久久久久久综合日本| 色综合久久最新中文字幕| 久久综合给合久久狠狠狠97色| 亚洲午夜福利精品久久| 久久精品国产黑森林| 青青草原综合久久大伊人精品| 99久久99这里只有免费的精品| 久久人爽人人爽人人片AV| 久久久久久综合网天天| 久久久精品人妻一区二区三区蜜桃 | 久久99精品国产麻豆宅宅| 久久婷婷五月综合色99啪ak| 九九久久精品国产| 日韩亚洲国产综合久久久|