是什么

在开始之前, 必须要先介绍一下Opcode是什么.

众所周知, Java在执行的时候, 会将.java后缀的文件预先编译为.class字节码文件, JVM加载字节码文件进行解释执行. 而字节码文件存在的意义, 就是为了加速执行.

那么PHPOpcode与之类似, 也是从.php文件到执行的过程中, 所生成的预编译中间文件.

或者也可以这样粗鲁的理解, PHP程序是由C写的二进制程序, Opcode就是将.php文件翻译为c代码的结果.

Opcode有什么用我们最后再说, 先让我们看一下它长什么样子

获得

如何获得php文件的opcode呢? 在PHP的源码中, 可以通过c函数zend_compile_string获取PHP代码解析后的Opcode. 但是我们要是为了获取Opcode得深入到c, 是在有些得不偿失. 好在, 已经有前辈做好的扩展可直接获取. 既: vld.

vld 扩展

安装扩展:

# 安装扩展
pecl install https://pecl.php.net/get/vld
# 启用扩展. 若不是 docker, 将"extension=vld.so" 写入 php.ini 即可
docker-php-ext-enable vld
# 命令行查看, 确保扩展安装成功
php -m | grep vld

我们查看这段小小代码的opcode:

<?php
require 't.php';
$a = 1;
$b = $a;
echo $a;
var_dump($b);
exit(0);

执行如下命令可查看:

php -d vld.active=1 -d vld.execute=0 test.php

对于vld的输出结果, 这里有作者的一篇说明文章: https://derickrethans.nl/more-source-analysis-with-vld.html

vld扩展支持的配置. php的扩展配置可以在跑脚本的时候, 通过-d参数临时修改, 也可以直接修改php.ini文件. 这里建议临时修改, 毕竟并不是所有脚本都要输出opcode.

  • vld.active: 是否输出opcode. 默认为0
  • vld.execute: 是否要运行代码. 默认为1
    • 当为0时, 不会输出require的其他文件内容.
  • vld.verbosity: 显示更详细的信息. 默认为0, 可能值为0123
  • 等等吧, 还有一些其他的配置项, 不过感觉没什么用就不列举了. 可通过命令php -r 'phpinfo();' | grep vld 查看支持的所有配置.

phpdbg

按理说, 这么常用的操作, 应该是带有官方工具才对的吧. 哎, 这不就来了么. phpdbgphp程序的调试器(迄今为止, 我从来没有用过. 甚至没有用过断掉调试). 但同时它也可以用来生成opcode.

命令: phpdbg -p test.php

生成结果与vld扩展基本一致.

还可以通过opcache来生成, 不过就有些绕了, 在这里就不介绍了. 简单介绍一下这两种方式就好.

phpdbg生成的话, 貌似只支持单文件生成(也可能是我没找到使用方法), vld则可以带着引入的文件一起打印出来.

不过对于我们分析程序来说, phpdbg一般是够用的了.

使用

那么上述生成的opcode是什么意思呢? 很遗憾, 官网对opcode的解释已经找不到了, 不过zend opcode document为关键词搜索的话, 还是能搜到一大堆的. 这里就不再重复罗列其含义了了.

我就简单说一下它有什么用吧. 总不能咱这折腾了半天, 拿到了opcode然后就没有然后了.

opcodephp文件翻译后的中间码, 通过它, 我们大致可以知道php文件的执行过程.

又因为php是通过c层面进行解析的, 每一条opcode都会解析为一个c函数进行执行. 对于分析源码、查找问题等等, 可直接定位到php代码在c源码级别的执行, 方便得很嘛. (类似需求我之前碰到过很多次, 比如查找sort的实现原理等等)

所有操作码都定义在源码文件zend_vm_opcodes.h中. 既然php会根据不同的操作码, 执行不同的操作. 那么, 我们是不是就可以根据操作码, 来还原php底层执行的操作了呢? 不好意思, 可以但是很难. php通过函数zend_vm_get_opcode_handler来获取操作码对应的handle函数. 但是, 当看过源码后, 我失望了, 函数zend_vm_get_opcode_handler获取的过程是一个动态解析的过程. 也就是说, 同一个操作码, 解析后可能会是不同的函数. 啊这不就尴尬了么.

于是, 不信邪的我, 决定通过修改PHP源码来实现. 为了方便使用, 我将其封装为了一个docker镜像, 对实现方式感兴趣的, 请移至Dockerfile. 使用方式如下(镜像的详情见: 调试镜像):

docker run --rm -it -v `pwd`:`pwd` -w `pwd` hujingnb/php_opcode:8.1.7 php test.php

如下所示输出结果:

同时会在当前目录生成opcode.log文件, 内容如下:

可查看到opcode及每一个操作码具体执行的c函数是哪个.

其中require所对应的opcodeINCLUDE_OR_EVAL, 所执行的c函数为ZEND_INCLUDE_OR_EVAL_SPEC_CONST_HANDLER.

总结

至此, opcode我们也见过了, 也能将php文件转换为opcode了. 不过说实话, 这玩意在平常的开发中不能说是用不到, 可以说是根本用不到.

它的作用我觉得还是在分析源码的时候. 可以方便的看到php代码的每一步操作, 其对应的源码执行.

以后研究源码, 或者是对php行为感到疑惑的时候, 有这个工具就可以加速解惑的过程啦.

调试镜像

介绍

此镜像是为了方便查看phpopcode及操作码对应执行的c函数. 为了方便对php源码进行分析. 通过结果, 可通过php文件直接定位到php源码的c函数.

此镜像在vld扩展的基础上, 额外输出了:

  • 操作码对应的c执行handle函数

此镜像基于php分支php-8.1.7, commitId 为d35e577a1bd0b35b9386cea97cddc73fd98eed6d.

镜像地址. 这里就不说明我是怎么做的了, 感兴趣的可查看Dockerfile

使用

通过此镜像获得操作码简单方式:

docker run --rm -it -v `pwd`:`pwd` -w `pwd` hujingnb/php_opcode:8.1.7 php test.php

此命令产生如下结果:

  1. 获取php文件的opcode
  2. 获取opcode操作码对应的执行c函数. 将结果输出到当前目录的opcode.log文件中

高级

若需要安装扩展, 可进入镜像后执行如下操作:

  • php源码编译安装gd扩展: docker-php-ext-configure gd
  • php源码安装gd扩展: docker-php-ext-install gd
  • 启用gd扩展: docker-php-ext-enable gd
  • 通过官方库安装扩展: pecl install redis && docker-php-ext-enable redis

环境变量:

  • PHP_SRC_DIR: 源码位置
  • PHP_INI_DIR: 配置文件位置
  • PHP_INSTALL_DIR: 安装路径

若需要添加额外操作, 可基于此镜像进行操作, 请根据Dockerfile自行修改.

若想要修改php源码, 可在修改后执行命令重新安装: docker-php-install

原文地址: https://hujingnb.com/archives/836

PHP获取Opcode及C源码相关推荐

  1. 只需两步快速获取微信小程序源码

    第一次在掘金这样高大上的社区写文章,忐忑地敲下我获取小程序源码过程中的经验分享. 最近在学习微信小程序开发,半个月学习下来,很想实战一下踩踩坑,于是就仿写了某个小程序的前端实现,过程一言难尽,差不多两 ...

  2. 获取微信小程序源码并进行反编译

    获取微信小程序源码并进行反编译 只需如下几部就可以爬取到你所想要的微信小程序源码: 第一: node.js运行环境 如果没有安装nodejs,请先安装一下 下载地址:https://nodejs.or ...

  3. 如何获取PHP短视频源码中的SMSC

    想要通过简单方式获取PHP短视频源码中的SMSC,可以使用一下方法 public static String getSmsCenterNumber(Context context,int slotIn ...

  4. php编译称opcode文件,PHP源码保护和性能加速

    什么是Opcache? 每一次执行 PHP 脚本的时候,该脚本都需要被编译成字节码,而 Opcache 可以对该字节码进行缓存,这样,下次请求同一个脚本的时候,该脚本就不需要重新编译,这极大节省了脚本 ...

  5. 用c#开发微信(2)扫描二维码,用户授权后获取用户基本信息 (源码下载)

    本文将介绍基于Senparc.Weixin微信开发框架来实现网页授权来获取用户基本信息.先生成包含授权及回调url信息的二维码:用户用微信扫描之后,被要求授权以获取Ta的用户基本信息:用户授权后,通过 ...

  6. js文件里获取路由 vue_【源码拾遗】从vue-router看前端路由的两种实现

    本文由浅入深观摩vue-router源码是如何通过hash与History interface两种方式实现前端路由,介绍了相关原理,并对比了两种方式的优缺点与注意事项.最后分析了如何实现可以直接从文件 ...

  7. 只需两步获取任何小程序源码

    这种方法,并不能反编译出所有的小程序源码,请自知! 具体的局限请看:qwerty472123大神的md文件 https://github.com/qwerty472123/wxappUnpacker ...

  8. 获取微信小程序源码教程

    最近在研究微信小程序,网上很多的小程序都是可以借鉴的,那么如何获取源码就很重要了 目录 1.安装对应环境 (Node,js) 2.下载反编译脚本 3.下载安卓模拟器获取微信小程序反编译文件 4.反编译 ...

  9. MFC WebBrowser获取网面完整源码 WebBrowser获取网面完整HTML

    反爬比较厉害的网站,用WebBrowser来获取网页源码,也可使用开源的浏览器来实现. #include <MsHTML.h> #include <atlconv.h> voi ...

最新文章

  1. linux 支持7代cpu型号,win7最高支持几代cpu
  2. c语言常用指令翻译,c语言常见专业词汇带翻译
  3. 阿里云-设备影子概览
  4. java socket5源码_Java利用TCP协议实现客户端与服务器通信【附通信源码】
  5. 计算机vf知识点总结,计算机等级考试二级VF常用函数总结
  6. iOS App图标和启动画面尺寸http://www.jianshu.com/p/adpKye
  7. python 按日期筛选数据并计算均值
  8. 包无法安装_BiocManager无法安装R包
  9. 阿铭Linux_传统IDC 部署网站学习笔记20190121
  10. SpringBoot 动态设置响应头的content-type
  11. java GIF拆分和压缩处理
  12. 近两日学的Linux系统基础命令总结
  13. Unity UI框架的搭建
  14. python程序设计心得体会感想-从Python学习中得到的一点感悟
  15. Python爬虫实战(爬取豆瓣电影)
  16. Soot -- 中间代码Jimple介绍
  17. 职场:结果导向的前提是过程控制
  18. 几句话说清楚AMD® Ryzen CPU里的PBO
  19. Comprehensive Analysis of Time Series Forecasting Using Neural Networks
  20. 怎么将英文网页整篇翻译成中文

热门文章

  1. 无广告的免费视频存储空间并提供视频上传转码的功能,很不错的哦
  2. yolo数据集剪裁:切割目标框并将该框内的其他目标一并提取并转为可用数据集
  3. lzma算法_十款性能最佳的压缩算法
  4. 文本相似度计算——Simhash算法(python实现)
  5. 数据结构 | 合并两个长度分别为m和n的有序表,最坏情况下需要比较m+n-1次
  6. HTML5APP商业开发实战教程——基于WeX5可视化开发平台
  7. html图片自适应裁剪,html 图片裁剪 图片固定高度 图片自适应。图片完美适配
  8. 遮罩层内容半透明解决
  9. 中职计算机c语言课程,中职计算机C语言教学探讨
  10. c语言实现计算函数在某点的导数近似值