让PHP停止替换'.' $ _GET或$ _POST数组中的字符?

71 php regex postback

如果我.通过$ _GET 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>";
Run Code Online (Sandbox Code Playgroud)

...输出以下内容:

url is /SpShipTool/php/testGetUrl.php?x.y=a.b
x.y is .
x_y is a.b.
Run Code Online (Sandbox Code Playgroud)

......我的问题是这样的:有什么方法可以阻止它吗?不能为我的生活弄清楚我做了什么值得这样做

我运行的PHP版本是5.2.4-2ubuntu5.3.

Jer*_*ten 63

这是PHP.net对其原因的解释:

输入变量名称中的点

通常,PHP在传递到脚本时不会更改变量的名称.但是,应该注意,点(句点,句号)不是PHP变量名中的有效字符.出于这个原因,看看它:

<?php
$varname.ext;  /* invalid variable name */
?>
Run Code Online (Sandbox Code Playgroud)

现在,解析器看到的是一个名为$ varname的变量,后跟字符串连接运算符,后跟barestring(即不带引号的字符串,它与任何已知的密钥或保留字不匹配)'ext'.显然,这没有预期的结果.

因此,请务必注意PHP会自动使用下划线替换传入变量名中的任何点.

那是来自http://ca.php.net/variables.external.

此外,根据此评论,这些其他字符将转换为下划线:

PHP转换为_(下划线)的字段名称字符的完整列表如下(不仅仅是点):

  • chr(32)()(空格)
  • chr(46)(.)(点)
  • chr(91)([)(空方括号)
  • chr(128) - chr(159)(各种)

因此看起来你已经坚持使用它,所以你必须使用dawnerd的建议将下划线转换回脚本中的点(我只是使用str_replace.)

  • 这是*为什么*的一个很好的解释,但没有回答"有没有办法让它停止"的原始问题; 下面的其他答案确实提供了原始问题的答案. (17认同)

crb*_*crb 58

很久以来一直回答问题,但实际上有更好的答案(或解决方法).PHP允许您处理原始输入流,因此您可以执行以下操作:

$query_string = file_get_contents('php://input');
Run Code Online (Sandbox Code Playgroud)

这将为您提供查询字符串格式的$ _POST数组,它们应该是句点.

然后,如果需要,您可以解析它(根据POSTer的评论)

<?php
// Function to fix up PHP's messing up input containing dots, etc.
// `$source` can be either 'POST' or 'GET'
function getRealInput($source) {
    $pairs = explode("&", $source == 'POST' ? file_get_contents("php://input") : $_SERVER['QUERY_STRING']);
    $vars = array();
    foreach ($pairs as $pair) {
        $nv = explode("=", $pair);
        $name = urldecode($nv[0]);
        $value = urldecode($nv[1]);
        $vars[$name] = $value;
    }
    return $vars;
}

// Wrapper functions specifically for GET and POST:
function getRealGET() { return getRealInput('GET'); }
function getRealPOST() { return getRealInput('POST'); }
?>
Run Code Online (Sandbox Code Playgroud)

对于包含'.'的OpenID参数非常有用.和'_',每个都有一定的意义!

  • 为了使用GET参数,使用`$ _SERVER ['QUERY_STRING']`替换`file_get_contents("php:// input")`. (5认同)
  • 这是一个良好的开端,但它有几个问题.它不处理数组值(例如foo.bar [] = blarg不会以数组结尾,它最终将作为一个名为foo.bar []的标量变量.它重新处理所有值时也会有很多开销,无论它们是否存在句点. (4认同)

sci*_*lot 26

在上面的评论中突出显示Johan的实际答案 - 我只是将我的整个帖子包装在顶级数组中,完全绕过问题而不需要繁重的处理.

在你做的形式

<input name="data[database.username]">  
<input name="data[database.password]">  
<input name="data[something.else.really.deep]">  
Run Code Online (Sandbox Code Playgroud)

代替

<input name="database.username"> 
<input name="database.password"> 
<input name="something.else.really.deep">  
Run Code Online (Sandbox Code Playgroud)

并在邮政处理程序中,只需打开它:

$posdata = $_POST['data'];
Run Code Online (Sandbox Code Playgroud)

对我而言,这是一个两线的变化,因为我的观点完全是模板化的.

仅供参考.我在字段名称中使用点来编辑分组数据的树.

  • 确实非常优雅和实用的解决方案,具有保持表单数据很好地命名空间的附带好处. (4认同)

Rok*_*alj 18

这个功能的工作是我在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;
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样调用这个函数,具体取决于来源:

$_POST   = fix(file_get_contents('php://input'));
$_GET    = fix($_SERVER['QUERY_STRING']);
$_COOKIE = fix($_SERVER['HTTP_COOKIE']);
Run Code Online (Sandbox Code Playgroud)

对于低于5.4 PHP:使用base64_encode代替bin2hexbase64_decode代替的hex2bin.


Ja͢*_*͢ck 6

发生这种情况是因为句点是变量名称中的无效字符,其原因在于PHP的实现非常深入,因此没有简单的修复(尚未).

在此期间,您可以通过以下方式解决此问题:

  1. 通过php://inputPOST数据或$_SERVER['QUERY_STRING']GET数据访问原始查询数据
  2. 使用转换功能.

下面的转换函数(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']);
Run Code Online (Sandbox Code Playgroud)

要么:

// handle posted data (this only works with application/x-www-form-urlencoded)
$data = parse_qs(file_get_contents('php://input'));
Run Code Online (Sandbox Code Playgroud)


El *_*obo 5

这种方法是Rok Kralj的改进版本,但需要进行一些调整,以提高效率(避免不必要的回调,对未受影响的键进行编码和解码)并正确处理数组键.

我们提供了有测试要点,欢迎任何反馈或建议.

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;                                              
        }                                                                      
    }                                                                          
}                                                                              
Run Code Online (Sandbox Code Playgroud)