data - php post url




讓PHP停止替換'。' $_GET或$_POST數組中的字符? (10)

如果我傳遞PHP變量. 在他們的名字中通過$ _GET 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>";

...輸出以下內容:

url is /SpShipTool/php/testGetUrl.php?x.y=a.b
x.y is .
x_y is a.b.

......我的問題是這樣的:有什麼方法可以讓我停下來嗎? 不能為我的生活弄清楚我做了什麼值得這樣做

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


..

你為什麼不把所有的點都轉換成某種令牌,例如轉換為(〜#〜)然後發布它? 收到vars後,你可以將它們重新轉換回來..這是因為有時我們需要發布下劃線..如果將所有“_”重新轉換為“。”,我們就會鬆開它們。


使用crb我想重新創建$_POST數組作為一個整體,但請記住,你仍然必須確保在客戶端和服務器上正確編碼和解碼。 重要的是要了解角色何時真正無效且真正有效 。 此外,在將數據庫命令與任何數據庫命令一起使用之前,人們仍然應該始終將客戶端數

<?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);
?>

我建議僅在個別情況下使用此功能,但我不確定將其置於主頭文件頂部的負面影響。


在看了Rok的解決方案之後,我想出了一個版本,它解決了我在下面的答案中的限制,crb以及Rok的解決方案。 查看我的改進版本

@ crb的答案是一個好的開始,但有幾個問題。

  • 它重新處理了一切,這是過度的; 只有那些有“。”的字段。 在名稱中需要重新處理。
  • 它無法以與本機PHP處理相同的方式處理數組,例如對於像“foo.bar []”這樣的鍵。

下面的解決方案現在解決了這兩個問題(注意它自最初發布以來已經更新)。 這比我在測試中的答案快約50%,但是不會處理數據具有相同鍵的情況(或者提取相同鍵的鍵,例如foo.bar和foo_bar都被提取為foo_bar)。

<?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]);                                       
            }                                                                  
        }                                                                      
    }                                                                          
}                                                                              

好吧,我在下麵包含的函數“getRealPostArray()”,不是一個漂亮的解決方案,但它處理數組並支持兩個名稱:“alpha_beta”和“alpha.beta”:

  <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>

而var_dump($ _ POST)產生:

  '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)

var_dump(getRealPostArray())生成:

  '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允許您處理原始輸入流 ,因此您可以執行以下操作:

$query_string = file_get_contents('php://input');

這將為您提供查詢字符串格式的$ _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'); }
?>

對於包含'。'的OpenID參數非常有用。 和'_',每個都有一定的意義!


我對這個問題的解決方案既快又髒,但我還是喜歡它。 我只是想發布一個在表單上檢查過的文件名列表。 我使用base64_encode對標記中的文件名進行編碼,然後在使用之前用base64_decode進行解碼。


發生這種情況是因為句點是變量名稱中的無效字符,其reason在於PHP的實現非常深入,因此沒有簡單的修復(尚未)。

在此期間,您可以通過以下方式解決此問題:

  1. 通過用於POST數據的php://input或用於GET數據的$_SERVER['QUERY_STRING']訪問原始查詢數據
  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']);

要么:

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

發生這種情況的原因是PHP的舊register_globals功能。 這個。 character不是變量名中的有效字符,因此PHP會將其轉換為下劃線以確保兼容性。

簡而言之,在URL變量中執行句點不是一個好習慣。


這是PHP.net對其原因的解釋:

傳入變量名稱中的點

通常,PHP在傳遞到腳本時不會更改變量的名稱。 但是,應該注意,點(句點,句號)不是PHP變量名中的有效字符。 出於這個原因,看看它:

<?php
$varname.ext;  /* invalid variable name */
?>

現在,解析器看到的是一個名為$ varname的變量,後跟字符串連接運算符,後跟barestring(即不帶引號的字符串,它與任何已知的密鑰或保留字不匹配)'ext'。 顯然,這沒有預期的結果。

出於這個原因,重要的是要注意PHP將使用下劃線自動替換傳入變量名中的任何點。

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

此外,根據此評論,這些其他字符將轉換為下劃線:

PHP轉換為_(下劃線)的字段名稱字符的完整列表如下(不僅僅是點):

  • chr(32)()(空格)
  • chr(46)(。)(點)
  • chr(91)([)(空方括號)
  • chr(128) - chr(159)(各種)

所以看起來你已經堅持下去,所以你必須使用dawnerd的建議將下劃線轉換回腳本中的點(我只是使用str_replace 。)


這種方法是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;                                              
        }                                                                      
    }                                                                          
}                                                                              






postback