Belle façon de supprimer les variables GET avec PHP?

92

J'ai une chaîne avec une URL complète comprenant des variables GET. Quelle est la meilleure façon de supprimer les variables GET? Existe-t-il un bon moyen d'en supprimer un seul?

C'est un code qui fonctionne mais qui n'est pas très beau (je pense):

$current_url = explode('?', $current_url);
echo $current_url[0];

Le code ci-dessus supprime simplement toutes les variables GET. L'URL est dans mon cas générée à partir d'un CMS, je n'ai donc pas besoin d'informations sur les variables du serveur.

Jens Törnell
la source
1
Je m'en tiendrai à ce que vous avez à moins que la performance ne soit pas un problème. La solution regex fournie par Gumbo sera aussi jolie que possible.
MitMaro
Il n'a pas besoin d'être beau si cela va dans functions.php ou partout où vous cachez vos vilains bits, vous n'aurez besoin que de voir qs_build () pour l'appeler
Question Mark
Voici un moyen de le faire via une belle fonction anonyme. stackoverflow.com/questions/4937478/…
doublejosh
Qu'en est-il du fragment d'url? Les solutions que je vois ci-dessous suppriment toutes le fragment, tout comme le fait votre code.
Marten Koetsier

Réponses:

232

Ok, pour supprimer toutes les variables, la plus jolie est peut-être

$url = strtok($url, '?');

Voyez strtokici .

C'est le plus rapide (voir ci-dessous), et gère les URL sans «?» correctement.

Pour prendre une URL + Querystring et supprimer une seule variable (sans utiliser de regex replace, ce qui peut être plus rapide dans certains cas), vous pouvez faire quelque chose comme:

function removeqsvar($url, $varname) {
    list($urlpart, $qspart) = array_pad(explode('?', $url), 2, '');
    parse_str($qspart, $qsvars);
    unset($qsvars[$varname]);
    $newqs = http_build_query($qsvars);
    return $urlpart . '?' . $newqs;
}

Une regex replace pour supprimer une seule var pourrait ressembler à ceci:

function removeqsvar($url, $varname) {
    return preg_replace('/([?&])'.$varname.'=[^&]+(&|$)/','$1',$url);
}

Voici les horaires de quelques méthodes différentes, garantissant que le chronométrage est réinitialisé entre les courses.

<?php

$number_of_tests = 40000;

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;

for($i = 0; $i < $number_of_tests; $i++){
    $str = "http://www.example.com?test=test";
    preg_replace('/\\?.*/', '', $str);
}
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "regexp execution time: ".$totaltime." seconds; ";

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;
for($i = 0; $i < $number_of_tests; $i++){
    $str = "http://www.example.com?test=test";
    $str = explode('?', $str);
}
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "explode execution time: ".$totaltime." seconds; ";

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;
for($i = 0; $i < $number_of_tests; $i++){
    $str = "http://www.example.com?test=test";
    $qPos = strpos($str, "?");
    $url_without_query_string = substr($str, 0, $qPos);
}
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "strpos execution time: ".$totaltime." seconds; ";

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;
for($i = 0; $i < $number_of_tests; $i++){
    $str = "http://www.example.com?test=test";
    $url_without_query_string = strtok($str, '?');
}
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "tok execution time: ".$totaltime." seconds; ";

spectacles

regexp execution time: 0.14604902267456 seconds; explode execution time: 0.068033933639526 seconds; strpos execution time: 0.064775943756104 seconds; tok execution time: 0.045819044113159 seconds; 
regexp execution time: 0.1408839225769 seconds; explode execution time: 0.06751012802124 seconds; strpos execution time: 0.064877986907959 seconds; tok execution time: 0.047760963439941 seconds; 
regexp execution time: 0.14162802696228 seconds; explode execution time: 0.065848112106323 seconds; strpos execution time: 0.064821004867554 seconds; tok execution time: 0.041788101196289 seconds; 
regexp execution time: 0.14043688774109 seconds; explode execution time: 0.066350221633911 seconds; strpos execution time: 0.066242933273315 seconds; tok execution time: 0.041517972946167 seconds; 
regexp execution time: 0.14228296279907 seconds; explode execution time: 0.06665301322937 seconds; strpos execution time: 0.063700199127197 seconds; tok execution time: 0.041836977005005 seconds; 

strtok gagne et est de loin le plus petit code.

Justin
la source
Ok, j'ai changé d'avis. La façon strtok est encore meilleure. Les autres fonctions ne fonctionnaient pas très bien. J'ai essayé les fonctions sur ces variables get? Cbyear = 2013 & test = value et j'ai écrit echo removeqsvar ($ current_url, 'cbyear'); et a obtenu le résultat: amp; test = value
Jens Törnell
ah ouais ... le regex n'est pas complet - il faudra remplacer le délimiteur de fin et manquer le premier (l'a écrit en aveugle). La fonction plus longue devrait toujours fonctionner correctement. preg_replace ('/([?& </font>)'.$ varname.' = [^ &] + (& | $) / ',' $ 1 ', $ url) devrait fonctionner
Justin
1
PHP 5.4 semble se plaindre de @unset - il n'aime pas le symbole @, curieusement.
Artem Russakovskii
1
pas étonnant - l'opérateur @ (masquer les erreurs) est en quelque sorte maléfique de toute façon - il y a probablement une meilleure façon de le faire en PHP 5.4 maintenant, mais je n'écris pas PHP depuis presque 2 ans maintenant, donc je suis un peu hors entraine toi.
Justin
strtok rocks, +1
FrancescoMM
33

Que diriez-vous:

preg_replace('/\\?.*/', '', $str)
Gombo
la source
1
Certainement plus joli. Je me demande cependant lequel serait le plus performant. +1
MitMaro
Cela m'a sauvé quelques rangées et pour moi c'est court et beau. Je vous remercie!
Jens Törnell
5
Utilisez /(\\?|&)the-var=.*?(&|$)/pour supprimer uniquement une variable spécifique ( the-varici).
10

Si l'URL dont vous essayez de supprimer la chaîne de requête est l'URL actuelle du script PHP, vous pouvez utiliser l'une des méthodes mentionnées précédemment. Si vous avez juste une variable de chaîne avec une URL et que vous souhaitez supprimer tout ce qui se trouve au-delà du «?» tu peux faire:

$pos = strpos($url, "?");
$url = substr($url, 0, $pos);
Ponts de Matt
la source
+1 parce que c'est la seule autre réponse ici qui répond à la question et offre une alternative.
MitMaro
2
Vous devez considérer que l'URL peut ne pas contenir de fichier ?. Votre code renverra alors une chaîne vide.
Gumbo
Ouais pour soutenir ce que @Gumbo a dit, je changerais la deuxième ligne en:$url = ($pos)? substr($url, 0, $pos) : $url;
CenterOrbit
7

Inspiré par le commentaire de @MitMaro, j'ai écrit un petit benchmark pour tester la vitesse des solutions de @Gumbo, @Matt Bridges et @justin la proposition dans la question:

function teststrtok($number_of_tests){
    for($i = 0; $i < $number_of_tests; $i++){
      $str = "http://www.example.com?test=test";
      $str = strtok($str,'?');
    }
}
function testexplode($number_of_tests){
    for($i = 0; $i < $number_of_tests; $i++){
      $str = "http://www.example.com?test=test";
      $str = explode('?', $str);
    }
}
function testregexp($number_of_tests){
    for($i = 0; $i < $number_of_tests; $i++){
      $str = "http://www.example.com?test=test";
      preg_replace('/\\?.*/', '', $str);
    }
}
function teststrpos($number_of_tests){
    for($i = 0; $i < $number_of_tests; $i++){
      $str = "http://www.example.com?test=test";
      $qPos = strpos($str, "?");
      $url_without_query_string = substr($str, 0, $qPos);
    }
}

$number_of_runs = 10;
for($runs = 0; $runs < $number_of_runs; $runs++){

  $number_of_tests = 40000;
  $functions = array("strtok", "explode", "regexp", "strpos");
  foreach($functions as $func){
    $starttime = microtime(true);
    call_user_func("test".$func, $number_of_tests);
    echo $func.": ". sprintf("%0.2f",microtime(true) - $starttime).";";
  }
  echo "<br />";
}
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;
strtok: 0,12; exploser: 0,19; expression rationnelle: 0,31; strpos: 0,18;

Résultat: le strtok de @ justin est le plus rapide.

Remarque: testé sur un système Debian Lenny local avec Apache2 et PHP5.

Scharrels
la source
temps d'exécution de l'expression régulière: 0,14591598510742 secondes; exploser le temps d'exécution: 0,07137393951416 secondes; temps d'exécution strpos: 0,080883026123047 secondes; temps d'exécution du tok: 0,042459011077881 secondes;
Justin
Très agréable! Je pense que la vitesse est importante. Ce n'est pas la seule chose qui va arriver. Une application Web peut avoir des centaines de fonctions. "Tout est dans les détails". Merci, votez!
Jens Törnell
Justin, merci. Le script est maintenant nettoyé et prend en compte votre solution.
Scharrels
7

Autre solution ... Je trouve cette fonction plus élégante, elle supprimera également le '?' si la clé à supprimer est la seule de la chaîne de requête.

/**
 * Remove a query string parameter from an URL.
 *
 * @param string $url
 * @param string $varname
 *
 * @return string
 */
function removeQueryStringParameter($url, $varname)
{
    $parsedUrl = parse_url($url);
    $query = array();

    if (isset($parsedUrl['query'])) {
        parse_str($parsedUrl['query'], $query);
        unset($query[$varname]);
    }

    $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';
    $query = !empty($query) ? '?'. http_build_query($query) : '';

    return $parsedUrl['scheme']. '://'. $parsedUrl['host']. $path. $query;
}

Tests:

$urls = array(
    'http://www.example.com?test=test',
    'http://www.example.com?bar=foo&test=test2&foo2=dooh',
    'http://www.example.com',
    'http://www.example.com?foo=bar',
    'http://www.example.com/test/no-empty-path/?foo=bar&test=test5',
    'https://www.example.com/test/test.test?test=test6',
);

foreach ($urls as $url) {
    echo $url. '<br/>';
    echo removeQueryStringParameter($url, 'test'). '<br/><br/>';
}

Sortira:

http://www.example.com?test=test
http://www.example.com

http://www.example.com?bar=foo&test=test2&foo2=dooh
http://www.example.com?bar=foo&foo2=dooh

http://www.example.com
http://www.example.com

http://www.example.com?foo=bar
http://www.example.com?foo=bar

http://www.example.com/test/no-empty-path/?foo=bar&test=test5
http://www.example.com/test/no-empty-path/?foo=bar

https://www.example.com/test/test.test?test=test6
https://www.example.com/test/test.test

»Exécutez ces tests sur 3v4l

Bobine
la source
3

N'avez-vous pas pu utiliser les variables de serveur pour ce faire?

Ou cela fonctionnerait-il?:

unset($_GET['page']);
$url = $_SERVER['SCRIPT_NAME'] ."?".http_build_query($_GET);

Juste une pensée.

Bobert
la source
2

Vous pouvez utiliser les variables du serveur pour cela, par exemple $_SERVER['REQUEST_URI'], ou encore mieux: $_SERVER['PHP_SELF'].

Scharrels
la source
4
Cela suppose bien sûr que l'url qu'il analyse est la page qui effectue l'analyse.
MitMaro
2
@list($url) = explode("?", $url, 2);
Rob Haswell
la source
0

Que diriez-vous d'une fonction pour réécrire la chaîne de requête en boucle sur le tableau $ _GET

! Aperçu approximatif d'une fonction appropriée

function query_string_exclude($exclude, $subject = $_GET, $array_prefix=''){
   $query_params = array;
   foreach($subject as $key=>$var){
      if(!in_array($key,$exclude)){
         if(is_array($var)){ //recursive call into sub array
            $query_params[]  = query_string_exclude($exclude, $var, $array_prefix.'['.$key.']');
         }else{
            $query_params[] = (!empty($array_prefix)?$array_prefix.'['.$key.']':$key).'='.$var;
         }
      }
   }

   return implode('&',$query_params);
}

Quelque chose comme ça serait bon à garder à portée de main pour les liens de pagination, etc.

<a href="?p=3&<?= query_string_exclude(array('p')) ?>" title="Click for page 3">Page 3</a>
Point d'interrogation
la source
0

basename($_SERVER['REQUEST_URI']) renvoie tout après et y compris le '?',

Dans mon code, je n'ai parfois besoin que de sections, alors séparez-les pour que je puisse obtenir la valeur de ce dont j'ai besoin à la volée. Je ne suis pas sûr de la vitesse de performance par rapport aux autres méthodes, mais c'est vraiment utile pour moi.

$urlprotocol = 'http'; if ($_SERVER["HTTPS"] == "on") {$urlprotocol .= "s";} $urlprotocol .= "://";
$urldomain = $_SERVER["SERVER_NAME"];
$urluri = $_SERVER['REQUEST_URI'];
$urlvars = basename($urluri);
$urlpath = str_replace($urlvars,"",$urluri);

$urlfull = $urlprotocol . $urldomain . $urlpath . $urlvars;
Sidupac
la source
0

À mon avis, la meilleure façon serait la suivante:

<? if(isset($_GET['i'])){unset($_GET['i']); header('location:/');} ?>

Il vérifie s'il existe un paramètre «i» GET et le supprime s'il y en a.

Joshua Anderson
la source
0

il suffit d'utiliser le javascript echo pour débarrasser l'URL de toutes les variables avec un formulaire vierge à soumission automatique:

    <?
    if (isset($_GET['your_var'])){
    //blah blah blah code
    echo "<script type='text/javascript'>unsetter();</script>"; 
    ?> 

Ensuite, faites cette fonction javascript:

    function unsetter() {
    $('<form id = "unset" name = "unset" METHOD="GET"><input type="submit"></form>').appendTo('body');
    $( "#unset" ).submit();
    }
Plan B
la source