我在c ++中创建了一个php扩展,它跟踪每个请求的调用图。现在,我想获取每个请求的远程ipaddress和URL详细信息。尝试使用CentOS 7.5和PHP 5.6.36(线程安全禁用),当用户给出每个请求(浏览器)时,apache会在处理到响应阶段时将控制传递给PHP模块。正在为Zend引擎的每个事务调用PHP_RINIT_FUNCTION()。我试图在PHP_RINIT_FUNCTION(apm)函数中获取服务器名称和远程地址及其详细信息,如下所示,
zval *args;
char * name = "REMOTE_ADDR";
int len = sizeof("REMOTE_ADDR");
if ( (zend_hash_find(&EG(symbol_table), name,len, (void **) &args) != FAILURE) || PG(http_globals)[TRACK_VARS_SERVER] || zend_hash_find(PG(http_globals)[TRACK_VARS_SERVER]->value.ht, name,len, (void **) &args) != FAILURE)
{
// success
//converts args(zval*) to string
}
else
{
//failed
//can't get REMOTE address
}
以上方法是否正确?如果是这样,每个请求都会失败。我哪里错了?如果有的话,有什么选择?
我过去成功完成的是从$_SERVER
超全局数组变量中读取这些值。为了使用$_SERVER
(尤其是来自RINIT
上下文),您必须确保已调用其自动全局回调。 PHP通常在第一个用户空间访问时调用它(换句话说,PHP延迟加载超级全局)。
为此,您从zend_auto_global
哈希表中查找auto_globals
值并调用auto全局回调。你应该经常检查以确保$_SERVER
尚未预先加载;虽然在你的情况下你是从RINIT
调用它所以它总是不会被加载。
在调用auto全局回调之后,您现在可以像访问$_SERVER
哈希表中的任何其他全局变量一样访问symbol_table
。
这是一个来自我的扩展名为uniauth
的示例(有关Github的完整上下文,请参阅this link):
/* Make sure $_SERVER is auto loaded already. */
if (!zend_hash_exists(&EG(symbol_table),"_SERVER",8)) {
if (zend_hash_find(CG(auto_globals),"_SERVER",8,(void**)&auto_global) != FAILURE) {
auto_global->armed = auto_global->auto_global_callback(auto_global->name,
auto_global->name_len TSRMLS_CC);
}
else {
zend_throw_exception(NULL,"could not activate _SERVER",0 TSRMLS_CC);
return 0;
}
}
在代码库的这个特定部分中,扩展使用$_SERVER
中的信息生成重定向URI。以下是显示服务器变量用于生成URI的代码(有关Github上的完整上下文,请参阅this link):
/* Get information about the protocol, host and port number from the _SERVER
* superglobal. We use HTTPS, HTTP_HOST and SERVER_PORT keys to resolve the
* scheme, host and port. I know of no better way to do this unfortunately
* with the PHP/ZEND API. The sapi globals just don't have what I need.
*/
if (zend_hash_find(&EG(symbol_table),"_SERVER",8,(void**)&arr) == FAILURE) {
zend_throw_exception(NULL,"no _SERVER superglobal",0 TSRMLS_CC);
return 0;
}
server = Z_ARRVAL_PP(arr);
if (zend_hash_find(server,"HTTPS",6,(void**)&val) != FAILURE) {
if (Z_TYPE_PP(val) != IS_STRING || strcmp(Z_STRVAL_PP(val),"off") != 0) {
https = 1;
}
}
if (zend_hash_find(server,"HTTP_HOST",10,(void**)&val) != FAILURE
&& Z_TYPE_PP(val) == IS_STRING)
{
host = Z_STRVAL_PP(val);
}
else {
zend_throw_exception(NULL,"no HTTP_HOST within _SERVER found",0 TSRMLS_CC);
}
在评论中,我哀叹这样一个事实,即如果不模仿你在用户空间代码中所做的事情就没有办法做到这一点。您可以在扩展中访问SAPI全局结构,但它没有我的项目(和您的)所需的所有信息。有关详细信息,请参阅PHP标头中的the relevant structures。