¿Hermosa manera de eliminar GET-variables con PHP?

92

Tengo una cadena con una URL completa que incluye variables GET. ¿Cuál es la mejor forma de eliminar las variables GET? ¿Existe una buena forma de eliminar solo uno de ellos?

Este es un código que funciona pero no es muy bonito (creo):

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

El código anterior simplemente elimina todas las variables GET. En mi caso, la URL se genera desde un CMS, por lo que no necesito ninguna información sobre las variables del servidor.

Jens Törnell
fuente
1
Me quedaría con lo que tienes a menos que el rendimiento no sea un problema. La solución de expresiones regulares proporcionada por Gumbo va a ser lo más bonita posible.
MitMaro
No es necesario que sea hermoso si va en functions.php o donde sea que oculte sus partes feas, solo necesitará ver qs_build () para llamarlo
Signo de interrogación
Aquí hay una forma de hacer esto a través de una buena función anónima. stackoverflow.com/questions/4937478/…
doublejosh
¿Qué tal el fragmento de URL? Las soluciones que veo a continuación también descartan el fragmento, tal como lo hace su código.
Marten Koetsier

Respuestas:

232

Ok, para eliminar todas las variables, quizás la más bonita sea

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

Vea strtokaquí .

Es el más rápido (ver más abajo) y maneja las URL sin un '?' correctamente.

Para tomar una url + cadena de consulta y eliminar solo una variable (sin usar un reemplazo de expresiones regulares, que puede ser más rápido en algunos casos), puede hacer 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;
}

Un reemplazo de expresiones regulares para eliminar una sola var podría verse así:

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

Aquí están los tiempos de algunos métodos diferentes, asegurando que el tiempo se reinicie entre ejecuciones.

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

muestra

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 gana y es, con mucho, el código más pequeño.

Justin
fuente
Ok, cambié de opinión. strtok way se ve aún mejor. Las otras funciones no funcionaron tan bien. Probé las funciones en estas variables get? Cbyear = 2013 & test = value y escribí echo removeqsvar ($ current_url, 'cbyear'); y obtuve el resultado: amperio; prueba = valor
Jens Törnell
ah, sí ... la expresión regular no está completa; tendrá que reemplazar el delimitador final y perder el principal (lo escribí a ciegas). Sin embargo, la función más larga debería funcionar bien. preg_replace ('/([?&])'.$ varname.' = [^ &] + (& | $) / ',' $ 1 ', $ url) debería funcionar
Justin
1
PHP 5.4 parece quejarse de @unset; curiosamente, no le gusta el símbolo @.
Artem Russakovskii
1
no es de extrañar, el operador @ (ocultar errores) es un poco malvado de todos modos, probablemente haya una mejor manera de hacerlo en PHP 5.4 ahora, pero no he estado escribiendo PHP durante casi 2 años, así que estoy un poco fuera de práctica.
Justin
strtok rocks, +1
FrancescoMM
33

Qué tal si:

preg_replace('/\\?.*/', '', $str)
Gumbo
fuente
1
Definitivamente más bonita. Sin embargo, me pregunto cuál funcionaría mejor. +1
MitMaro
Esto me salvó algunas filas y para mí esto es corto y hermoso. ¡Gracias!
Jens Törnell
5
Úselo /(\\?|&)the-var=.*?(&|$)/para eliminar solo una variable específica ( the-varaquí).
10

Si la URL de la que está intentando eliminar la cadena de consulta es la URL actual del script PHP, puede utilizar uno de los métodos mencionados anteriormente. Si solo tiene una variable de cadena con una URL y desea eliminar todo lo que pasa después del '?' tu puedes hacer:

$pos = strpos($url, "?");
$url = substr($url, 0, $pos);
Matt Bridges
fuente
+1 porque es la única otra respuesta aquí que responde a la pregunta y proporciona una alternativa.
MitMaro
2
Debe tener en cuenta que es posible que la URL no contenga un ?. Su código luego devolverá una cadena vacía.
Gumbo
Sí, para respaldar lo que dijo @Gumbo, cambiaría la segunda línea a:$url = ($pos)? substr($url, 0, $pos) : $url;
CenterOrbit
7

Inspirado por el comentario de @MitMaro, escribí un pequeño benchmark para probar la velocidad de las soluciones de @Gumbo, @Matt Bridges y @justin la propuesta en la pregunta:

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; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;
strtok: 0.12; explotar: 0.19; regexp: 0.31; strpos: 0.18;

Resultado: el strtok de @ justin es el más rápido.

Nota: probado en un sistema Debian Lenny local con Apache2 y PHP5.

Ardillas
fuente
tiempo de ejecución de regexp: 0.14591598510742 segundos; tiempo de ejecución de explosión: 0.07137393951416 segundos; tiempo de ejecución de strpos: 0.080883026123047 segundos; tiempo de ejecución de tok: 0.042459011077881 segundos;
Justin
¡Muy agradable! Creo que la velocidad es importante. No es lo único que va a pasar. Una aplicación web puede tener cientos de funciones. "Todo está en los detalles". ¡Gracias, vota!
Jens Törnell
Justin, gracias. El script ahora está limpio y tiene en cuenta su solución.
Scharrels
7

Otra solución ... Encuentro esta función más elegante, también eliminará el final '?' si la clave a eliminar es la única en la cadena 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;
}

Pruebas:

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

Saldrá:

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

»Ejecute estas pruebas en 3v4l

Bobina
fuente
3

¿No podrías usar las variables del servidor para hacer esto?

¿O funcionaría esto ?:

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

Solo un pensamiento.

bobert
fuente
2

Puede utilizar las variables de servidor para esto, por ejemplo $_SERVER['REQUEST_URI'], o incluso mejor: $_SERVER['PHP_SELF'].

Ardillas
fuente
4
Esto supone, por supuesto, que la URL que está analizando es la página que realiza el análisis.
MitMaro
2
@list($url) = explode("?", $url, 2);
Rob Haswell
fuente
0

¿Qué tal una función para reescribir la cadena de consulta recorriendo la matriz $ _GET?

! Esquema aproximado de una función adecuada

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 como esto sería bueno para tenerlo a mano para los enlaces de paginación, etc.

<a href="?p=3&<?= query_string_exclude(array('p')) ?>" title="Click for page 3">Page 3</a>
Signo de interrogación
fuente
0

basename($_SERVER['REQUEST_URI']) devuelve todo después e incluido el '?',

En mi código, a veces solo necesito secciones, así que sepárelo para poder obtener el valor de lo que necesito sobre la marcha. No estoy seguro de la velocidad de rendimiento en comparación con otros métodos, pero es realmente útil para mí.

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

En mi opinión, la mejor forma sería esta:

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

Comprueba si hay un parámetro GET 'i' y lo elimina si lo hay.

Joshua Anderson
fuente
0

simplemente use javascript echo'd para eliminar la URL de cualquier variable con un formulario en blanco de autoenvío:

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

Luego haz esta función de javascript:

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