国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 網站 > 建站經驗 > 正文

如何使用PHP Embed SAPI實現Opcodes查看器

2024-04-25 20:16:37
字體:
來源:轉載
供稿:網友

這篇文章主要介紹了如何使用PHP Embed SAPI實現Opcodes查看器的相關資料,需要的朋友可以參考下。

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 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腳本解析器了, 我的例子:

  1. #include "sapi/embed/php_embed.h" 
  2. int main(int argc, char * argv[]){ 
  3.  PHP_EMBED_START_BLOCK(argc,argv); 
  4.  char * script = " print 'Hello World!';"
  5.  zend_eval_string(script, NULL, 
  6.           "Simple Hello World App" TSRMLS_CC); 
  7.  PHP_EMBED_END_BLOCK(); 
  8.  return 0; 

然后就是要指明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.  static char buffer[BUFFER_LEN]; 
  3.  int len; 
  4.  switch(z->type) { 
  5.   case IS_NULL
  6.    return "NULL"
  7.   case IS_LONG
  8.   case IS_BOOL
  9.    snprintf(buffer, BUFFER_LEN, "%d", z->value.lval); 
  10.    return buffer; 
  11.   case IS_DOUBLE
  12.    snprintf(buffer, BUFFER_LEN, "%f", z->value.dval); 
  13.    return buffer; 
  14.   case IS_STRING
  15.    snprintf(buffer, BUFFER_LEN, "/"%s/"", z->value.str.val); 
  16.    return buffer; 
  17.   case IS_ARRAY
  18.   case IS_OBJECT
  19.   case IS_RESOURCE
  20.   case IS_CONSTANT: 
  21.   case IS_CONSTANT_ARRAY: 
  22.    return ""
  23.   default
  24.    return "unknown"
  25.  } 
  26. char * format_znode(znode *n){ 
  27.  static char buffer[BUFFER_LEN]; 
  28.  switch (n->op_type) { 
  29.   case IS_CONST: 
  30.    return format_zval(&n->u.constant); 
  31.    break
  32.   case IS_VAR: 
  33.    snprintf(buffer, BUFFER_LEN, "$%d", n->u.var/sizeof(temp_variable)); 
  34.    return buffer; 
  35.    break
  36.   case IS_TMP_VAR: 
  37.    snprintf(buffer, BUFFER_LEN, "~%d", n->u.var/sizeof(temp_variable)); 
  38.    return buffer; 
  39.    break
  40.   default
  41.    return ""
  42.    break
  43.  } 

然后定義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. void dump_op_array(zend_op_array *op_array){ 
  8.  if(op_array) { 
  9.   int i; 
  10.   printf("%5s %5s %30s %040s %040s %040s/n""opnum""line""opcode""op1""op2""result"); 
  11.   for(i = 0; i < op_array->last; i++) { 
  12.    dump_op(&op_array->opcodes[i], i); 
  13.   } 
  14.  } 

最后,就是程序的主函數了:

  1. int main(int argc, char **argv){ 
  2.  zend_op_array *op_array; 
  3.  zend_file_handle file_handle; 
  4.  if(argc != 2) { 
  5.   printf("usage: op_dumper <script>/n"); 
  6.   return 1; 
  7.  } 
  8.  PHP_EMBED_START_BLOCK(argc,argv); 
  9.  printf("Script: %s/n", argv[1]); 
  10.  file_handle.filename = argv[1]; 
  11.  file_handle.free_filename = 0; 
  12.  file_handle.type = ZEND_HANDLE_FILENAME; 
  13.  file_handle.opened_path = NULL; 
  14.  op_array = zend_compile_file(&file_handle, ZEND_INCLUDE TSRMLS_CC); 
  15.  if(!op_array) { 
  16.   printf("Error parsing script: %s/n", file_handle.filename); 
  17.   return 1; 
  18.  } 
  19.  dump_op_array(op_array); 
  20.  PHP_EMBED_END_BLOCK(); 
  21.  return 0; 

編譯,運行測試腳本(sample.php):

sample.php:

echo "laruence";

命令:./opcodes_dumper  sample.php

得到輸出結果(如果你對下面的結果很迷惑,那么建議你再看看我的這篇文章:深入理解PHP原理之Opcodes):

  1. Script: sample.php 
  2. opnum   line                         opcode                                      op1                                      op2                                   result 
  3.     0      2                      ZEND_ECHO                               "laruence" 
  4.     1      4                    ZEND_RETURN                                        1 

呵呵,怎么樣,是不是很好玩呢?

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 德令哈市| 嘉祥县| 崇阳县| 海宁市| 贵阳市| 屏南县| 兰坪| 普洱| 贡嘎县| 公主岭市| 东兰县| 海晏县| 瑞安市| 龙江县| 明水县| 兴城市| 西昌市| 大埔区| 集贤县| 平南县| 铁力市| 札达县| 泰州市| 兴宁市| 昌黎县| 商丘市| 宣威市| 高清| 章丘市| 防城港市| 连州市| 获嘉县| 海阳市| 宕昌县| 中江县| 长治市| 临沂市| 谷城县| 栾川县| 栾川县| 张家港市|