PHP的GET/POST等大变量生成过程
时间:2008-11-21
来源:互联网
· 本文地址: http://www.laruence.com/2008/11/07/581.html
· 转载请注明出处
主要探讨了PHP的大变量的生成过程。另外如果你注意到, 当在表单中提交的input的name中如果有点号的时候, 在PHP中会自动把点号处理成下划线。并且你很想知道这是为什么,在什么时候发生的? 呵呵,本文也就这个问题做了回答。
首先明确一个问题,PHP的变量名中是不能包含点号的。 但是为了处理表单中的点号命名,PHP就会自动把点号(.)转换成下划线(_)。
要知道PHP是怎么处理的,首先我们要了解,$_GET, $_POST, $_COOKIE等变量的构造过程。
在每个请求到来以后,apache处理到response阶段的时候, 会将控制权交给PHP模块, PHP模块会在处理请求之前首先间接调用php_request_startup (具体调用序列是send_php -> apache_php_module_main ->php_request_startup, 关于这部门可以参看我前面的文章(PHP Life Cycle) , 在php_request_startup中:
int
php_request_startup(TSRMLS_D)
{
int
retval = SUCCESS;
#if PHP_SIGCHILD
signal(SIGCHLD, sigchld_handler);
#endif
if
(php_start_sapi() == FAILURE)
{
return
FAILURE;
}
php_output_activate(TSRMLS_C);
sapi_activate(TSRMLS_C);
php_hash_environment(TSRMLS_C);
zend_try
{
PG(during_request_startup) = 1;
php_output_activate(TSRMLS_C);
if
(PG(expose_php))
{
sapi_add_header(SAPI_PHP_VERSION_HEADER, sizeof(SAPI_PHP_VERSION_HEADER)-1, 1);
}
}
zend_catch
{
retval = FAILURE;
}
zend_end_try();
return
retval;
}
注意其中的php_hash_environment(TSRMLS_C) 函数调用 , 这个函数就是在请求处理前, 初始化请求相关的变量的函数。
这个函数定义在: main/php_variables.c中 , 有兴趣的可以看看:
int
php_hash_environment(TSRMLS_D)
{
char *p;
unsigned
char
_gpc_flags[5] = {0, 0, 0, 0, 0};
zend_bool
jit_initialization = (PG(auto_globals_jit) && !PG(register_globals) && !PG(register_long_arrays));
struct
auto_global_record
{
char *name;
uint
name_len;
char *long_name;
uint
long_name_len;
zend_bool
jit_initialization;
}
auto_global_records[] = {
{
"_POST", sizeof("_POST"), "HTTP_POST_VARS", sizeof("HTTP_POST_VARS"), 0
},
{
"_GET", sizeof("_GET"), "HTTP_GET_VARS", sizeof("HTTP_GET_VARS"), 0
},
{
"_COOKIE", sizeof("_COOKIE"), "HTTP_COOKIE_VARS", sizeof("HTTP_COOKIE_VARS"), 0
},
{
"_SERVER", sizeof("_SERVER"), "HTTP_SERVER_VARS", sizeof("HTTP_SERVER_VARS"), 1
},
{
"_ENV", sizeof("_ENV"), "HTTP_ENV_VARS", sizeof("HTTP_ENV_VARS"), 1
},
{
"_FILES", sizeof("_FILES"), "HTTP_POST_FILES", sizeof("HTTP_POST_FILES"), 0
},
};
size_t
num_track_vars = sizeof(auto_global_records)/sizeof(struct
auto_global_record);
size_t
i;
/* jit_initialization = 0; */
for
(i=0; i<num_track_vars; i++)
{
PG(http_globals)[i] = NULL;
}
for
(p=PG(variables_order); p && *p; p++)
{
switch(*p)
{
case
'p':
case
'P':
if
(!_gpc_flags[0] && !SG(headers_sent) && SG(request_info).request_method && !strcasecmp(SG(request_info).request_method, "POST"))
{
sapi_module.treat_data(PARSE_POST, NULL, NULL
TSRMLS_CC); /* POST Data */
_gpc_flags[0] = 1;
if
(PG(register_globals))
{
php_autoglobal_merge(&EG(symbol_table), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST])
TSRMLS_CC);
}
}
break;
....以下省略:
}}}
到了这里说个题外话, 就是在php.ini中, 可以使用variables_order来控制PHP是否生成某个大变量,已经大变量的生成顺序。
关于顺序,就是说, 如果打开了auto_register_globals的情况下, 如果先处理p,后处理g,那么$_GET['a'],就会覆盖$_POST['a'];
可以看到,离成功不远了,sapi_module.treat_data 也就是php_default_treat_data,
在php_default_treat_data中,对于变量,都调用php_register_variable_safe来注册变量, 而php_register_variable_safe最终会调用php_register_variable_ex:
PHPAPI
void
php_register_variable_ex(char *var, zval *val, zval *track_vars_array
TSRMLS_DC)
{
char *p = NULL;
char *ip; /* index pointer */
char *index, *escaped_index = NULL;
int
var_len, index_len;
zval *gpc_element, **gpc_element_p;
zend_bool
is_array = 0;
HashTable *symtable1 = NULL;
assert(var != NULL);
if
(track_vars_array)
{
symtable1 = Z_ARRVAL_P(track_vars_array);
}
else
if
(PG(register_globals))
{
symtable1 = EG(active_symbol_table);
}
if
(!symtable1)
{
/* Nothing to do */
zval_dtor(val);
return;
}
/*
* Prepare variable name
*/
/* ignore leading spaces in the variable name */
while
(*var && *var=='
')
{
var++;
}
/* ensure that we don't have spaces or dots in the variable name (not binary safe) */
//特别注意以下这段。。。。
for
(p = var; *p; p++)
{
if
(*p == '
' || *p == '.')
{
*p='_';
}
else
if
(*p == '[')
{
is_array = 1;
ip = p;
*p = 0;
break;
}
....以下省略
呵呵,问题的原因找到了, 就是在php_register_variable的时候,会将(.)转换成(_).
最后,再介绍下$_REQUEST变量的生成, 其实很简单, 在php_hash_environment中的最后, 会调用php_auto_globals_create_request(”_REQUEST”, sizeof(”_REQUEST”)-1TSRMLS_CC)来注册_REQUEST大变量, 在php_auto_globals_create_request(”_REQUEST”,sizeof(”_REQUEST”)-1 TSRMLS_CC)中,只是简单的将$_GET, $_POST, $_COOKIEmerge起来(G(http_globals)[TRACK_VARS_COOKIE]这部分,可以参看我较早前的在PHP Module中获取$_GET/$_POST/$_COOKIE的方法研究) :
static
zend_bool
php_auto_globals_create_request(char *name, uint
name_len
TSRMLS_DC)
{
zval *form_variables;
unsigned
char
_gpc_flags[3] = {0, 0, 0};
char *p;
ALLOC_ZVAL(form_variables);
array_init(form_variables);
INIT_PZVAL(form_variables);
for
(p = PG(variables_order); p && *p; p++)
{
switch
(*p)
{
case 'g':
case 'G':
if
(!_gpc_flags[0])
{
php_autoglobal_merge(Z_ARRVAL_P(form_variables), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_GET])
TSRMLS_CC);
_gpc_flags[0] = 1;
}
break; case 'p':
case 'P':
if
(!_gpc_flags[1])
{
php_autoglobal_merge(Z_ARRVAL_P(form_variables), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_POST])
TSRMLS_CC);
_gpc_flags[1] = 1;
}
break;
case 'c':
case 'C': if
(!_gpc_flags[2])
{
php_autoglobal_merge(Z_ARRVAL_P(form_variables), Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE])
TSRMLS_CC);
_gpc_flags[2] = 1;
}
break;
}
}
zend_hash_update(&EG(symbol_table), "_REQUEST", sizeof("_REQUEST"), &form_variables, sizeof(zval *), NULL);
return
0;
}
作者: laruence 发布时间: 2008-11-21


作者: ieliwb 发布时间: 2008-11-23
作者: ws00377531 发布时间: 2008-11-24
作者: quanhaier 发布时间: 2008-11-24
这是原创么?
呵呵
作者: 0hudu 发布时间: 2008-11-24
作者: laruence 发布时间: 2008-11-24
我看上你了
太厉害了。。。
作者: xyiyo 发布时间: 2008-11-24
LZ来夜色吧
我看上你了
太厉害了。。。
作者: shanji 发布时间: 2008-11-24
LZ来夜色吧
我看上你了
太厉害了。。。
作者: 没办法 发布时间: 2008-11-27
作者: laruence 发布时间: 2008-11-28
作者: 第六条河 发布时间: 2008-11-30
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28