如何使用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 <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;
}

编译,运行测试脚本(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)

相关推荐

  • 利用PHP扩展vld查看PHP opcode操作步骤

    首先下载最新版vld扩展: 复制代码 代码如下: ~/public_html/php-5.3.13/ext> wget http://pecl.php.net/get/vld-0.11.2.tgz ~/public_html/php-5.3.13/ext> tar zxvf vld-0.11.2.tgz ~/public_html/php-5.3.13/ext> cd vld-0.11.2/ 接下来编译安装vld扩展: 复制代码 代码如下: ~/public_html/php-5.3.1

  • 理解php原理的opcodes(操作码)

    Opcondes是一种php脚本编译后的中间语言,就像Java的Byte Code,或者.NET 的MSL .(都没了解过~) 举个文中的例子 复制代码 代码如下: <?php echo "Hello World"; $a = 1 + 1; echo $a; ?> PHP执行这段代码会经过如下4个步骤(确切的来说,应该是PHP的语言引擎Zend) 复制代码 代码如下: 1.Scanning(Lexing) (扫描),将PHP代码转换为语言片段(Tokens) 2.Parsi

  • PHP OPCode缓存 APC详细介绍

    APC的介绍 The Alternative PHP Cache (APC) is a free and open opcode cache for PHP. Its goal is to provide a free, open, and robust framework for caching and optimizing PHP intermediate code. APC官方网站:http://www.php.net/manual/en/book.apc.php WIN下最新版本的下载地

  • 深入理解PHP之OpCode原理详解

    本文实例讲述了PHP中OpCode的原理.分享给大家供大家参考,具体如下: OpCode是一种PHP脚本编译后的中间语言,就像Java的ByteCode,或者.NET的MSL. 此文主要基于< Understanding OPcode>和 网络,根据个人的理解和修改,特记录下来 : PHP代码: <?php echo "Hello World"; $a = 1 + 1; echo $a; ?> PHP执行这段代码会经过如下4个步骤: 1. Scanning (L

  • PHP内核学习教程之php opcode内核实现

    opcode是计算机指令中的一部分,用于指定要执行的操作, 指令的格式和规范由处理器的指令规范指定. 除了指令本身以外通常还有指令所需要的操作数,可能有的指令不需要显式的操作数. 这些操作数可能是寄存器中的值,堆栈中的值,某块内存的值或者IO端口中的值等等. 通常opcode还有另一种称谓:字节码(byte codes). 例如Java虚拟机(JVM),.NET的通用中间语言(CIL: Common Intermeditate Language)等等. 1. Opcode简介 opcode是计算

  • 为PHP5.4开启Zend OPCode缓存

    编译步骤: 复制代码 代码如下: git clone git://github.com/zend-dev/ZendOptimizerPlus.git cd ZendOptimizerPlus $PHP_DIR/bin/phpize ./configure \ --with-php-config=$PHP_DIR/bin/php-config make && make install 配置步骤:在 php.ini 内增加zend_extension=/...full path.../opca

  • 如何使用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/  ./ma

  • require、backbone等重构手机图片查看器

    本文是对之前的部分补充,也是对最近学习require.backbone的一次实例化的实践,希望对正在学习理解中的同学们有帮助 前文请前往:制作手机使用的网页图片查看器 新手机图片查看器 网页部分 require引入是重点,指明了主函数所在文件路径 <!doctype html> <html lang="zh-cn"> <head> <title>webapp图片查看器</title> <meta charset=&quo

  • hta实现的笨狼树状节点查看器

    <html> <head> <style> table {     border-collapse: collapse;     border-width: 4;      border-style: double;      border-color:#15336F;     font-size:12px; } body {     font-size:12px; } div {     width:100%;     height:9;      border-st

  • jQuery实现简单的图片查看器

    项目中自己diy了一个图片查看器.因为初始代码不是自己的,只是在上面改了一下也没有弄的很漂亮.等以后有时间了在重写一下样式和封装,作为备用的只是积累吧.如果有童鞋有用到,完全可以在此基础上改,比较容易,代码也比较简单 图片查看器主要有几个功能: 1.显示图片和图片信息(图片名称.发布者等等) 2.切换图片 3.关闭图片查看器 初始化接口函数pictureViewer.init: function(picInfos,tapNumber,isBig) picInfos: 传入图片组信息,必须,格式如

  • 移动端js图片查看器

    本文实例为大家分享了js图片查看器插件的使用方法,制作手机使用的网页图片查看器,供大家参考,具体内容如下 这几天抽空在为项目开发一个量身的图片查看器,目前已初步完成需求. 开发场景是:在一个多文件下载展示列表中,如检测某些文件为图片时,则点击该文件时打开图片查看器展示该图片,并将列表内其它图片同时展示查看器队列内,可供前后滑动查看及其它附带功能. 乍一听功能点似乎有点多而且有些复杂,需要梳理一下 功能点整理 首先,我们要获得点击的图片文件对象及符合条件的图片文件对象集 其次,图片查看器的制作及图

  • 基于touch.js手势库+zepto.js插件开发图片查看器(滑动、缩放、双击缩放)

    最近由于公司项目需要图片查看器,网上搜了一圈,感觉资料很少,所以决定基于百度的touch.js手势库+zepto.js自己写了一个小插件,实现了左右滑动,双指缩放,双击缩放功能,基本使用还行,但是有时候还是不太顺畅,后续会慢慢完善:写的不好的地方望各位能够给出好的建议,谢谢! 源码地址:https://github.com/GLwen/molong_photoSwipe.git 演示:http://runjs.cn/detail/iceaaogh molong.css *{padding:0;m

  • Android仿微信朋友圈图片查看器

    再看文章之前,希望大家先打开自己的微信点到朋友圈中去,仔细观察是不是发现朋友圈里的有个"九宫格"的图片区域,点击图片又会跳到图片的详细查看页面,并且支持图片的滑动和缩放?这个功能是不是很常用呢?!那么我今天正好做了这个Demo,下面为大家讲解一下.首先按照惯例先看一下效果图吧,尤其不会录制gif动画(哎~没办法,模拟器不支持多点触控,刚好我的手机又没有Root,不能录屏,悲催啊,大家见谅,想要看真实效果的话,烦请移到文章最下方转载文章中进行源码下载,点击下载源码,运行后再看效果哈~~)

  • C#如何实现图片查看器

    这篇文章将简单介绍下如何使用C#来实现一个图片查看器的功能的,该工具保存的功能有: 1. 可以通过"上一张" "下一张"这样的按钮来轮换浏览图片  2.实现对图片的旋转  3.实现对旋转后图片的保存功能.本程序不仅提供旋转90/180/270这样的实现,同时提供一个方法来完成旋转任意角度的实现 4.该程序未实现Windows图片查看图片缩放的功能,这部分的功能主要要点是改变图片在PictureBox控件中的高度和宽度就可以的 二.实现思路 2.1 图片轮换浏览功能的

  • Android编程实现网络图片查看器和网页源码查看器实例

    本文实例讲述了Android编程实现网络图片查看器和网页源码查看器.分享给大家供大家参考,具体如下: 网络图片查看器 清单文加入网络访问权限: <!-- 访问internet权限 --> <uses-permission android:name="android.permission.INTERNET"/> 界面如下: 示例: public class MainActivity extends Activity { private EditText image

  • Android实现的可以调整透明度的图片查看器实例

    本文以实例讲解了基于Android的可以调整透明度的图片查看器实现方法,具体如下:  main.xml部分代码如下: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"

随机推荐