PHP Profiler - 使用 C++ 从 PHP 扩展获取客户端 IP 和 URL
PHP Profiler - Getting client IP and URL from PHP extension using C++
我在 c++ 中创建了一个 php 扩展,它现在跟踪每个 request.And 的调用图,我想获取每个请求的远程 IP 地址和 URL 详细信息。
在 CentOS 7.5 和 PHP 5.6.36(禁用线程安全)中尝试
,当用户给每个请求(浏览器)到达时,apache 将控制权交给 PHP 模块,当它被处理到响应阶段时。
PHP_RINIT_FUNCTION() 正在为来自 Zend 引擎的每个事务调用。
我试图在 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 lazy-loads 超全局变量)。
为此,您从 auto_globals
哈希表中查找 zend_auto_global
值并调用自动全局回调。您应该始终检查以确保 $_SERVER
没有事先加载;虽然在你的情况下你是从 RINIT
调用它所以它总是不会被加载。
调用自动全局回调后,您现在可以像访问 symbol_table
哈希表中的任何其他全局变量一样访问 $_SERVER
。
这是我的一个名为 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 headers 中的 the relevant structures。
我在 c++ 中创建了一个 php 扩展,它现在跟踪每个 request.And 的调用图,我想获取每个请求的远程 IP 地址和 URL 详细信息。 在 CentOS 7.5 和 PHP 5.6.36(禁用线程安全)中尝试 ,当用户给每个请求(浏览器)到达时,apache 将控制权交给 PHP 模块,当它被处理到响应阶段时。 PHP_RINIT_FUNCTION() 正在为来自 Zend 引擎的每个事务调用。 我试图在 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 lazy-loads 超全局变量)。
为此,您从 auto_globals
哈希表中查找 zend_auto_global
值并调用自动全局回调。您应该始终检查以确保 $_SERVER
没有事先加载;虽然在你的情况下你是从 RINIT
调用它所以它总是不会被加载。
调用自动全局回调后,您现在可以像访问 symbol_table
哈希表中的任何其他全局变量一样访问 $_SERVER
。
这是我的一个名为 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 headers 中的 the relevant structures。