php embed init,使用PHP Embed SAPI实现Opcodes查看器

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 = 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)

编译成功以后, 运行,我们可以看到, 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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值