• <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 肥仔 閱讀(519) 評論(0)  編輯 收藏 引用 所屬分類: Web-后臺

            国产精品成人99久久久久91gav| 四虎国产精品免费久久5151| 久久久中文字幕日本| 久久久久一级精品亚洲国产成人综合AV区 | 久久亚洲精品国产精品婷婷| 久久精品免费全国观看国产| 日韩精品无码久久久久久| 国产精品久久久久久吹潮| 久久嫩草影院免费看夜色| 性欧美大战久久久久久久久| 国产精品九九久久免费视频| 久久婷婷五月综合97色直播| 99久久免费只有精品国产| 亚洲AV乱码久久精品蜜桃| 久久无码精品一区二区三区| 久久久无码一区二区三区| 久久久久亚洲AV无码专区网站| 久久99亚洲网美利坚合众国| 久久亚洲精品国产亚洲老地址 | 久久99热这里只有精品国产| 99久久免费国产精品| 久久ZYZ资源站无码中文动漫| 久久国产免费| 91性高湖久久久久| 久久99精品久久久久久久不卡| 欧美日韩精品久久久免费观看| 久久国产福利免费| 国产精品99久久久久久宅男 | 合区精品久久久中文字幕一区| 欧美日韩中文字幕久久伊人| 久久久久女人精品毛片| 奇米综合四色77777久久| 亚洲精品第一综合99久久| 香蕉aa三级久久毛片| 一级做a爰片久久毛片免费陪| 精品水蜜桃久久久久久久| 久久精品国产99久久久香蕉| 久久精品无码一区二区三区日韩| 国产激情久久久久影院小草| 国产精品九九久久免费视频 | 久久精品欧美日韩精品|