itsource

PHP가 $_GET 또는 $_POST 배열에서 '.' 문자의 치환을 중지하도록 합니다.

mycopycode 2022. 9. 14. 22:26
반응형

PHP가 $_GET 또는 $_POST 배열에서 '.' 문자의 치환을 중지하도록 합니다.

를 PHP와 함께 .$ 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입니다.

그 이유에 대한 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를 사용합니다).

오랫동안 질문에 답했지만 실제로는 더 나은 답변(또는 회피책)이 있습니다.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'); }
?>

오픈에 큰 도움이 되다ID 매개 변수. 각각 '.'와 '_'를 모두 포함하며, 각각 특정 의미를 가집니다.

위의 코멘트에서 Johan에 의한 실제 답변을 강조 표시 - 저는 방금 투고 전체를 문제를 완전히 우회하는 톱 레벨 어레이로 정리했습니다.부하 처리는 필요 없습니다.

당신이 하는 형태로

<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'];

나의 견해는 완전히 틀에 박힌 것이었기 때문에, 나에게 이것은 두 줄의 변화였다.

참고로, 필드 이름에 점을 사용하여 그룹화된 데이터의 트리를 편집합니다.

표준규격에 준거하여 딥 어레이와 연동되는 솔루션을 원하십니까(예:?param[2][5]=10 ? ) 。

이 문제의 가능한 모든 원인을 수정하려면 PHP 코드 맨 위에 신청하십시오.

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

이 기능은 2013년 여름휴가 때 생각해 낸 멋진 아이디어입니다.이름을 한 후 regex를 합니다. 모든 쿼리 이름을 가져와 인코딩한 다음(그래서 점이 보존됨) 일반을 사용합니다.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;
}

이는 마침표가 변수 이름에 유효하지 않은 문자이기 때문에 발생하며, 이유는 PHP 구현에 매우 깊이 있기 때문에 쉬운 수정은 아직 없습니다.

그 사이에, 다음의 방법으로 이 문제를 해결할 수 있습니다.

  1. 에 대한 은 adda를 .php://input 또는 POST의 $_SERVER['QUERY_STRING'] GET 데 for for
  2. 변환 함수를 사용합니다.

변환 PHP > .4는 각 , 의 「(PHP >= 5.4)」를 합니다.parse_str();가 완료되면 16진수 이름을 원래 형식으로 되돌립니다.

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

이 접근방식은 Rock 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;                                              
        }                                                                      
    }                                                                          
}                                                                              

이 문제가 발생하는 이유는 PHP의 오래된 register_globals 기능 때문입니다..문자는 변수 이름에 유효한 문자가 아니기 때문에 호환성을 확인하기 위해 밑줄로 덮어씁니다.

즉, URL 변수에 마침표를 찍는 것은 좋은 방법이 아닙니다.

PHP가 $_GET 또는 $_POST 배열에서 문자 그대로 '.'를 대체하는 방법을 찾는다면, 그러한 방법 중 하나는 PHP의 소스를 수정하는 것입니다(이 경우 비교적 간단합니다).

경고: PHP C 소스를 수정하는 것은 고급 옵션입니다!

또한 동일한 수정을 제안하는 이 PHP 버그 보고서를 참조하십시오.

탐색하려면 다음 작업을 수행해야 합니다.

소스 변경 자체는 사소한 것으로, 의 1행의 절반만 갱신할 필요가 있습니다.main/php_variables.c:

....
/* 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='_';
....

: 오리지널과의 : ★★★★★★★★★★★★★★★★★★★★★★★★★★」|| *p == '.'


출력 예:

QUERY_STRING "의 a.a[]=bb&a.a[]=BB&c%20c=dd, 달리기, 뛰다.<?php print_r($_GET);츠키다

어레이([a.a] => 어레이([0] => bb[1] => BB)
[c_c] => dd)

주의:

  • 이 패치는 원래 질문에만 대응합니다(스페이스가 아닌 도트 치환을 중지합니다).
  • 이 패치로 실행하는 것은 스크립트 레벨의 솔루션보다 빠릅니다만, PHP 자체를 변경하지 않기 때문에, 이러한 pure.php의 답변은 여전히 일반적으로 바람직합니다.
  • 는 여기서 하기 위해 의 변화를 하는 어프로치를 할 수 .parse_str()및 (사용할 수 없는 경우) 저속 메서드로 폴백합니다.

이 문제에 대한 나의 해결책은 빠르고 지저분했지만, 나는 여전히 그것을 좋아한다.저는 단지 양식에 체크된 파일명의 목록을 올리고 싶었습니다.하였습니다.base64_encode후, 「」, 「」로 합니다.base64_decode★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

Rock의 솔루션을 검토한 후 아래 답변의 한계와 crb의 위, 그리고 Rock의 솔루션을 해결하는 버전을 생각해냈습니다.개선된 버전을 참조하십시오.


위의 @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;
}

crb를 사용하여 저는 이 파일을 재현하고 싶었습니다.$_POST다만, 클라이언트와 서버 양쪽에서 올바르게 인코딩 및 디코딩하고 있는 것을 확인할 필요가 있습니다.캐릭터가 정말 무효이고 그것이 정말 유효한지를 이해하는 것이 중요합니다.또한 예외 없이 database 명령어함께 사용하기 전에 클라이언트 데이터를 항상 이스케이프해야 합니다.

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

언급URL : https://stackoverflow.com/questions/68651/get-php-to-stop-replacing-characters-in-get-or-post-arrays

반응형