Domanda

Se io passo le variabili PHP con . nella loro nomi tramite $_GET PHP auto-li sostituisce con _ i caratteri.Per esempio:

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

...uscite le seguenti:

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

...la mia domanda è questa:c'è qualsiasi modo per ottenere questo?Non posso per la vita di me a capire cosa ho fatto per meritare questo

Versione di PHP sto correndo con 5.2.4-2ubuntu5.3.

È stato utile?

Soluzione

Ecco PHP.net's spiegazione del perché lo fa:

Punti in arrivo per i nomi delle variabili

In genere, PHP, non altera il i nomi delle variabili quando sono passati in uno script.Tuttavia, è dovrebbe essere notato che il punto (periodo, full stop) non è un carattere valido in una variabile PHP nome.Per la ragione che guarda:

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

Ora, che cosa vede il parser è una variabile di nome $varname, seguita dalla stringa operatore di concatenazione, seguita da il barestring (es.non quotate stringa che non appartiene a nessuna chiave o parole riservate) 'ext'.Ovviamente, questo non avere il risultato desiderato.

Per questo motivo, è importante nota che il PHP automaticamente sostituire eventuali punti di ingresso variabile nomi con caratteri di sottolineatura.

Da http://ca.php.net/variables.external.

Inoltre, secondo questo commento questi caratteri vengono convertiti in caratteri di sottolineatura:

La lista completa di caratteri del nome che PHP converte a carattere di sottolineatura ( _ ) è il seguente (non solo punto):

  • chr(32) ( ) (spazio)
  • chr(46) (.) (dot)
  • chr(91) ([) (aperta parentesi quadra)
  • chr(128) - chr(159) (varie)

Così sembra che sei bloccato con esso, in modo da dovrete convertire i caratteri di sottolineatura torna a punti in tuo script utilizzando dawnerd suggerimento (Vorrei proprio usare str_replace però.)

Altri suggerimenti

Lungo poiché risposto domanda, ma in realtà c'è una risposta migliore (o aggirare).PHP permette al raw flusso di input, così si può fare qualcosa di simile a questo:

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

che vi darà il $_POST array in una stringa di query formato, periodi, in quanto dovrebbe essere.

Si può quindi analizzare se hai bisogno di aiuto (come per POSTer commento)

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

Estremamente utile per OpenID parametri, che contengono sia '.' e '_', ciascuna con un certo senso!

Evidenziando una risposta concreta da Johan in un commento sopra, ho appena concluso il mio intero post in un array che bypassa completamente il problema senza una pesante elaborazione richiesta.

Il modulo che fare

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

invece di

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

e nel post gestore, basta aprire il pacco regalo:

$posdata = $_POST['data'];

Per me questo è stato un cambiamento, come il mio punto di vista sono stati interamente basato su modelli.

Cordiali saluti.Sto usando punti nel mio campo i nomi di modificare alberi di dati raggruppati.

Il funzionamento di questa funzione è un genio hack che mi è venuta durante le mie vacanze estive nel 2013.Vorrei scrivere un post del blog su di esso di nuovo un giorno.

Questo fix funziona universalmente e ha una profonda supporto di matrice, per esempio a.a[x][b.a]=10.Utilizza parse_str() dietro le quinte con alcuni pre-elaborazione.

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

E poi si può chiamare questa funzione come questa, a seconda della fonte:

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

Per PHP sotto 5.4: utilizzare base64_encode invece di bin2hex e base64_decode invece di hex2bin.

Questo accade a causa di un periodo di un carattere non valido nel nome di una variabile, il ragione per il quale si trova molto in profondità nella realizzazione di PHP, quindi non ci sono soluzioni semplici (di sicurezza).

Nel frattempo è possibile risolvere questo problema:

  1. Accedendo al grezzo dei dati di query tramite php://input per inviare i dati o $_SERVER['QUERY_STRING'] per OTTENERE i dati
  2. Utilizzando una funzione di conversione.

Il seguito di conversione di funzione (PHP >= 5.4) codifica i nomi di ogni coppia chiave-valore in una rappresentazione esadecimale e quindi esegue una regolare parse_str();una volta fatto, torna esadecimale nomi di tornare alla loro forma originale:

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

O:

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

Questo approccio è una versione modificata di Rok Kralj, ma con qualche ritocco per lavoro, per migliorare l'efficienza (evita inutili richiamate, la codifica e la decodifica su inalterate le chiavi) e per gestire correttamente chiavi dell'array.

Un gist con test è disponibile e qualsiasi feedback o suggerimenti sono i benvenuti qui o di là.

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

La ragione per cui questo accade è perché il PHP storico di register_globals funzionalità.L' .il carattere non è un carattere valido in nome di una variabile, in modo da PHP copritrici con un carattere di sottolineatura per assicurarsi che non c'è compatibilità.

In breve, non è una buona pratica per fare periodi variabili URL.

Se in cerca di qualsiasi modo per letteralmente PHP interrompere la sostituzione '.' personaggi $_GET o $_POST array, quindi un modo per farlo è quello di modificare il PHP origine (e in questo caso è relativamente semplice).

AVVISO:Modificare il PHP di origine C è un opzione avanzata!

Anche in questo PHP bug report che suggerisce la stessa modifica.

Per esplorare avrai bisogno di:

  • download PHP del codice sorgente in C
  • disabilitare il . sostituzione di controllo
  • ./configurare, fare e la distribuzione di compilazione personalizzato di PHP

La modifica sorgente di per sé è banale e richiede l'aggiornamento solo la metà di una linea in 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='_';
....

Nota:rispetto all'originale || *p == '.' è stato commentato


Esempio Di Output:

dato un QUERY_STRING di a.a[]=bb&a.a[]=BB&c%20c=dd, in esecuzione <?php print_r($_GET); ora produce:

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

    [c_c] => dd
)

Note:

  • questa patch risolve la domanda originale solo (si ferma sostituzione di punti, e non gli spazi).
  • in esecuzione su questa patch sarà più veloce di script a livello di soluzioni, ma quelli pure-.php le risposte sono ancora generalmente-preferibile (perché di evitare di cambiare il PHP stesso).
  • in teoria un polyfill tipo di approccio è possibile qui e di poter combinare approcci-test per il C-variazione di livello utilizzando parse_str() e (se disponibile) ritorno al più lento metodi.

La mia soluzione a questo problema è stata veloce e sporco, ma mi piace ancora.Ho semplicemente voluto pubblicare un elenco di nomi di file che sono stati controllati nel modulo.Ho usato base64_encode per codificare i nomi dei file all'interno del markup e poi decodificati con base64_decode prima di utilizzarli.

Dopo aver guardato Rok soluzione sono venuto con una versione che risolve le limitazioni nella mia risposta qui sotto, crb sopra e Rok è la soluzione.Vedere un la mia versione migliorata.


@crb risposta sopra è un buon inizio, ma ci sono un paio di problemi.

  • Riprocessa tutto ciò che è eccessivo;solo i campi che hanno un "." nel nome devono essere rielaborati.
  • Non riesce a gestire matrici nello stesso modo in cui nativa di PHP elaborazione, ad esempioper le chiavi come "pippo.bar[]".

La soluzione di seguito gli indirizzi di entrambi questi problemi ora (nota che è stata aggiornata poiché originariamente inviato).Questo è circa il 50% più veloce rispetto alla mia risposta precedente, nel mio test, ma non gestire le situazioni in cui i dati sono la stessa chiave (o una chiave che viene estratto lo stesso, ad esempiopippo.bar e foo_bar sono entrambi estratti come 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]);                                       
            }                                                                  
        }                                                                      
    }                                                                          
}                                                                              

Beh, la funzione che ho comprendono di seguito, "getRealPostArray()", non è una bella soluzione, ma gestisce le matrici e supporta entrambi i nomi:"alpha_beta" e "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>

considerando che var_dump($_POST) produce:

  '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 ()), produce:

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

La funzione, per quel che vale:

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

Utilizzando crb ho voluto ricreare l' $_POST array come, ma tenete a mente è necessario per garantire la codifica e la decodifica correttamente sia il client e il server.È importante capire che quando un personaggio è veramente non valido ed è veramente valido.Inoltre la gente dovrebbe ancora e sempre fuga di dati client prima di utilizzarlo con qualsiasi comando di database senza eccezione.

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

Mi consiglia di utilizzare questo solo per singoli casi solo, lì per lì non sono sicuro circa i punti negativi di questo mettere in cima alla vostra primario file di intestazione.

La mia soluzione attuale (basato sul precedente argomento risposte):

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']);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top