You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何用PHP扩展覆盖Zend内部函数?实现遇阻求助

修复PHP7.3下var_dump钩子不生效的问题

我刚帮你排查了代码里的问题,主要有两个核心原因导致你的hook逻辑没生效,咱们一步步来修复:

1. 模块入口未注册MINIT初始化函数

你的zend_module_entry结构体里,把模块初始化(MINIT)的回调参数设成了NULL,PHP根本不会执行你写的PHP_MINIT_FUNCTION(hook_php)函数,自然也就没完成var_dump的替换逻辑。

修改后的模块入口结构体:

zend_module_entry hook_php_module_entry = {
    STANDARD_MODULE_HEADER,
    PHP_HOOK_EXTNAME,
    hook_php_functions,
    PHP_MINIT(hook_php), // 替换原来的NULL,指定MINIT回调
    NULL,
    NULL,
    NULL,
    NULL,
    PHP_HOOK_VERSION,
    STANDARD_MODULE_PROPERTIES
};

2. MINIT阶段误用请求级函数表查找全局内置函数

EG(function_table)请求级别的执行环境函数表,在模块初始化(MINIT)阶段,请求还未启动,这个表是未初始化的状态。你需要使用全局的内置函数表zend_global_function_table来查找var_dump

同时别忘了在MINIT函数末尾返回SUCCESS,符合PHP扩展的规范:

PHP_MINIT_FUNCTION(hook_php) {
    zend_function *original;
    // 替换EG(function_table)为全局函数表指针
    original = zend_hash_str_find_ptr(&zend_global_function_table, "var_dump", sizeof("var_dump")-1);
    if (original != NULL) {
        original_handler_var_dump = original->internal_function.handler;
        original->internal_function.handler = my_overwrite_var_dump;
    }
    return SUCCESS;
}

3. 优化函数指针类型定义(可选但推荐)

你代码里针对PHP版本的zif_handlertypedef可以替换成官方定义的ZEND_FUNCTION_HANDLER类型,不用自己维护版本判断:

// 替换原来的#if PHP_VERSION_ID <70200那段代码
ZEND_FUNCTION_HANDLER original_handler_var_dump;

完整修复后的php_hook.c代码

// include the PHP API itself
#include <php.h>
// then include the header of your extension
#include "php_hook.h"
// register our function to the PHP API
// so that PHP knows, which functions are in this module
zend_function_entry hook_php_functions[] = {
    ZEND_NAMED_FE(my_overwrite_var_dump, my_overwrite_var_dump, NULL)
    {NULL, NULL, NULL}
};
// some pieces of information about our module
zend_module_entry hook_php_module_entry = {
    STANDARD_MODULE_HEADER,
    PHP_HOOK_EXTNAME,
    hook_php_functions,
    PHP_MINIT(hook_php),
    NULL,
    NULL,
    NULL,
    NULL,
    PHP_HOOK_VERSION,
    STANDARD_MODULE_PROPERTIES
};
// use a macro to output additional C code, to make ext dynamically loadable
ZEND_GET_MODULE(hook_php)

// 使用官方定义的函数句柄类型
ZEND_FUNCTION_HANDLER original_handler_var_dump;

ZEND_NAMED_FUNCTION(my_overwrite_var_dump) {
    php_printf("hooked (var_dump))\n");
    // if we want to call the original function
    original_handler_var_dump(INTERNAL_FUNCTION_PARAM_PASSTHRU);
}

PHP_MINIT_FUNCTION(hook_php) {
    zend_function *original;
    original = zend_hash_str_find_ptr(&zend_global_function_table, "var_dump", sizeof("var_dump")-1);
    if (original != NULL) {
        original_handler_var_dump = original->internal_function.handler;
        original->internal_function.handler = my_overwrite_var_dump;
    }
    return SUCCESS;
}

测试验证

重新编译安装你的扩展后,调用var_dump(1),应该会先输出hooked (var_dump)),然后再输出int(1),说明钩子已经生效了。

内容的提问来源于stack exchange,提问作者fufyayokku

火山引擎 最新活动