90 votes

Faire en sorte que PHP cesse de remplacer les caractères '.' dans les tableaux $_GET ou $_POST ?

Si je passe des variables PHP avec . dans leur nom via $_GET PHP les remplace automatiquement par _ personnages. Par exemple :

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

... produit les résultats suivants :

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

... ma question est la suivante : existe-t-il cualquier comment je peux arrêter ça ? Je n'arrive pas à comprendre ce que j'ai fait pour mériter ça.

La version de PHP que j'utilise est 5.2.4-2ubuntu5.3.

6voto

El Yobo Points 7580

Cette approche est une version modifiée de celle de Rok Kralj, mais avec quelques modifications pour améliorer l'efficacité (évite les rappels inutiles, l'encodage et le décodage sur les clés non affectées) et pour gérer correctement les clés des tableaux.

A gist avec tests est disponible et tout commentaire ou suggestion est le bienvenu ici ou 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;                                              
        }                                                                      
    }                                                                          
}

4voto

Jeremy Privett Points 2678

La raison pour laquelle cela se produit est due à l'ancienne fonctionnalité register_globals de PHP. Le caractère . n'est pas un caractère valide dans un nom de variable, donc PHP le remplace par un trait de soulignement afin de s'assurer de la compatibilité.

En bref, ce n'est pas une bonne pratique de faire des périodes dans les variables URL.

3voto

humbletim Points 103

Si vous cherchez cualquier moyen de littéralement pour que PHP arrête de remplacer les caractères '.' dans les tableaux $_GET ou $_POST, il faut modifier les sources de PHP (et dans ce cas, c'est relativement simple).

AVERTISSEMENT : La modification des sources de PHP C est une option avancée !

Voir aussi ceci Rapport de bug PHP qui suggère la même modification.

Pour explorer, vous devrez :

  • télécharger Le code source C de PHP
  • désactiver le . contrôle de remplacement
  • ./configure , faire et déployer votre version personnalisée de PHP

Le changement de source lui-même est trivial et implique la mise à jour de seulement la moitié d'une ligne en 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 : par rapport à l'original || *p == '.' a été commenté


Exemple de sortie :

avec une QUERY_STRING de a.a[]=bb&a.a[]=BB&c%20c=dd , course à pied <?php print_r($_GET); produit maintenant :

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

    \[c\_c\] => dd
)

Notes :

_* ce correctif répond uniquement à la question initiale (il arrête le remplacement des points, pas des espaces).

  • s'exécutant sur ce patch sera plus rapide que les solutions de niveau script, mais ces réponses purement-.php sont encore généralement préférables (car elles évitent de modifier PHP lui-même)._* _en théorie, une approche polyfill est possible ici et pourrait combiner les approches -- tester le changement de niveau C en utilisant parse_str() et (si elles ne sont pas disponibles) se rabattre sur des méthodes plus lentes._

2voto

Jason Points 27

Ma solution à ce problème était rapide et sale, mais je l'aime toujours. Je voulais simplement afficher une liste des noms de fichiers qui ont été cochés sur le formulaire. J'ai utilisé base64_encode pour encoder les noms de fichiers dans le balisage et les décoder ensuite avec base64_decode avant de les utiliser.

2voto

El Yobo Points 7580

Après avoir examiné la solution de Rok, j'ai proposé une version qui tient compte des limitations de ma réponse ci-dessous, de celle de crb ci-dessus et de la solution de Rok également. Voir a ma version améliorée .


La réponse de @crb au-dessus de est un bon début, mais il y a quelques problèmes.

  • Il retraite tout, ce qui est excessif ; seuls les champs dont le nom comporte un "." doivent être retraités.
  • Il ne parvient pas à gérer les tableaux de la même manière que le traitement PHP natif, par exemple pour des clés comme "foo.bar[]".

La solution ci-dessous résout maintenant ces deux problèmes (notez qu'elle a été mise à jour depuis sa publication initiale). Elle est environ 50% plus rapide que ma réponse ci-dessus dans mes tests, mais elle ne gère pas les situations où les données ont la même clé (ou une clé qui est extraite de la même manière, par exemple foo.bar et foo_bar sont tous deux extraits comme 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]);                                       
            }                                                                  
        }                                                                      
    }                                                                          
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X