web-dev-qa-db-fra.com

Comment obtenir plusieurs paramètres avec le même nom à partir d'une URL dans PHP

J'ai une application PHP qui devra parfois gérer des URL où plus d'un paramètre dans l'URL aura le même nom. Existe-t-il un moyen simple de récupérer toutes les valeurs d'une clé donnée ? PHP $ _GET renvoie uniquement la dernière valeur.

Pour rendre cela concret, mon application est un résolveur OpenURL, et peut obtenir des paramètres URL comme celui-ci:

ctx_ver=Z39.88-2004
&rft_id=info:oclcnum/1903126
&rft_id=http://www.biodiversitylibrary.org/bibliography/4323
&rft_val_fmt=info:ofi/fmt:kev:mtx:book
&rft.genre=book
&rft.btitle=At last: a Christmas in the West Indies. 
&rft.place=London,
&rft.pub=Macmillan and co.,
&rft.aufirst=Charles
&rft.aulast=Kingsley
&rft.au=Kingsley, Charles,
&rft.pages=1-352
&rft.tpages=352
&rft.date=1871

(Oui, je sais que c'est moche, bienvenue dans mon monde). Notez que la clé "rft_id" apparaît deux fois:

  1. rft_id=info:oclcnum/1903126
  2. rft_id=http://www.biodiversitylibrary.org/bibliography/4323

$_GET renverra juste http://www.biodiversitylibrary.org/bibliography/4323, la valeur précédente (info:oclcnum/1903126) ayant été écrasé.

J'aimerais avoir accès aux deux valeurs. Est-ce possible en PHP? Sinon, des réflexions sur la façon de gérer ce problème?

43
rdmpage

Quelque chose comme:

$query  = explode('&', $_SERVER['QUERY_STRING']);
$params = array();

foreach( $query as $param )
{
  // prevent notice on explode() if $param has no '='
  if (strpos($param, '=') === false) $param += '=';

  list($name, $value) = explode('=', $param, 2);
  $params[urldecode($name)][] = urldecode($value);
}

vous donne:

array(
  'ctx_ver'     => array('Z39.88-2004'),
  'rft_id'      => array('info:oclcnum/1903126', 'http://www.biodiversitylibrary.org/bibliography/4323'),
  'rft_val_fmt' => array('info:ofi/fmt:kev:mtx:book'),
  'rft.genre'   => array('book'),
  'rft.btitle'  => array('At last: a Christmas in the West Indies.'),
  'rft.place'   => array('London'),
  'rft.pub'     => array('Macmillan and co.'),
  'rft.aufirst' => array('Charles'),
  'rft.aulast'  => array('Kingsley'),
  'rft.au'      => array('Kingsley, Charles'),
  'rft.pages'   => array('1-352'),
  'rft.tpages'  => array('352'),
  'rft.date'    => array('1871')
)

Puisqu'il est toujours possible qu'un paramètre d'URL soit répété, il est préférable de toujours avoir des tableaux, au lieu de seulement pour les paramètres où vous les anticipez.

65
Tomalak

Ne fonctionnera pas pour vous car il semble que vous ne contrôliez pas la chaîne de requête, mais une autre réponse valide: au lieu d'analyser la chaîne de requête, vous pouvez afficher et '[]' à la fin du nom, puis PHP fera un tableau des éléments.

C'EST À DIRE:

someurl.php?name[]=aaa&name[]=bbb

vous donnera un $ _GET ressemblant à:

array(0=>'aaa', 1=>'bbb')
38
benlumley

Je pense qu'il faudrait analyser $_SERVER['QUERY_STRING'] manuellement.

Quelque chose comme (non testé):

$query = $_SERVER['QUERY_STRING'];
$vars = array();
foreach (explode('&', $query) as $pair) {
    list($key, $value) = explode('=', $pair);
    $vars[] = array(urldecode($key), urldecode($value));
}

Cela devrait vous donner un tableau $vars:

array(
    array('ctx_ver'     => 'Z39.88-2004'),
    array('rft_id'      => 'info:oclcnum/1903126'),
    array('rft_id'      => 'http://www.biodiversitylibrary.org/bibliography/4323'),
    array('rft_val_fmt' => 'info:ofi/fmt:kev:mtx:book'),
    array('rft.genre'   => 'book'),
    array('rft.btitle'  => 'At last: a Christmas in the West Indies.'),
    array('rft.place'   => 'London'),
    array('rft.pub'     => 'Macmillan and co.'),
    array('rft.aufirst' => 'Charles'),
    array('rft.aulast'  => 'Kingsley'),
    array('rft.au'      => 'Kingsley, Charles'),
    array('rft.pages'   => '1-352'),
    array('rft.tpages'  => '352'),
    array('rft.date'    => '1871')
)

Après avoir vu Tomalak's réponse, j'aime beaucoup mieux son format de données pour le tableau résultant, car il permet d'accéder à des clés spécifiques par leur nom.

10
Stefan Gehrig

Il n'est pas nécessaire d'utiliser des solutions de contournement explode stupides pour cela. Une simple expression régulière peut plus facilement rectifier un QUERY_STRING avec plusieurs paramètres de même nom:

// Replace `&x=1&x=2` into `x[]=1&x[]=2`
$qs = preg_replace("/(?<=^|&)(\w+)(?==)/", "$1[]", $_SERVER["QUERY_STRING"]);

C'est aussi simple que d'utiliser parse_str :

parse_str($qs, $new_GET);

Ce qui a l'avantage de décoder correctement %xy L'URL s'échappe immédiatement.

Si vous souhaitez simplement extraire un ou plusieurs paramètres spécifiques sous forme de tableau, utilisez (id|name) au lieu de (\w+) dans l'expression régulière.

6
mario

AFAIK il n'y a aucun moyen d'obtenir des valeurs en double en utilisant $_GET car la deuxième valeur écrasera la première

Pour le contourner, vous pouvez accéder à la chaîne de requête brute à l'aide de $_SERVER['QUERY_STRING'] puis analysez-le vous-même.

3
Neil Aitken

Supposons que vous ayez une chaîne de requête comme celle-ci:

param1 = 2549 & appname = appName1 & appname = appName2 & appname = appName3 & appname = appName4 & appname = appName5 & apptype = thetype & idsess = 1231324567980147dzeze55sd4 & action = myaction

Tu peux le faire :

public static function getMultipleParameters()
    {
        $query = $_SERVER['QUERY_STRING'];
        $vars = array();
        $second = array();
        foreach (explode('&', $query) as $pair) {
            list($key, $value) = explode('=', $pair);
            if('' == trim($value)){
                continue;
            }

            if (array_key_exists($key, $vars)) {
                if (!array_key_exists($key, $second))
                    $second[$key][] .= $vars[$key];
                $second[$key][] = $value;
            } else {
                $vars[$key] = urldecode($value);
            }
        }
        return array_merge($vars, $second);
    }

Ça donne :

array (
  'param1' => '2549',
  'appname' => 
      array (
        0 => 'appName1',
        1 => 'appName2',
        2 => 'appName3',
        3 => 'appName4',
        4 => 'appName5',
  ),
  'apptype' => 'thetype',
  'idsess' => '1231324567980147dzeze55sd4',
  'action' => 'myaction',
);

J'espère que cela pourra aider ;)

2
MonsterDev

Partager ma version de cette fonction

function parse_mstr($query_string,&$query=array()){
    $query = $query? $query: array();
    $params  = explode('&', $query_string);
    foreach( $params as $param ){
        $k = $param;
        $v = '';
        if(strpos($param,'=')){
            list($name, $value) = explode('=', $param);
            $k = rawurldecode($name);
            $v = rawurldecode($value);
        }
        if(array_key_exists($k, $query)){
            if(is_array($query[$k])){
                $query[$k][] = $v;
            }else{
                $query[$k] = array($query[$k],$v);
            }
        }else{
            $query[$k] = $v;
        }
    }
}

// usage
parse_mstr('a=1&a=2&b=3', $arr);

// resulting array
$arr = [
    'a' => ['1', '2'],
    'b' => '3'
]
2
Timo Huovinen