【问题标题】:Beautiful way to remove GET-variables with PHP?用 PHP 删除 GET 变量的好方法?
【发布时间】:2010-11-18 02:31:16
【问题描述】:

我有一个包含 GET 变量的完整 URL 字符串。删除 GET 变量的最佳方法是什么?有什么好方法可以只删除其中一个吗?

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

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

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

【问题讨论】:

  • 我会坚持你所拥有的,除非性能不是问题。 Gumbo 提供的正则表达式解决方案将尽可能漂亮。
  • 它不需要很漂亮,如果它在functions.php中或者任何你隐藏你丑陋的地方,你只需要看到qs_build()来调用它
  • 这是一种通过一个不错的匿名函数来实现此目的的方法。 stackoverflow.com/questions/4937478/…
  • url片段怎么样?我在下面看到的解决方案也都丢弃了片段,就像您的代码一样。

标签: php url variables get


【解决方案1】:

好吧,去掉所有变量,也许最漂亮的是

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

查看strtok here

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

要获取 url+querystring 并仅删除一个变量(不使用正则表达式替换,在某些情况下可能更快),您可以执行以下操作:

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
  • 啊,是的......正则表达式不完整 - 它需要替换尾随分隔符并错过前导分隔符(盲写)。不过,较长的功能应该仍然可以正常工作。 preg_replace('/([?&])'.$varname.'=[^&]+(&|$)/','$1',$url) 应该可以工作
  • PHP 5.4 似乎在抱怨 @unset - 奇怪的是它不喜欢 @ 符号。
  • 并不奇怪 - @ 运算符(隐藏错误)无论如何都是邪恶的 - 现在在 PHP 5.4 中可能有更好的方法,但我已经快 2 年没有写 PHP了所以我有点不习惯。
  • strtok 岩石,+1
【解决方案2】:

怎么样:

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

【讨论】:

  • 绝对更漂亮。我想知道哪一个会表现得更好。 +1
  • 这为我节省了几行,对我来说这又短又漂亮。谢谢!
  • 使用/(\\?|&amp;)the-var=.*?(&amp;|$)/ 仅删除特定变量(此处为the-var)。
【解决方案3】:

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

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

【讨论】:

  • +1,因为它是这里唯一回答问题并提供替代方案的其他答案。
  • 您应该考虑到 URL 可能不包含 ?。然后您的代码将返回一个空字符串。
  • 是的,支持@Gumbo 所说的,我会将第二行更改为:$url = ($pos)? substr($url, 0, $pos) : $url;
【解决方案4】:

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

结果:@justin 的 strtok 是最快的。

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

【讨论】:

  • 正则表达式执行时间:0.14591598510742秒;爆炸执行时间:0.07137393951416 秒; strpos 执行时间:0.080883026123047 秒; tok执行时间:0.042459011077881秒;
  • 非常好!我认为速度很重要。这不是唯一会发生的事情。一个 Web 应用程序可能有数百个功能。 “一切尽在细节之中”。谢谢,投票!
  • 贾斯汀,谢谢。该脚本现已清理完毕,并考虑了您的解决方案。
【解决方案5】:

另一个解决方案...我觉得这个功能更优雅,它还会删除尾随的'?'如果要删除的键是查询字符串中唯一的键。

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

» Run these tests on 3v4l

【讨论】:

    【解决方案6】:

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

    或者这行得通吗?:

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

    只是一个想法。

    【讨论】:

      【解决方案7】:

      您可以为此使用server variables,例如$_SERVER['REQUEST_URI'],或者更好:$_SERVER['PHP_SELF']

      【讨论】:

      • 这当然假设他正在解析的url是正在解析的页面。
      【解决方案8】:
      @list($url) = explode("?", $url, 2);
      

      【讨论】:

        【解决方案9】:

        一个函数如何通过循环 $_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>
        

        【讨论】:

          【解决方案10】:

          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;
          

          【讨论】:

            【解决方案11】:

            在我看来,最好的方法是:

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

            它检查是否有 'i' GET 参数,如果有则删除它。

            【讨论】:

              【解决方案12】:

              只需使用 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();
                  }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-08-04
                • 1970-01-01
                • 2011-12-07
                • 1970-01-01
                • 2012-12-22
                • 1970-01-01
                • 2012-10-11
                相关资源
                最近更新 更多