How to use PHPEmbedSAPI to implement the Opcodes viewer and sapiopcodes. How to use PHPEmbedSAPI to implement the Opcodes viewer, sapiopcodesPHP provides an EmbedSAPI, that is, PHP allows you to call functions provided by PHPZE in the CC ++ language. This article describes how to use PHP Embed SAPI to implement Opcodes viewer and sapiopcodes
PHP provides an Embed SAPI, that is, PHP allows you to call functions provided by PHP/ZE in C/C ++. This article uses the Embed SAPI to implement a PHP opcodes viewer.
First, download the PHP source code for Compilation. now I am using PHP5.3 alpha2
Go to the source code directory:
./Configure -- enable-embed -- with-config-file-scan-dir =/etc/php. d -- with-mysql -- with-config-file-path =/etc/
./Make
./Make install
Finally, remember to copy the generated libphp5.so to the Directory of the runtime library. I copied it directly to/lib/. Otherwise, an error will be reported when running your own embed program:
./Embed: error while loading shared libraries: libphp5.so: cannot open shared object file: No such file or directory
If you are not familiar with php sapi, I suggest you read my article: Understanding Zend SAPIs (Zend SAPI Internals)
At this time, you can embed the PHP script parser in your C code. my example:
#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;}
Then you need to specify the include path, a simple Makefile.
CC = gccCFLAGS = -I/usr/local/include/php/ \ -I/usr/local/include/php/main \ -I/usr/local/include/php/Zend \ -I/usr/local/include/php/TSRM \ -Wall -gLDFLAGS = -lstdc++ -L/usr/local/lib -lphp5ALL: $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)
After the compilation is successful, run. we can see that stdout outputs Hello World!
Based on this, we can easily implement a Opcodes dumper similar to vld:
First, we define the opcode conversion function (all opcodes can view 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 when: return "then"; 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 ;/*... omitted .... */default: return "UNKNOW"; break;
Then define the zval and znode output functions:
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; }}
Then define the output function of 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); } }}
Finally, it is the main function of the program:
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;}
Compile and run the test script (sample. php ):
The code is as follows:
Sample. php:
Echo "laruence ";
Command:
The code is as follows:
./Opcodes_dumper sample. php
Get the output result (if you are confused about the following results, I suggest you read this article again: an in-depth understanding of the principles of PHP Opcodes ):
Script: sample. php
Opnum line opcode op1 op2 result
0 2 ZEND_ECHO "laruence"
1 4 ZEND_RETURN 1
Haha, how is it fun?
Pluembed SAPI implements the Opcodes viewer. sapiopcodes PHP provides an Embed SAPI. that is to say, PHP allows you to call functions provided by PHP/ZE in C/C ++. This article uses...