Yerine durdurmak için PHP alın. '

11 Cevap php

Ben. 'PHP değişkenleri geçirirseniz $ _GET PHP ile kendi adlarına '_' karakterleri ile otomatik değiştirir. Örneğin:

<?php
echo "url is ".$_SERVER['REQUEST_URI']."<p>";
echo "x.y is ".$_GET['x.y'].".<p>";
echo "x_y is ".$_GET['x_y'].".<p>";

... Aşağıdaki çıktılar:

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

Bunu durdurmak için alabileceğiniz any yolu var: ... Benim soru şudur? Beni yaşam için ben bu :-( hak edecek ne yaptık bilemiyorum

Ben koşuyorum PHP version 5.2.4-2ubuntu5.3 olduğunu.

11 Cevap

İşte bunu yapar neden PHP.net 'nin açıklaması var:

Dots in incoming variable names

Typically, PHP does not alter the names of variables when they are passed into a script. However, it should be noted that the dot (period, full stop) is not a valid character in a PHP variable name. For the reason, look at it:

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

Now, what the parser sees is a variable named $varname, followed by the string concatenation operator, followed by the barestring (i.e. unquoted string which doesn't match any known key or reserved words) 'ext'. Obviously, this doesn't have the intended result.

For this reason, it is important to note that PHP will automatically replace any dots in incoming variable names with underscores.

İşte http://ca.php.net/variables.external geliyor.

Ayrıca, uygun olarak this comment bu karakterler çizgi dönüştürülür:

PHP _ (alt çizgi) dönüştüren alan-adı karakterlerin tam listesini (sadece nokta değil) aşağıdaki gibidir:

  • chr (32) () (boşluk)
  • chr (46) (.) (nokta)
  • chr (91) ([) (açık köşeli ayraç)
  • chr (128) - chr (159) (çeşitli)

Yani onunla sıkışmış konum gibi görünüyor, bu yüzden dawnerd's suggestion kullanarak komut geri noktalar için çizgi dönüştürmek gerekir (Ben sadece olsa str_replace kullanmak istiyorum.)

Uzun beri soruyu yanıtladı, ancak (iş çevresinde ya da) daha iyi bir cevap aslında yoktur. PHP raw input stream sizi sağlar, bu yüzden böyle bir şey yapabilirsiniz:

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

sorgu dize biçiminde $ _POST dizi, onlar olması gerektiği gibi dönemleri verecektir.

Eğer (POSTer's comment) başı olarak ihtiyacınız varsa o zaman ayrıştırmak

<?php
// Function to fix up PHP's messing up POST input containing dots, etc.
function getRealPOST() {
    $pairs = explode("&", file_get_contents("php://input"));
    $vars = array();
    foreach ($pairs as $pair) {
        $nv = explode("=", $pair);
        $name = urldecode($nv[0]);
        $value = urldecode($nv[1]);
        $vars[$name] = $value;
    }
    return $vars;
}
?>

Hem de içeren OpenID parametreleri, için son derece yararlıdır. ' ve '_', belli bir anlam ile her!

Bu durumda nedeni PHP'nin eski register_globals işlevselliği olduğunu. . karakter bir değişken adı geçerli bir karakter değil, bu yüzden PHP uyumluluk var emin olmak için bir alt çizgi coverts.

Kısacası, URL değişkenleri dönemleri yapmak için iyi bir uygulama değil.

@ BRC çözümü olduğundan severely limited in functionality, ben de diziler idare edebilmek ve tam olarak diğer uygulamaları (Raylar / Django) gibi davranır mayın, yayınlamak için gidiyorum. Bu a.b[1 2][2.x]=5 gibi tüm köşe durumlarda, yönetir.

Özünde aynı talihsiz sıkan vardır (altçizgiye özel karakterleri çevirir) dışında hemen hemen tüm iş yapar PHP'nin parse_str() function, var.

Bu nedenle, tüm birinci anahtarlar HEX kodlanır ve daha sonra çözülür. Bu şekilde, nokta, boşluk ve diğer özel karakterler are preserved. Bu harika bir fikir.

function fix(&$target, $source, $discard = true) {
    if ($discard)
        $target = array();

    $source = preg_replace_callback(
        '/(^|(?<=&))[^=[]+/',
        function($key) { return bin2hex(urldecode($key[0])); },
        $source
    );

    parse_str($source, $post);
    foreach($post as $key => $val)
        $target[ hex2bin($key) ] = $val;
}

Ve sonra size böyle bu işlevini çağırabilirsiniz:

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

Çok eski / orijinal değerlerini korumak istiyorsanız false için $discard parametresini ayarlayabilirsiniz. Benim çözüm basitlik onayladı.

Bir dönem PHP uygulanmasında çok derin yatıyor reason hangi bir değişkenin adı geçersiz bir karakter, bu nedenle (henüz) yok kolay düzeltmeler vardır, çünkü bu olur.

: Bu arada sen bu soruna geçici çalışabilirsiniz

  1. php://input POST veri veya $_SERVER['QUERY_STRING'] GET veri ya yoluyla ham sorgu verilerine erişme
  2. Bir dönüştürme işlevini kullanma.

Aşağıdaki dönüştürme fonksiyonu (PHP> = 5.4) bir onaltılık gösterimi her bir anahtar-değer çiftinin adlarını kodlar ve daha sonra düzenli bir parse_str() gerçekleştirir; bir kez yapılır, geri orijinal forma onaltılık adlarını döner:

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

Veya:

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

Bu yaklaşım Rok Kralj en değişmiş versiyonu, ama verimliliği artırmak için, çalışmak için bazı uğraşmayla (gereksiz çağırımların, etkilenmemiş tuşları kodlama ve çözme önler) ve doğru dizisi tuşları işlemek için.

A gist with tests mevcuttur ve herhangi bir geri bildirim veya önerileri burada ya da orada açıktır.

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

Için any yol arıyorsanız literally yerine durdurmak için PHP olsun. ' $ _GET veya $ _POST diziler karakterler, daha sonra böyle bir yol PHP'nin kaynağını değiştirmek için (ve bu durumda oldukça basittir).

WARNING: Modifying PHP C source is an advanced option!

Ayrıca aynı değişiklik göstermektedir ki bu PHP bug report bkz.

Eğer gerekir keşfetmek için:

  • indir PHP's C source code
  • . yedek denetimini devre dışı
  • ./configure, make ve PHP, özelleştirilmiş yapı dağıtmak

Kaynağı değişikliği kendisi önemsiz ve sadece one half of one line güncellenmesi içerir 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='_';
....

Note: compared to original || *p == '.' yorumladı-out olmuştur


Örnek Çıktı:

given a QUERY_STRING of a.a[]=bb&a.a[]=BB&c%20c=dd, running <?php print_r($_GET); now produces:

Array
(
    [a.a] => Array
        (
            [0] => bb
            [1] => BB
        )

    [c_c] => dd
)

Notlar:

  • Bu yama sadece özgün soru (bu noktalar, boşlukların değil değiştirilmesini durur) giderir.
  • Bu yama üzerinde çalışan script düzeyde çözümler daha hızlı olabilir, ancak bu saf-.php cevaplar (onlar PHP kendisini değişen önlemek için) hala genel olarak-tercih edilir olacaktır.
  • in theory a polyfill approach is possible here and could combine approaches -- test for the C-level change using parse_str() and (if unavailable) fall-back to slower methods.

Bu sorunun benim çözüm hızlı ve kirli, ama ben yine de seviyorum. Ben sadece form üzerinde kontrol edildi dosya listesini yayınlamak istedik. I base64_encode biçimlendirme içindeki dosya adlarını kodlamak ve sonra sadece base64_decode önce bunları kullanarak bunu deşifre etmek için kullanılır.

Yukarıda bir yorum Johan tarafından gerçek bir cevap vurgulayarak - Ben sadece tamamen ağır işleme gerekli olan sorunu atlar üst düzey bir dizide benim tüm yazı tamamladı.

Yapmanız şeklinde

<input name="data[database.username]">  
<input name="data[database.password]">  
<input name="data[something.else.really.deep]">  

yerine

<input name="database.username"> 
<input name="database.password"> 
<input name="something.else.really.deep">  

ve sonrası işleyicisi, sadece açmak:

$posdata = $_POST['data'];

Benim görüşlerim tamamen şablonu olduğu gibi benim için bu, bir iki satır değişiklik oldu.

Bilginize. Ben gruplandırılmış veri ağaçları düzenlemek benim alan adları noktaları kullanıyorum.

..

Why don't you just convert all dots to some kind of token, like for instance, to (~#~) and then post it? When receiving the vars you can then reconvert them back.. This is because sometimes we NEED to post underscores.. and we would loose them if reconverting all "_" to "."s...

Rok 'çözüm baktıktan sonra aşağıda benim cevap sınırlamaları gideren bir versiyonu, crb en yukarıda ve Rok çözümü de birlikte geldi. Bir bakın my improved version.


@ BRC cevabı above iyi bir başlangıç, ama sorunları bir çift vardır.

  • ; Bu overkill şeyi, reprocesses a sahip olan alanlar "." adına tekrar işleme tabi tutulması gerekir.
  • Bu, örneğin, doğal PHP işlem yaptığı aynı şekilde diziler işlemek için başarısız "foo.bar []" gibi şifreler için.

Adresleri aşağıdadır çözüm bu sorunların her ikisi de şimdi (aslında yayınlanmıştır beri güncellenmiş olduğunu unutmayın). Bu benim test yukarıda benim cevap yaklaşık% 50 daha hızlı olduğunu, ancak veriler aynı anahtarı (veya aynı ayıklanır bir anahtar, örneğin foo.bar ve foo_bar hem foo_bar olarak ayıklanır) sahiptir durumlarla başa olmaz.

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