用PHP删除GET变量的漂亮方法?


92

我有一个带有完整URL的字符串,其中包括GET变量。删除GET变量的最佳方法是哪种?是否有一种删除其中一个的好方法?

这是一个有效的代码,但不是很漂亮(我认为):

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

上面的代码仅删除了所有GET变量。在我的情况下,URL是从CMS生成的,因此我不需要有关服务器变量的任何信息。


1
除非性能不是问题,否则我会坚持使用您所拥有的东西。Gumbo提供的regex解决方案将变得尽可能漂亮。
MitMaro

如果将它放到functions.php中,或者隐藏在任何丑陋的地方,它都不需要很漂亮,您只需要看qs_build()即可调用它
问号,2009年

这是通过不错的匿名函数实现此目的的方法。stackoverflow.com/questions/4937478/...
doublejosh

网址片段如何?我在下面看到的解决方案也像代码一样,也丢弃了该片段。
Marten Koetsier

Answers:


232

好吧,要删除所有变量,也许最漂亮的是

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

请看strtok这里

它是最快的(请参见下文),并且处理不带“?”的网址 正确地。

要采用url + querystring并仅删除一个变量(不使用regex替换,在某些情况下可能会更快),您可以执行以下操作:

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

用正则表达式替换来删除单个var可能看起来像:

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

以下是几种不同方法的计时,以确保在运行之间重置计时。

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

表演

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获胜,并且是迄今为止最小的代码。


好吧,我改变了主意。strtok的方式看起来更好。其他功能效果不佳。我尝试了这些获取变量?cbyear = 2013&test = value的函数,并写了echo removeqsvar($ current_url,'cbyear'); 并得到结果:amp; test = value
JensTörnell'09

嗯,是的。正则表达式不完整-它需要替换尾随的定界符并错过前导定界符(将其盲写)。较长的功能应该仍然可以正常工作。preg_replace('/([[?&])'.$ varname。'= [^&] +(&| $)/','$ 1',$ url)应该可以正常工作
-Justin

1
PHP 5.4似乎在抱怨@unset-奇怪的是,它不喜欢@符号。
Artem Russakovskii 2014年

1
不足为奇-@运算符(隐藏错误)还是很邪恶的-现在可能在PHP 5.4中有一种更好的方法,但是我已经有将近两年没有写PHP了,所以我有点过时了实践。
贾斯汀

strtok岩石,+ 1
FrancescoMM


10

如果您要从中删除查询字符串的URL是PHP脚本的当前URL,则可以使用前面提到的方法之一。如果您只有一个带有URL的字符串变量,并且想删除所有'?'之后的内容 你可以做:

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

+1是因为它是这里唯一回答问题并提供替代方案的其他答案。
MitMaro

2
您应该考虑到URL可能不包含?。然后,您的代码将返回一个空字符串。
Gumbo

是的,支持@Gumbo所说的,我将第二行更改为:$url = ($pos)? substr($url, 0, $pos) : $url;
CenterOrbit

7

受@MitMaro的评论启发,我编写了一个小型基准测试@ Gumbo,@ Matt Bridges和@justin问题中的提案的解决方案速度:

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

结果:@justin的strtok最快。

注意:在使用Apache2和PHP5的本地Debian Lenny系统上进行了测试。


正则表达式执行时间:0.14591598510742秒; 爆炸执行时间:0.07137393951416秒;strpos执行时间:0.080883026123047秒;Tok执行时间:0.042459011077881秒;
贾斯汀2009年

非常好!我认为速度很重要。这不是唯一会发生的事情。Web应用程序可能具有数百个功能。“一切都在细节中”。谢谢,投票!
延斯·托内尔09年

贾斯汀,谢谢。现在,脚本已清理完毕,并考虑了您的解决方案。
Scharrels

7

另一个解决方案...我发现此功能更优雅,它还会删除结尾的“?” 如果要删除的键是查询字符串中的唯一键。

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

测试:

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

将输出:

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

»在3v4l上运行这些测试


3

您不能使用服务器变量来执行此操作吗?

还是行得通?:

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

只是一个想法。


2

您可以使用服务器变量对于这一点,例如$_SERVER['REQUEST_URI'],甚至更好:$_SERVER['PHP_SELF']


4
当然,这假设他正在解析的url是进行解析的页面。
MitMaro


0

如何通过遍历$ _GET数组重写查询字符串的函数

!合适功能的大致轮廓

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

这样的事情对于分页链接等来说很方便。

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

0

basename($_SERVER['REQUEST_URI']) 返回“?”之后的所有内容,包括“?”,

有时在我的代码中,我只需要几个部分,因此将其分开,这样我就可以即时获得所需的价值。不确定与其他方法相比的性能速度,但这对我来说真的很有用。

$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

只需使用echo'd javascript以自提交的空白格式删除所有变量的URL:

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

然后使这个JavaScript函数:

    function unsetter() {
    $('<form id = "unset" name = "unset" METHOD="GET"><input type="submit"></form>').appendTo('body');
    $( "#unset" ).submit();
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.