将哈希表数据从 php.ini 传递到扩展方法:损坏的值
Passing HashTable data from php.ini to an extension method: corrupted values
我正在尝试在扩展方法中使用 PHP (7.4) 扩展将 php.ini
(如 myext.map=key1=val1,key2=val2;
)中的设置解析为关联数组。我希望解析发生在 PHP_MINIT_FUNCTION(myext)
.
所以,我声明了一个 php 设置,在 PHP_MINIT_FUNCTION(myext)
中取消注释 REGISTER_INI_ENTRIES();
,声明:
ZEND_BEGIN_MODULE_GLOBALS(myext)
HashTable map;
ZEND_END_MODULE_GLOBALS(myext)
并从 php.ini
设置中填充 MYEXT_G(map)
JR:
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, 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, key_len, 1 );
zval val_z;
ZVAL_STRINGL( &val_z, val, 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), key_z, 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, E_WARNING, "Z_STRVAL_P(val_z) = %s\n", Z_STRVAL_P(val_z) );
php_error_docref( NULL TSRMLS_CC, E_WARNING, "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 (internals@lists.php.net) 中被告知的那样,ZVAL_STRINGL
分配了一个 per-request 字符串;我需要 ZVAL_STR
: ZVAL_STR(&val_z, zend_string_init(val, val_len, 1));
.
然后我将 val_z
添加到全局哈希 table: zend_hash_str_add_new( &MYEXT_G(map), key_z, key_len, &val_z );
。散列table &MYEXT_G(map)
在处理 HTTP 请求时是可读的(包括键和值)。
我正在尝试在扩展方法中使用 PHP (7.4) 扩展将 php.ini
(如 myext.map=key1=val1,key2=val2;
)中的设置解析为关联数组。我希望解析发生在 PHP_MINIT_FUNCTION(myext)
.
所以,我声明了一个 php 设置,在 PHP_MINIT_FUNCTION(myext)
中取消注释 REGISTER_INI_ENTRIES();
,声明:
ZEND_BEGIN_MODULE_GLOBALS(myext)
HashTable map;
ZEND_END_MODULE_GLOBALS(myext)
并从 php.ini
设置中填充 MYEXT_G(map)
JR:
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, 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, key_len, 1 );
zval val_z;
ZVAL_STRINGL( &val_z, val, 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), key_z, 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, E_WARNING, "Z_STRVAL_P(val_z) = %s\n", Z_STRVAL_P(val_z) );
php_error_docref( NULL TSRMLS_CC, E_WARNING, "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 (internals@lists.php.net) 中被告知的那样,ZVAL_STRINGL
分配了一个 per-request 字符串;我需要 ZVAL_STR
: ZVAL_STR(&val_z, zend_string_init(val, val_len, 1));
.
然后我将 val_z
添加到全局哈希 table: zend_hash_str_add_new( &MYEXT_G(map), key_z, key_len, &val_z );
。散列table &MYEXT_G(map)
在处理 HTTP 请求时是可读的(包括键和值)。