Piękny sposób na usunięcie zmiennych GET za pomocą PHP?


94

Mam ciąg z pełnym adresem URL zawierającym zmienne GET. Jaki jest najlepszy sposób na usunięcie zmiennych GET? Czy jest dobry sposób na usunięcie tylko jednego z nich?

To jest kod, który działa, ale nie jest zbyt piękny (myślę):

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

Powyższy kod po prostu usuwa wszystkie zmienne GET. Adres URL jest w moim przypadku generowany z CMS, więc nie potrzebuję żadnych informacji o zmiennych serwerowych.


1
Trzymałbym się tego, co masz, chyba że wydajność nie jest problemem. Rozwiązanie regex dostarczone przez Gumbo będzie tak ładne, jak to tylko możliwe.
MitMaro

Nie musi być piękny, jeśli idzie w functions.php lub gdziekolwiek ukryjesz swoje brzydkie fragmenty, wystarczy zobaczyć qs_build (), aby to nazwać
znak zapytania

Oto sposób na zrobienie tego za pomocą ładnej anonimowej funkcji. stackoverflow.com/questions/4937478/…
doublejosh

A co z fragmentem adresu URL? Rozwiązania, które widzę poniżej, również odrzucają fragment, tak jak robi to twój kod.
Marten Koetsier

Odpowiedzi:


236

Ok, żeby usunąć wszystkie zmienne, może najładniejsza jest

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

Zobacz strtoktutaj .

Jest najszybszy (patrz poniżej) i obsługuje adresy URL bez znaku „?” prawidłowo.

Aby wziąć adres URL + querystring i usunąć tylko jedną zmienną (bez użycia zamiany wyrażenia regularnego, co może być szybsze w niektórych przypadkach), możesz zrobić coś takiego:

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

Zastąpienie wyrażenia regularnego w celu usunięcia pojedynczej zmiennej może wyglądać następująco:

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

Oto czasy kilku różnych metod, zapewniające resetowanie czasu między uruchomieniami.

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

przedstawia

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 wygrywa i jest zdecydowanie najmniejszym kodem.


Ok, zmieniłem zdanie. Strtok wygląda jeszcze lepiej. Inne funkcje nie działały tak dobrze. Wypróbowałem funkcje na tych zmiennych get? Cbyear = 2013 & test = value i napisałem echo removeqsvar ($ current_url, 'cbyear'); i otrzymałem wynik: amp; test = wartość
Jens Törnell

ach tak ... wyrażenie regularne nie jest kompletne - będzie musiało zastąpić końcowy separator i pomijać wiodący (napisane na ślepo). Jednak dłuższa funkcja powinna nadal działać dobrze. preg_replace ('/([?&])'.$ varname.' = [^ &] + (& | $) / ',' $ 1 ', $ url) powinno działać
Justin

1
PHP 5.4 wydaje się narzekać na @unset - dziwnie nie lubi symbolu @.
Artem Russakovskii

1
nic dziwnego - operator @ (ukryj błędy) i tak jest w pewnym sensie zły - prawdopodobnie jest teraz lepszy sposób na zrobienie tego w PHP 5.4, ale nie piszę PHP od prawie 2 lat, więc trochę mi się skończyło ćwiczyć.
Justin,

strtok rocks, +1
FrancescoMM

33

Co powiesz na:

preg_replace('/\\?.*/', '', $str)

1
Zdecydowanie ładniejsza. Zastanawiam się jednak, który z nich działałby lepiej. +1
MitMaro

Zaoszczędziło mi to kilka rzędów i dla mnie jest to krótkie i piękne. Dziękuję Ci!
Jens Törnell

5
Służy /(\\?|&)the-var=.*?(&|$)/do usuwania tylko określonej zmiennej ( the-vartutaj).

10

Jeśli adres URL, z którego próbujesz usunąć ciąg zapytania, jest bieżącym adresem URL skryptu PHP, możesz użyć jednej z wcześniej wspomnianych metod. Jeśli masz tylko zmienną łańcuchową z adresem URL i chcesz usunąć wszystko poza znakiem „?” możesz to zrobić:

$pos = strpos($url, "?");
$url = substr($url, 0, $pos);

+1, ponieważ jest to jedyna inna odpowiedź, która odpowiada na pytanie i stanowi alternatywę.
MitMaro

2
Należy wziąć pod uwagę, że adres URL może nie zawierać rozszerzenia ?. Twój kod zwróci wtedy pusty ciąg.
Gumbo

Tak, aby cofnąć to, co powiedział @Gumbo, zmieniłbym drugą linię na:$url = ($pos)? substr($url, 0, $pos) : $url;
CenterOrbit

7

Zainspirowany komentarzem @MitMaro napisałem mały benchmark do testowania szybkości rozwiązań @Gumbo, @Matt Bridges i @justin propozycja w pytaniu:

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; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;
strtok: 0,12; eksplodować: 0,19; regexp: 0,31; strpos: 0,18;

Wynik: strtok @ justina jest najszybszy.

Uwaga: przetestowano na lokalnym systemie Debian Lenny z Apache2 i PHP5.


czas wykonania wyrażenia regularnego: 0,14591598510742 sekundy; czas wykonania eksplozji: 0,07137393951416 sekund; czas wykonania strpos: 0,080883026123047 sekund; czas wykonania tokena: 0,042459011077881 sekund;
Justin

Bardzo dobrze! Myślę, że szybkość jest ważna. To nie jedyna rzecz, która się wydarzy. Aplikacja internetowa może mieć setki funkcji. „Wszystko tkwi w szczegółach”. Dzięki, zagłosuj!
Jens Törnell

Justin, dzięki. Skrypt jest teraz czyszczony i uwzględnia Twoje rozwiązanie.
Scharrels

7

Inne rozwiązanie ... Uważam, że ta funkcja jest bardziej elegancka, usunie również końcowe „?” jeśli klucz do usunięcia jest jedynym kluczem w ciągu zapytania.

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

Testy:

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

Wyświetli:

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

»Przeprowadź te testy na 3v4l


3

Czy nie mógłbyś użyć do tego zmiennych serwera?

A może to zadziała ?:

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

Tylko myśl.


2

Można użyć zmiennych serwera za to, na przykład $_SERVER['REQUEST_URI'], albo nawet lepiej: $_SERVER['PHP_SELF'].


4
Zakłada się oczywiście, że adres URL, który analizuje, jest stroną wykonującą parsowanie.
MitMaro


0

Co powiesz na funkcję, która przepisuje ciąg zapytania przez zapętlenie tablicy $ _GET

! Zgrubny zarys odpowiedniej funkcji

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

Coś takiego przydałoby się w przypadku linków do paginacji itp.

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

0

basename($_SERVER['REQUEST_URI']) zwraca wszystko po znaku „?” i łącznie z nim,

W moim kodzie czasami potrzebuję tylko sekcji, więc oddziel go, aby uzyskać wartość tego, czego potrzebuję w locie. Nie jestem pewien szybkości działania w porównaniu z innymi metodami, ale jest to dla mnie naprawdę przydatne.

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

0

Moim zdaniem najlepszym sposobem byłoby to:

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

Sprawdza, czy istnieje parametr GET „i” i usuwa go, jeśli istnieje.


0

po prostu użyj wyrażonego echo javascript, aby usunąć z adresu URL dowolne zmienne za pomocą samoskładającego się, pustego formularza:

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

Następnie wykonaj tę funkcję javascript:

    function unsetter() {
    $('<form id = "unset" name = "unset" METHOD="GET"><input type="submit"></form>').appendTo('body');
    $( "#unset" ).submit();
    }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.