原文地址:https://www.hongweipeng.com/i...当启动表单提交给PHP脚本时,PHP底层会做一个转换层。将一些符号转换为下划线_。其实在这一层转换中会出现很多意想不到的情况。列举这些情况,一个简单的测试就出事故了。一是单个的[也会被替换,对于array的输入,key不会进行转换。所以我测试了很多并得到以下列表:变成:$_REQUEST["a_b"]变成:$_REQUEST["a_b"]变成:$_REQUEST["a_b"]变成:$_REQUEST["a]b"]转为:$_REQUEST["a-b"]转为:$_REQUEST["ab"]转为:$_REQUEST["ab"]变成:$_REQUEST["arr"]["a.b"]变成:$_REQUEST["ar_r"]["a.b"]变成:$_REQUEST["arr"]["a[b"]变成:$_REQUEST["arr"]["a["]变成:$_REQUEST["arr"][0]变成:$_REQUEST["arr"]["a"]变成:$_REQUEST["arr_a.b"]转化为:$_REQUEST["arr_[a.b"]这个转化机制很奇葩吧?查了一下,Bug#77172converterroronreceivingvariablesfromexternalsources中提出了id[]_texttoid[]convertingerror的问题,结果补全了文档上的描述。还有一些关于是否关闭此转换的讨论:Request#34882Unabletoaccessoriginalpostedvariablenamewithdotin;请求#37040变量名的自动转换应该关闭建议取消讨论这个转换;请求#65252输入字符串解析-允许''和'.'charsashashkey讨论转换的hash冲突;这三个Request都还在open,目前还没有结果,关闭转换的讨论早在2006年就提出来了。我不清楚PHP为什么要做这个转换,目的是什么。据我所知java,Django不会做转换。PHP会对外部输入的变量进行转换,涉及$_POST、$_GET、$_FILES、$_COOKIE、$_REQUEST等变量。源码分析虽然没有看过php源码,但是在朋友的帮助下,这部分的转换代码是在main/php_variables.c的php_register_variable_ex函数中的php_variables.c#L68。源代码简化了这个过程:PHPAPIvoidphp_register_variable_ex(char*var_name,zval*val,zval*track_vars_array){char*p=NULL;char*ip=NULL;/*索引指针*/char*index;字符*var,*var_orig;/*忽略变量名中的前导空格*/while(*var_name==''){//忽略前导空格var_name++;}for(p=var;*p;p++){if(*p==''||*p=='.'){//空格和点替换为下划线*p='_';}elseif(*p=='['){is_array=1;//如果遇到[,则认为是数组,is_array设置为1ip=p;*p=0;休息;}}...}这里可以看出忽略前导空格是第一个动作;遇到第一个[,php认为是数组,不再转换,设置is_array=1break。这个is_array有什么用,往下看:if(is_array){intnest_level=0;while(1){char*index_s;size_tnew_idx_len=0;知识产权++;//[下一个字符index_s=ip;if(*ip==']'){//如果下一个字符已经是],则说明没有设置keyindex_s=NULL;}else{ip=strchr(ip,']');//在剩余的字符串中查找键]if(!ip){/*PHP变量的名称中不能包含'[',所以我们用'_'替换字符*/*(index_s-1)='_';//如果没有找到,则用下划线替换[index_len=0;如果(索引){index_len=strlen(索引);}gotoplain_var;返回;}*IP=0;new_idx_len=strlen(index_s);//lengthofkeytofirstoccurrence]until}}...}至此,转换过程就很清晰了。对于数组情况下的变量名,有两种:]没有找到匹配,变量名不是数组。用下划线替换[,不处理后面的字符串;如果有]与之匹配,则将]第一次出现的位置作为key,后面的字符将被丢弃。对于情况1来说很奇怪,如果输入是arr[[a.b那么它将被转换为arr_[a.b。总结鉴于目前的转换规则,总结规则如下:在第一个[之前的字符中,忽略前面的空格,替换为.和带有下划线_的空格;第一个[之后的字符不会被替换:如果后面的字符中没有],第一个[被替换为_,后面的字符串不被转换;如果后面的字符中有],则以]第一次出现的位置为key,丢弃后面的字符。另外,谁能告诉我PHP的这一层转换的设计初衷是什么。