Bela maneira de remover variáveis ​​GET com PHP?

92

Eu tenho uma string com um URL completo, incluindo variáveis ​​GET. Qual é a melhor maneira de remover as variáveis ​​GET? Existe uma boa maneira de remover apenas um deles?

Este é um código que funciona, mas não é muito bonito (eu acho):

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

O código acima apenas remove todas as variáveis ​​GET. O URL é, no meu caso, gerado a partir de um CMS, então não preciso de nenhuma informação sobre as variáveis ​​do servidor.

Jens Törnell
fonte
1
Eu continuaria com o que você tem, a menos que o desempenho não seja um problema. A solução regex fornecida pela Gumbo será o mais bonita possível.
MitMaro
Não precisa ser bonito se estiver em functions.php ou onde quer que você esconda seus bits feios, você só precisará ver qs_build () para chamá-lo
Ponto de interrogação
Aqui está uma maneira de fazer isso por meio de uma boa função anônima. stackoverflow.com/questions/4937478/…
doublejosh
Que tal o fragmento de url? Todas as soluções que vejo abaixo descartam o fragmento, assim como seu código.
Marten Koetsier de

Respostas:

232

Ok, para remover todas as variáveis, talvez a mais bonita seja

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

Veja strtokaqui .

É o mais rápido (veja abaixo) e lida com urls sem um '?' devidamente.

Para pegar um url + querystring e remover apenas uma variável (sem usar uma substituição regex, que pode ser mais rápida em alguns casos), você pode fazer algo como:

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

Uma substituição regex para remover uma única var pode ter a seguinte aparência:

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

Aqui estão os tempos de alguns métodos diferentes, garantindo que o tempo seja reiniciado entre as corridas.

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

shows

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 vence e é de longe o menor código.

Justin
fonte
Ok, mudei de ideia. maneira strtok parece ainda melhor. As outras funções não funcionaram muito bem. Experimentei as funções nessas variáveis ​​get? Cbyear = 2013 & test = value e escrevi echo removeqsvar ($ current_url, 'cbyear'); e obtive o resultado: amp; test = value
Jens Törnell
ah sim ... a regex não está completa - ela precisará substituir o delimitador final e perder o delimitador principal (escrevi às cegas). A função mais longa ainda deve funcionar bem. preg_replace ('/([?&])'.$ varname.' = [^ &] + (& | $) / ',' $ 1 ', $ url) deve funcionar
Justin
1
PHP 5.4 parece reclamar do @unset - ele não gosta do símbolo @, estranhamente.
Artem Russakovskii
1
não é surpreendente - o operador @ (ocultar erros) é meio maléfico de qualquer maneira - provavelmente há uma maneira melhor de fazer isso no PHP 5.4 agora, mas eu não escrevo PHP há quase 2 anos, então estou um pouco fora do prática.
Justin
Strtok rocks, +1
FrancescoMM
33

E se:

preg_replace('/\\?.*/', '', $str)
quiabo
fonte
1
Definitivamente mais bonita. Eu me pergunto qual teria melhor desempenho. +1
MitMaro
Isso me salvou algumas linhas e para mim isso é curto e bonito. Obrigado!
Jens Törnell
5
Use /(\\?|&)the-var=.*?(&|$)/para remover apenas uma variável específica ( the-varaqui).
10

Se o URL do qual você está tentando remover a string de consulta for o URL atual do script PHP, você pode usar um dos métodos mencionados anteriormente. Se você tiver apenas uma variável de string com um URL e quiser retirar tudo após o '?' você pode fazer:

$pos = strpos($url, "?");
$url = substr($url, 0, $pos);
Matt Bridges
fonte
+1 porque é a única outra resposta aqui que responde à pergunta e fornece uma alternativa.
MitMaro
2
Você deve considerar que o URL não pode conter a ?. Seu código retornará uma string vazia.
Gumbo
Sim, para fazer o que @Gumbo disse, eu mudaria a segunda linha para:$url = ($pos)? substr($url, 0, $pos) : $url;
CenterOrbit
7

Inspirado pelo comentário de @MitMaro, escrevi um pequeno benchmark para testar a velocidade das soluções de @Gumbo, @Matt Bridges e @justin na proposta na questão:

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

Resultado: o strtok de @justin é o mais rápido.

Nota: testado em um sistema Debian Lenny local com Apache2 e PHP5.

Scharrels
fonte
tempo de execução do regexp: 0,14591598510742 segundos; tempo de execução da explosão: 0,07137393951416 segundos; tempo de execução strpos: 0,080883026123047 segundos; tempo de execução do tok: 0,042459011077881 segundos;
Justin
Muito agradável! Acho que a velocidade é importante. Não é a única coisa que vai acontecer. Um aplicativo da web pode ter centenas de funções. “Está tudo nos detalhes”. Obrigado, vote positivamente!
Jens Törnell
Justin, obrigado. O script agora está limpo e leva sua solução em consideração.
Scharrels
7

Outra solução ... Acho essa função mais elegante, ela também vai remover o '?' se a chave a ser removida for a única na string de consulta.

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

Testes:

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

Irá produzir:

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

»Execute esses testes em 3v4l

Bobina
fonte
3

Você não poderia usar as variáveis ​​do servidor para fazer isso?

Ou isso funcionaria ?:

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

Apenas um pensamento.

Bobert
fonte
2

Você pode usar as variáveis de servidor para isso, por exemplo $_SERVER['REQUEST_URI'], ou ainda melhor: $_SERVER['PHP_SELF'].

Scharrels
fonte
4
Isso pressupõe, é claro, que o url que ele está analisando é a página que está analisando.
MitMaro
2
@list($url) = explode("?", $url, 2);
Rob Haswell
fonte
0

Que tal uma função para reescrever a string de consulta, percorrendo o array $ _GET

! Esboço aproximado de uma função adequada

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

Algo assim seria bom para manter links de paginação, etc.

<a href="?p=3&<?= query_string_exclude(array('p')) ?>" title="Click for page 3">Page 3</a>
Ponto de interrogação
fonte
0

basename($_SERVER['REQUEST_URI']) retorna tudo após e incluindo o '?',

Às vezes, no meu código, preciso apenas de seções, então separe-as para que eu possa obter o valor de que preciso imediatamente. Não tenho certeza sobre a velocidade de desempenho em comparação com outros métodos, mas é muito útil para mim.

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

Na minha opinião, a melhor maneira seria esta:

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

Ele verifica se há um parâmetro 'i' GET e o remove se houver.

Joshua Anderson
fonte
0

basta usar javascript echo'd para livrar o URL de quaisquer variáveis ​​com um formulário em branco de auto-envio:

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

Em seguida, faça esta função javascript:

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