PHP内核中读取$_GET\$_POST等全局变量

一、内核中获取$_GET$_POST$_SERVER$_FILES$_COOKIE等全局变量
HashTable是PHP很多实现的基础,例如$_GET$_POST等全局变量实现。
那么,在扩展中读取这些全局变量,当然还是操作HashTable。
内核中初始化环境变量的通过main/php_variables.c中php_hash_environment(TSRMLS_D)

PHP在初始化环境变量的同时,考虑到对大变量的读性能,会通过main/php_variables.c的php_startup_auto_globals来注册一份只读的环境变量。

void php_startup_auto_globals(TSRMLS_D)
{
 zend_register_auto_global("_GET", sizeof("_GET")-1, NULL TSRMLS_CC);
 zend_register_auto_global("_POST", sizeof("_POST")-1, NULL TSRMLS_CC);
 zend_register_auto_global("_COOKIE", sizeof("_COOKIE")-1, NULL TSRMLS_CC);
 zend_register_auto_global("_SERVER", sizeof("_SERVER")-1, php_auto_globals_create_server TSRMLS_CC);
 zend_register_auto_global("_ENV", sizeof("_ENV")-1, php_auto_globals_create_env TSRMLS_CC);
 zend_register_auto_global("_REQUEST", sizeof("_REQUEST")-1, php_auto_globals_create_request TSRMLS_CC);
 zend_register_auto_global("_FILES", sizeof("_FILES")-1, NULL TSRMLS_CC);
}

只读环境变量的读取方式:

&PG(http_globals)[TRACK_VARS_GET];
&PG(http_globals)[TRACK_VARS_POST];
&PG(http_globals)[TRACK_VARS_REQUEST];
&PG(http_globals)[TRACK_VARS_COOKIE];
&PG(http_globals)[TRACK_VARS_ENV];
&PG(http_globals)[TRACK_VARS_FILES];

其中用到的宏为内核提供

/*main/php_globals.h*/
#define TRACK_VARS_POST 0
#define TRACK_VARS_GET 1
#define TRACK_VARS_COOKIE 2
#define TRACK_VARS_SERVER 3
#define TRACK_VARS_ENV 4
#define TRACK_VARS_FILES 5
#define TRACK_VARS_REQUEST 6

如果需要对环境变量进行修改,可以在全局作用域中搜索:

(void)zend_hash_find(&EG(symbol_table), ZEND_STRS("_GET"), (void **)&carrier);
(void)zend_hash_find(&EG(symbol_table), ZEND_STRS("_POST"), (void **)&carrier);
(void)zend_hash_find(&EG(symbol_table), ZEND_STRS("_REQUEST"), (void **)&carrier);
(void)zend_hash_find(&EG(symbol_table), ZEND_STRS("_COOKIE"), (void **)&carrier);
(void)zend_hash_find(&EG(symbol_table), ZEND_STRS("_FILES"), (void **)&carrier);
(void)zend_hash_find(&EG(symbol_table), ZEND_STRS("_ENV"), (void **)&carrier);

二、现在来看案例,定义一个类request,拥有方法getQuery与getPost.来读取$_GET和$_POST

/*
 * fw_request.c
 *
 * Created on: 2012-6-19
 * Author: jy
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "main/SAPI.h"
#include "Zend/zend_exceptions.h"
#include "Zend/zend_alloc.h"

#include "php_fw.h"
#include "fw_request.h"

zend_class_entry *request;

/**
 *
class Request {
 public mixed getLang ( void );
 public mixed getQuery ( string $name = NULL );
}
 */

//定义类方法的参数类型,使内核自动校验参数类型
ZEND_BEGIN_ARG_INFO(getQueryArgs, 1)
 ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

ZEND_BEGIN_ARG_INFO(getPostArgs, 1)
 ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()

ZEND_METHOD(request, getQuery)
{
 zval **carrier;
 zval *key, *ret;

if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE){
 RETURN_FALSE;
 }

ret = request_query(TRACK_VARS_GET, Z_STRVAL_P(key), Z_STRLEN_P(key) TSRMLS_CC);

RETURN_ZVAL(ret, 0, NULL);
}

ZEND_METHOD(request, getPost)
{
 zval **carrier;
 zval *key, *ret;

if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &key) == FAILURE){
 RETURN_FALSE;
 }

ret = request_query(TRACK_VARS_POST, Z_STRVAL_P(key), Z_STRLEN_P(key) TSRMLS_CC);

RETURN_ZVAL(ret, 0, NULL);
}

zend_function_entry functions_entry[] = {
 PHP_ME(request, getQuery, getQueryArgs, ZEND_ACC_PUBLIC)
 PHP_ME(request, getPost, getPostArgs, ZEND_ACC_PUBLIC)
};

ZEND_MINIT_FUNCTION(fw_request)
{
 zend_class_entry ce;

INIT_CLASS_ENTRY(ce, "request", functions_entry);

request = zend_register_internal_class_ex(&ce, NULL, NULL TSRMLS_CC);

return SUCCESS;
}

/*
定义request_query来完成内核中读取$_GET$_POST$_SERVER$_FILES$_COOKIE$_REQUEST
其中只有$_REQUEST的值是可修改的
*/
zval * request_query(uint type, char * name, uint len TSRMLS_DC) {
 zval **carrier, **ret;

zend_bool jit_initialization = (PG(auto_globals_jit) && !PG(register_globals) && !PG(register_long_arrays));

switch (type) {
 case TRACK_VARS_POST:
 case TRACK_VARS_GET:
 case TRACK_VARS_FILES:
 case TRACK_VARS_COOKIE:
 carrier = &PG(http_globals)[type];
 break;
 case TRACK_VARS_ENV:
 if (jit_initialization) {
 zend_is_auto_global(ZEND_STRL("_ENV") TSRMLS_CC);
 }
 carrier = &PG(http_globals)[type];
 break;
 case TRACK_VARS_SERVER:
 if (jit_initialization) {
 zend_is_auto_global(ZEND_STRL("_SERVER") TSRMLS_CC);
 }
 carrier = &PG(http_globals)[type];
 break;
 case TRACK_VARS_REQUEST:
 if (jit_initialization) {
 zend_is_auto_global(ZEND_STRL("_REQUEST") TSRMLS_CC);
 }
 (void)zend_hash_find(&EG(symbol_table), ZEND_STRS("_REQUEST"), (void **)&carrier);
 break;
 default:
 break;
 }

if (!carrier || !(*carrier)) {
 zval *empty;
 MAKE_STD_ZVAL(empty);
 ZVAL_NULL(empty);
 return empty;
 }

if (!len) {
 Z_ADDREF_P(*carrier);
 return *carrier;
 }

if (zend_hash_find(Z_ARRVAL_PP(carrier), name, len + 1, (void **)&ret) == FAILURE) {
 zval *empty;
 MAKE_STD_ZVAL(empty);
 ZVAL_NULL(empty);
 return empty;
 }

Z_ADDREF_P(*ret);
 return *ret;
}

三、网页访问PHP测试

访问网址http://localhost/test.php?get=test,这个网址由你本地环境决定

$_GET['test'] = "abc";
$obj = new request();

echo $obj->getQuery('test')."<br>";

echo $obj->getPost('test');

输出结果:
test

这也证明了,request_query读取的是只读全局变量。

未经允许不得转载:SuperMan's blog » PHP内核中读取$_GET\$_POST等全局变量

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址