将HashTable数据从php.ini传递到扩展方法:损坏的值

问题描述

我试图在扩展方法中使用PHP(7.4)扩展,将PHP.ini(如myext.map=key1=val1,key2=val2;)中的设置解析为关联数组。我希望解析在PHP_MINIT_FUNCTION(myext)中进行。

因此,我声明了一个PHP设置,在REGISTER_INI_ENTRIES();中未注释PHP_MINIT_FUNCTION(myext),声明:

ZEND_BEGIN_MODULE_GLOBALS(myext)
    HashTable map;
ZEND_END_MODULE_GLOBALS(myext)

并从MYEXT_G(map)设置JR中填充PHP.ini

PHP_INI_MH(myext_update_map) {
// The part that parses new_value into (key => val) pairs is skipped. It works.
//...
// key = val assignments have been counted.
zend_hash_init(&MYEXT_G(map),count,NULL,1); // 1 for "persistent".
// ...
// Iterating (key => value) pairs.
    // key,key_len,val,val_len have been successfully extracted from PHP.ini.
    zend_string * key_z = zend_string_init( key,1 );
    zval val_z;
    ZVAL_STRINGL( &val_z,val_len );
    zend_hash_add_new( &MYEXT_G(map),key_z,&val_z );

然后,在PHP方法中,我尝试从&MYEXT_G(map)读取数据:

PHP_METHOD(MyExt,getMap) {
// ...
zend_string * key_z;
zval * val_z;
ZEND_HASH_FOREACH_STR_KEY_VAL(&MYEXT_G(map),val_z)
    PHP_error_docref( NULL TSrmlS_CC,E_WARNING,"ZSTR_VAL(key_z) = %s\n",ZSTR_VAL(key_z) );
    PHP_error_docref( NULL TSrmlS_CC,"Z_STRVAL_P(val_z) = %s\n",Z_STRVAL_P(val_z) );
    PHP_error_docref( NULL TSrmlS_CC,"Z_STRLEN_P(val_z) = %lu\n",Z_STRLEN_P(val_z) );
ZEND_HASH_FOREACH_END();

如果从命令行调用了包含MyExt::getLibraries()PHP脚本,则PHP警告将打印在PHP.ini中设置的键和值。

但是,如果脚本是通过HTTP请求调用的,则警告消息中的ZSTR_VAL(key_z)是正确的,但是Z_STRVAL_P(val_z)Z_STRLEN_P(val_z)都包含垃圾

所有涉及的函数要么定义为PHP宏,要么接收TSrmlS_DC

似乎全局哈希表中的值(但不是键)在模块初始化和服务HTTP请求之间重新分配。

我确保MYEXT_G中的标量值可以从PHP_MINIT_FUNCTION(myExt)保留到HTTP请求调用PHP方法中。

那么,如何确定HashTable值是真正持久的?

解决方法

正如我在 PHP内部(internals@lists.php.net)所建议的那样,ZVAL_STRINGL分配每个请求字符串;我需要ZVAL_STRZVAL_STR(&val_z,zend_string_init(val,val_len,1));

然后我将val_z添加到了全局哈希表:zend_hash_str_add_new( &MYEXT_G(map),key_z,key_len,&val_z );。在处理HTTP请求时,哈希表&MYEXT_G(map)是可读的(键和值)。