让PHP停止替换'';$\u GET或$\u POST数组中的字符?
如果我通过$传递名称中带有让PHP停止替换'';$\u GET或$\u POST数组中的字符?,php,regex,postback,Php,Regex,Postback,如果我通过$传递名称中带有的PHP变量,那么PHP会自动将它们替换为字符。例如: <?php echo "url is ".$_SERVER['REQUEST_URI']."<p>"; echo "x.y is ".$_GET['x.y'].".<p>"; echo "x_y is ".$_GET['x_y'].".<p>"; 。。。我的问题是:有什么方法可以让这一切停止吗?我一辈子都不知道我做了什么才配得到这个 我运行的PHP版本是5.2.4-2ub
的PHP变量,那么PHP会自动将它们替换为
字符。例如:
<?php
echo "url is ".$_SERVER['REQUEST_URI']."<p>";
echo "x.y is ".$_GET['x.y'].".<p>";
echo "x_y is ".$_GET['x_y'].".<p>";
。。。我的问题是:有什么方法可以让这一切停止吗?我一辈子都不知道我做了什么才配得到这个
我运行的PHP版本是5.2.4-2ubuntu5.3。发生这种情况的原因是PHP的旧register\u globals功能。这个字符不是变量名中的有效字符,因此PHP将其转换为下划线以确保兼容性
简而言之,在URL变量中使用句点不是一个好的做法。下面是PHP.net对其使用原因的解释: 传入变量名中的点 通常,PHP不会改变 变量的名称,当它们是 传递到脚本中。但是, 应该注意的是,点(周期, 句号)不是中的有效字符 PHP变量名。因此,, 看看它:
<?php
$varname.ext; /* invalid variable name */
?>
现在,什么
解析器看到的是一个名为
$varname,后跟字符串
串联运算符,后跟
裸字符串(即无引号的字符串
与任何已知的密钥或
保留字“ext”。显然,这
没有达到预期的效果
因此,重要的是
请注意,PHP将自动
替换传入变量中的任何点
带下划线的名称
那是我的
此外,根据这些规则,其他字符将转换为下划线:
PHP转换为(下划线)的字段名字符的完整列表如下(不仅仅是点):
- chr(32)((空格)
- chr(46)()(dot)
- chr(91)([)(开方括号)
- chr(128)-chr(159)(各种)
因此,看起来您似乎被它困住了,所以您必须使用(我只是使用)将脚本中的下划线转换回点。早就回答了这个问题,但实际上有一个更好的答案(或解决方法)。PHP允许您使用,所以您可以这样做:
$query_string = file_get_contents('php://input');
这将为您提供查询字符串格式的$\u POST数组,句点应为
如果需要,您可以解析它(根据)
我对这个问题的解决方案既快又脏,但我仍然喜欢它。我只是想发布一个在表单上检查过的文件名列表。我使用base64\u encode
对标记中的文件名进行编码,然后在使用它们之前用base64\u decode
对其进行解码。发生这种情况是因为一个句点是一个字符变量名中的无效字符,该字符在PHP实现中非常深入,因此没有简单的修复方法(目前)
同时,您可以通过以下方式解决此问题:
通过php://input
用于发布数据或$\u服务器['QUERY\u STRING']
用于获取数据
使用转换函数
下面的转换函数(PHP>=5.4)将每个键值对的名称编码为十六进制表示,然后执行常规的parse_str()
;完成后,它会将十六进制名称恢复为原始形式:
function parse_qs($data)
{
$data = preg_replace_callback('/(?:^|(?<=&))[^=[]+/', function($match) {
return bin2hex(urldecode($match[0]));
}, $data);
parse_str($data, $values);
return array_combine(array_map('hex2bin', array_keys($values)), $values);
}
// work with the raw query string
$data = parse_qs($_SERVER['QUERY_STRING']);
在研究了Rok的解决方案后,我提出了一个版本,该版本解决了我下面的答案、crb的上面以及Rok的解决方案中的局限性。请参阅a
@crb的回答是一个良好的开端,但也存在一些问题
- 它会重新处理所有内容,这太过分了;只有那些名称中有“.”的字段需要重新处理
- 它无法以与本机PHP处理相同的方式处理数组,例如对于“foo.bar[]”之类的键
下面的解决方案现在解决了这两个问题(请注意,它自最初发布以来已经更新)。这比我在测试中的上述答案快50%左右,但不会处理数据具有相同密钥(或提取的密钥相同,例如foo.bar和foo_bar都提取为foo_bar)的情况
这种方法是Rok Kralj的改进版本,但需要进行一些调整,以提高效率(避免对未受影响的密钥进行不必要的回调、编码和解码)并正确处理数组密钥
A是可用的,欢迎任何反馈或建议
public function fix(&$target, $source, $keep = false) {
if (!$source) {
return;
}
$keys = array();
$source = preg_replace_callback(
'/
# Match at start of string or &
(?:^|(?<=&))
# Exclude cases where the period is in brackets, e.g. foo[bar.blarg]
[^=&\[]*
# Affected cases: periods and spaces
(?:\.|%20)
# Keep matching until assignment, next variable, end of string or
# start of an array
[^=&\[]*
/x',
function ($key) use (&$keys) {
$keys[] = $key = base64_encode(urldecode($key[0]));
return urlencode($key);
},
$source
);
if (!$keep) {
$target = array();
}
parse_str($source, $data);
foreach ($data as $key => $val) {
// Only unprocess encoded keys
if (!in_array($key, $keys)) {
$target[$key] = $val;
continue;
}
$key = base64_decode($key);
$target[$key] = $val;
if ($keep) {
// Keep a copy in the underscore key version
$key = preg_replace('/(\.| )/', '_', $key);
$target[$key] = $val;
}
}
}
公共函数修复(&$target,$source,$keep=false){
如果(!$source){
返回;
}
$keys=array();
$source=preg\u replace\u回调(
'/
#在字符串或&
(?:^ |)(?这个函数的工作是我在2013年暑假期间想到的一个好主意
它符合标准并具有深度数组支持,例如a.a[x][b.a]=10
。它在后台使用parse_str()
,并进行一些有针对性的预处理
function fix($source) {
$source = preg_replace_callback(
'/(^|(?<=&))[^=[&]+/',
function($key) { return bin2hex(urldecode($key[0])); },
$source
);
parse_str($source, $post);
$result = array();
foreach ($post as $key => $val) {
$result[hex2bin($key)] = $val;
}
return $result;
}
对于低于5.4的PHP:如果要查找任何方法来让PHP停止替换$get或$POST数组中的“.”字符,请使用base64_encode
而不是base64_decode,(在这种情况下,它相对简单)
警告:修改PHP C源代码是一个高级选项
也可以看到这一点,这表明同样的修改
要进行探索,您需要:
- 下载
- 禁用更换检查
// handle posted data (this only works with application/x-www-form-urlencoded)
$data = parse_qs(file_get_contents('php://input'));
<?php
public function fix2(&$target, $source, $keep = false) {
if (!$source) {
return;
}
preg_match_all(
'/
# Match at start of string or &
(?:^|(?<=&))
# Exclude cases where the period is in brackets, e.g. foo[bar.blarg]
[^=&\[]*
# Affected cases: periods and spaces
(?:\.|%20)
# Keep matching until assignment, next variable, end of string or
# start of an array
[^=&\[]*
/x',
$source,
$matches
);
foreach (current($matches) as $key) {
$key = urldecode($key);
$badKey = preg_replace('/(\.| )/', '_', $key);
if (isset($target[$badKey])) {
// Duplicate values may have already unset this
$target[$key] = $target[$badKey];
if (!$keep) {
unset($target[$badKey]);
}
}
}
}
public function fix(&$target, $source, $keep = false) {
if (!$source) {
return;
}
$keys = array();
$source = preg_replace_callback(
'/
# Match at start of string or &
(?:^|(?<=&))
# Exclude cases where the period is in brackets, e.g. foo[bar.blarg]
[^=&\[]*
# Affected cases: periods and spaces
(?:\.|%20)
# Keep matching until assignment, next variable, end of string or
# start of an array
[^=&\[]*
/x',
function ($key) use (&$keys) {
$keys[] = $key = base64_encode(urldecode($key[0]));
return urlencode($key);
},
$source
);
if (!$keep) {
$target = array();
}
parse_str($source, $data);
foreach ($data as $key => $val) {
// Only unprocess encoded keys
if (!in_array($key, $keys)) {
$target[$key] = $val;
continue;
}
$key = base64_decode($key);
$target[$key] = $val;
if ($keep) {
// Keep a copy in the underscore key version
$key = preg_replace('/(\.| )/', '_', $key);
$target[$key] = $val;
}
}
}
function fix($source) {
$source = preg_replace_callback(
'/(^|(?<=&))[^=[&]+/',
function($key) { return bin2hex(urldecode($key[0])); },
$source
);
parse_str($source, $post);
$result = array();
foreach ($post as $key => $val) {
$result[hex2bin($key)] = $val;
}
return $result;
}
$_POST = fix(file_get_contents('php://input'));
$_GET = fix($_SERVER['QUERY_STRING']);
$_COOKIE = fix($_SERVER['HTTP_COOKIE']);
Array
(
[a.a] => Array
(
[0] => bb
[1] => BB
)
[c_c] => dd
)
<input name="data[database.username]">
<input name="data[database.password]">
<input name="data[something.else.really.deep]">
<input name="database.username">
<input name="database.password">
<input name="something.else.really.deep">
$posdata = $_POST['data'];
<input type='text' value='First-.' name='alpha.beta[a.b][]' /><br>
<input type='text' value='Second-.' name='alpha.beta[a.b][]' /><br>
<input type='text' value='First-_' name='alpha_beta[a.b][]' /><br>
<input type='text' value='Second-_' name='alpha_beta[a.b][]' /><br>
'alpha_beta' =>
array (size=1)
'a.b' =>
array (size=4)
0 => string 'First-.' (length=7)
1 => string 'Second-.' (length=8)
2 => string 'First-_' (length=7)
3 => string 'Second-_' (length=8)
'alpha.beta' =>
array (size=1)
'a.b' =>
array (size=2)
0 => string 'First-.' (length=7)
1 => string 'Second-.' (length=8)
'alpha_beta' =>
array (size=1)
'a.b' =>
array (size=2)
0 => string 'First-_' (length=7)
1 => string 'Second-_' (length=8)
function getRealPostArray() {
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {#Nothing to do
return null;
}
$neverANamePart = '~#~'; #Any arbitrary string never expected in a 'name'
$postdata = file_get_contents("php://input");
$post = [];
$rebuiltpairs = [];
$postraws = explode('&', $postdata);
foreach ($postraws as $postraw) { #Each is a string like: 'xxxx=yyyy'
$keyvalpair = explode('=',$postraw);
if (empty($keyvalpair[1])) {
$keyvalpair[1] = '';
}
$pos = strpos($keyvalpair[0],'%5B');
if ($pos !== false) {
$str1 = substr($keyvalpair[0], 0, $pos);
$str2 = substr($keyvalpair[0], $pos);
$str1 = str_replace('.',$neverANamePart,$str1);
$keyvalpair[0] = $str1.$str2;
} else {
$keyvalpair[0] = str_replace('.',$neverANamePart,$keyvalpair[0]);
}
$rebuiltpair = implode('=',$keyvalpair);
$rebuiltpairs[]=$rebuiltpair;
}
$rebuiltpostdata = implode('&',$rebuiltpairs);
parse_str($rebuiltpostdata, $post);
$fixedpost = [];
foreach ($post as $key => $val) {
$fixedpost[str_replace($neverANamePart,'.',$key)] = $val;
}
return $fixedpost;
}
<?php
unset($_POST);
$_POST = array();
$p0 = explode('&',file_get_contents('php://input'));
foreach ($p0 as $key => $value)
{
$p1 = explode('=',$value);
$_POST[$p1[0]] = $p1[1];
//OR...
//$_POST[urldecode($p1[0])] = urldecode($p1[1]);
}
print_r($_POST);
?>
function parseQueryString($data)
{
$data = rawurldecode($data);
$pattern = '/(?:^|(?<=&))[^=&\[]*[^=&\[]*/';
$data = preg_replace_callback($pattern, function ($match){
return bin2hex(urldecode($match[0]));
}, $data);
parse_str($data, $values);
return array_combine(array_map('hex2bin', array_keys($values)), $values);
}
$_GET = parseQueryString($_SERVER['QUERY_STRING']);