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

            欧美精品一区二区精品久久| 久久久这里有精品| 亚洲色欲久久久综合网| 亚洲欧美国产精品专区久久| 久久99久久成人免费播放| 秋霞久久国产精品电影院| 国产精品一区二区久久| 国产精品久久久久影院色| 99re久久精品国产首页2020| 久久99精品久久久久久hb无码| 色综合久久无码五十路人妻| 日韩人妻无码精品久久久不卡| 色婷婷综合久久久久中文一区二区| 精品伊人久久大线蕉色首页| 亚洲精品无码成人片久久| 伊人久久综合无码成人网| 狠狠色婷婷久久一区二区三区| 国产一级持黄大片99久久| 国产成人久久精品二区三区| 久久se精品一区二区影院| 亚洲精品97久久中文字幕无码| 久久久久久综合网天天| 99久久99久久久精品齐齐| 99久久国产亚洲高清观看2024| 免费一级欧美大片久久网| 三级三级久久三级久久| 国产精品久久久久国产A级| 国产无套内射久久久国产| 亚洲欧美日韩精品久久亚洲区| 日韩av无码久久精品免费| 99热热久久这里只有精品68| 免费无码国产欧美久久18| 久久精品这里热有精品| 亚洲国产精品一区二区三区久久| 久久久久久九九99精品| 精品国产青草久久久久福利| 久久精品国产免费观看三人同眠| 久久精品国产福利国产秒| 奇米影视7777久久精品人人爽| 国产欧美一区二区久久| 久久精品亚洲AV久久久无码|