《PHP學(xué)習(xí):如何使用PHP Embed SAPI實現(xiàn)Opcodes查看器》要點(diǎn):
本文介紹了PHP學(xué)習(xí):如何使用PHP Embed SAPI實現(xiàn)Opcodes查看器,希望對您有用。如果有疑問,可以聯(lián)系我們。
PHP實例PHP提供了一個Embed SAPI,也便是說,PHP容許你在C/C++語言中調(diào)用PHP/ZE提供的函數(shù).本文就通過基于Embed SAPI實現(xiàn)一個PHP的opcodes查看器.
PHP實例起首,下載PHP源碼以供編譯, 我現(xiàn)在使用的是PHP5.3 alpha2
PHP實例進(jìn)入源碼目次:
PHP實例?./configure --enable-embed --with-config-file-scan-dir=/etc/php.d --with-mysql? --with-config-file-path=/etc/
?./make
?./make install
PHP實例最后,記得要將生成的libphp5.so復(fù)制到運(yùn)行時庫的目錄,我直接拷貝到了/lib/, 否則會在運(yùn)行你本身的embed程序的時候報錯:
PHP實例./embed: error while loading shared libraries: libphp5.so: cannot open shared object file: No such file or directory
PHP實例如果你對PHP的SAPI還不熟悉的話,我建議你看看我的這篇文章:深入懂得Zend SAPIs(Zend SAPI Internals)
這個時候,你就可以在你的C代碼中,嵌入PHP腳本解析器了, 我的例子:
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;
}
PHP實例然后便是要指明include path了,一個簡單的Makefile
PHP實例
CC = gcc
CFLAGS = -I/usr/local/include/php/ \
-I/usr/local/include/php/main \
-I/usr/local/include/php/Zend \
-I/usr/local/include/php/TSRM \
-Wall -g
LDFLAGS = -lstdc++ -L/usr/local/lib -lphp5
ALL:
$(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)
PHP實例編譯勝利以后, 運(yùn)行,我們可以看到, stdout輸出 Hello World!
PHP實例基于這個,我們就可以很容易的實現(xiàn)一個類似于vld的Opcodes dumper:
首先我們界說opcode的轉(zhuǎn)換函數(shù)(全部的opcodes可以查看Zend/zend_vm_opcodes.h);
PHP實例
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;
PHP實例然后界說zval和znode的輸出函數(shù):
PHP實例
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;
}
}
PHP實例?然后界說op_array的輸出函數(shù):
PHP實例
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);
}
}
}
PHP實例最后,便是程序的主函數(shù)了:
PHP實例
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;
}
PHP實例編譯,運(yùn)行測試劇本(sample.php):
PHP實例敕令:
PHP實例得到輸出成果(如果你對下面的成果很迷惑,那么建議你再看看我的這篇文章:深入理解PHP原理之Opcodes):
PHP實例Script: sample.php
PHP實例opnum?? line???????????????????????? opcode????????????????????????????????????? op1????????????????????????????????????? op2?????????????????????????????????? result
??? 0????? 2????????????????????? ZEND_ECHO?????????????????????????????? "laruence"
??? 1????? 4??????????????????? ZEND_RETURN??????????????????????????????????????? 1
PHP實例呵呵,怎樣樣,是不是很好玩呢?
《PHP學(xué)習(xí):如何使用PHP Embed SAPI實現(xiàn)Opcodes查看器》是否對您有啟發(fā),歡迎查看更多與《PHP學(xué)習(xí):如何使用PHP Embed SAPI實現(xiàn)Opcodes查看器》相關(guān)教程,學(xué)精學(xué)透。維易PHP學(xué)院為您提供精彩教程。
轉(zhuǎn)載請注明本頁網(wǎng)址:
http://www.snjht.com/jiaocheng/8430.html