Schöne Möglichkeit, GET-Variablen mit PHP zu entfernen?

92

Ich habe eine Zeichenfolge mit einer vollständigen URL einschließlich GET-Variablen. Wie lassen sich die GET-Variablen am besten entfernen? Gibt es eine gute Möglichkeit, nur einen davon zu entfernen?

Dies ist ein Code, der funktioniert, aber nicht sehr schön ist (glaube ich):

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

Der obige Code entfernt nur alle GET-Variablen. Die URL wird in meinem Fall von einem CMS generiert, sodass ich keine Informationen zu Servervariablen benötige.

Jens Törnell
quelle
1
Ich würde bei dem bleiben, was Sie haben, es sei denn, die Leistung ist kein Problem. Die von Gumbo gelieferte Regex-Lösung wird so hübsch wie möglich sein.
MitMaro
Es muss nicht schön sein, wenn es in functions.php läuft oder wo immer Sie Ihre hässlichen Teile verstecken, müssen Sie nur qs_build () sehen, um es aufzurufen
Fragezeichen
Hier ist eine Möglichkeit, dies über eine nette anonyme Funktion zu tun. stackoverflow.com/questions/4937478/…
doublejosh
Wie wäre es mit dem URL-Fragment? Die Lösungen, die ich unten sehe, verwerfen das Fragment ebenso wie Ihr Code.
Marten Koetsier

Antworten:

230

Ok, um alle Variablen zu entfernen, ist vielleicht die schönste

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

Sehen Sie strtokhier ungefähr .

Es ist das schnellste (siehe unten) und verarbeitet URLs ohne '?' richtig.

Um einen URL + Querystring zu verwenden und nur eine Variable zu entfernen (ohne einen regulären Ausdruck zu verwenden, der in einigen Fällen schneller sein kann), können Sie Folgendes tun:

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

Ein Regex-Ersatz zum Entfernen einer einzelnen Variable könnte folgendermaßen aussehen:

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

Hier sind die Timings einiger verschiedener Methoden, um sicherzustellen, dass das Timing zwischen den Läufen zurückgesetzt wird.

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

zeigt an

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 gewinnt und ist mit Abstand der kleinste Code.

Justin
quelle
Ok, ich habe es mir anders überlegt. strtok way sieht noch besser aus. Die anderen Funktionen funktionierten nicht so gut. Ich habe die Funktionen für diese get-Variablen ausprobiert? Cbyear = 2013 & test = value und habe echo removeqsvar ($ current_url, 'cbyear') geschrieben. und bekam das Ergebnis: amp; test = value
Jens Törnell
ah yeah ... der reguläre Ausdruck ist nicht vollständig - er muss das nachfolgende Trennzeichen ersetzen und das führende verfehlen (hat es blind geschrieben). Die längere Funktion sollte trotzdem gut funktionieren. preg_replace ('/([?&‹)'.$ varname.' = [^ &] + (& | $) / ',' $ 1 ', $ url) sollte funktionieren
Justin
1
PHP 5.4 scheint sich über @unset zu beschweren - seltsamerweise mag es das @ -Symbol nicht.
Artem Russakovskii
1
Kein Wunder - der @ -Operator (Fehler ausblenden) ist sowieso irgendwie böse - es gibt wahrscheinlich eine bessere Möglichkeit, dies in PHP 5.4 zu tun, aber ich habe PHP seit fast 2 Jahren nicht mehr geschrieben, also bin ich ein bisschen aus trainieren.
Justin
Strtok Rocks, +1
FrancescoMM
33

Wie wäre es mit:

preg_replace('/\\?.*/', '', $str)
Gumbo
quelle
1
Auf jeden Fall schöner. Ich frage mich, welches besser abschneiden würde. +1
MitMaro
Das hat mir ein paar Zeilen erspart und für mich ist das kurz und schön. Danke dir!
Jens Törnell
5
Verwenden Sie /(\\?|&)the-var=.*?(&|$)/diese Option , um nur eine bestimmte Variable zu entfernen ( the-varhier).
10

Wenn die URL, von der Sie die Abfragezeichenfolge entfernen möchten, die aktuelle URL des PHP-Skripts ist, können Sie eine der zuvor genannten Methoden verwenden. Wenn Sie nur eine Zeichenfolgenvariable mit einer URL haben und alles nach dem '?' du kannst tun:

$pos = strpos($url, "?");
$url = substr($url, 0, $pos);
Matt Bridges
quelle
+1, weil dies die einzige andere Antwort ist, die die Frage beantwortet und eine Alternative bietet.
MitMaro
2
Sie sollten berücksichtigen, dass die URL möglicherweise kein a enthält ?. Ihr Code gibt dann eine leere Zeichenfolge zurück.
Gumbo
Ja, um zu unterstützen, was @Gumbo gesagt hat, würde ich die zweite Zeile ändern in:$url = ($pos)? substr($url, 0, $pos) : $url;
CenterOrbit
7

Inspiriert von dem Kommentar von @MitMaro schrieb ich einen kleinen Benchmark, um die Lösungsgeschwindigkeit von @Gumbo, @Matt Bridges und @justin des Vorschlags in der Frage zu testen:

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; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;
strtok: 0,12; explodieren: 0,19; regulärer Ausdruck: 0,31; strpos: 0,18;

Ergebnis: @ justins strtok ist der schnellste.

Hinweis: Auf einem lokalen Debian Lenny-System mit Apache2 und PHP5 getestet.

Scharrels
quelle
Regexp-Ausführungszeit: 0,14591598510742 Sekunden; Explosionsausführungszeit: 0,07137393951416 Sekunden; Ausführungszeit von strpos: 0,080883026123047 Sekunden; Ausführungszeit des Tokens: 0,042459011077881 Sekunden;
Justin
Sehr schön! Ich denke, Geschwindigkeit ist wichtig. Es ist nicht das einzige, was passieren wird. Eine Webanwendung kann Hunderte von Funktionen haben. "Es steckt alles im Detail". Danke, stimme ab!
Jens Törnell
Justin, danke. Das Skript wird jetzt bereinigt und berücksichtigt Ihre Lösung.
Scharrels
7

Eine andere Lösung ... Ich finde diese Funktion eleganter, sie entfernt auch das nachfolgende '?' wenn der zu entfernende Schlüssel der einzige in der Abfragezeichenfolge ist.

/**
 * 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/>';
}

Wird ausgegeben:

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

»Führen Sie diese Tests auf 3v4l durch

Spule
quelle
3

Könnten Sie dazu nicht die Servervariablen verwenden?

Oder würde das funktionieren?:

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

Nur ein Gedanke.

bobert
quelle
2

Sie können die Verwendung Servervariablen für diese, zum Beispiel $_SERVER['REQUEST_URI'], oder noch besser: $_SERVER['PHP_SELF'].

Scharrels
quelle
4
Dies setzt natürlich voraus, dass die URL, die er analysiert, die Seite ist, auf der die Analyse durchgeführt wird.
MitMaro
2
@list($url) = explode("?", $url, 2);
Rob Haswell
quelle
0

Wie wäre es mit einer Funktion zum Umschreiben der Abfragezeichenfolge durch Durchlaufen des Arrays $ _GET

! Grobe Darstellung einer geeigneten Funktion

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

So etwas wäre gut, um es für Paginierungslinks usw. griffbereit zu halten.

<a href="?p=3&<?= query_string_exclude(array('p')) ?>" title="Click for page 3">Page 3</a>
Fragezeichen
quelle
0

basename($_SERVER['REQUEST_URI']) gibt alles nach und einschließlich des '?' zurück,

In meinem Code brauche ich manchmal nur Abschnitte, also trennen Sie ihn heraus, damit ich den Wert dessen, was ich brauche, im laufenden Betrieb erhalten kann. Ich bin mir nicht sicher, wie schnell die Leistung im Vergleich zu anderen Methoden ist, aber es ist wirklich nützlich für mich.

$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
quelle
0

Meiner Meinung nach wäre der beste Weg:

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

Es prüft, ob es einen 'i'-GET-Parameter gibt, und entfernt ihn, falls vorhanden.

Joshua Anderson
quelle
0

Verwenden Sie einfach echo'd Javascript, um die URL von Variablen mit einem selbst übermittelnden, leeren Formular zu entfernen:

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

Dann machen Sie diese Javascript-Funktion:

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