Cách tuyệt vời để loại bỏ biến GET với PHP?


92

Tôi có một chuỗi với URL đầy đủ bao gồm các biến GET. Cách tốt nhất để loại bỏ các biến GET? Có cách nào hay để loại bỏ chỉ một trong số chúng không?

Đây là một đoạn mã hoạt động nhưng không đẹp lắm (tôi nghĩ vậy):

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

Đoạn mã trên chỉ xóa tất cả các biến GET. Trong trường hợp của tôi, URL được tạo từ CMS nên tôi không cần bất kỳ thông tin nào về các biến máy chủ.


1
Tôi sẽ gắn bó với những gì bạn có trừ khi hiệu suất không phải là vấn đề. Giải pháp regex do Gumbo cung cấp sẽ trở nên đẹp đẽ như nó có được.
MitMaro

Nó Không cần phải đẹp nếu nó đi vào functions.php hoặc bất cứ nơi nào bạn giấu bit xấu xí của bạn, bạn sẽ chỉ cần phải nhìn thấy qs_build () để gọi nó
Câu hỏi Đánh dấu

Đây là một cách để làm điều này thông qua một chức năng ẩn danh tốt đẹp. stackoverflow.com/questions/4937478/…
doublejosh

Làm thế nào về đoạn url? Các giải pháp tôi thấy bên dưới đều loại bỏ phân đoạn, giống như mã của bạn.
Marten Koetsier

Câu trả lời:


232

Được, để loại bỏ tất cả các biến, có thể tốt nhất là

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

Xem về strtoktại đây .

Nó là nhanh nhất (xem bên dưới) và xử lý các url không có '?' đúng cách.

Để lấy một url + chuỗi truy vấn và chỉ xóa một biến (mà không sử dụng thay thế regex, có thể nhanh hơn trong một số trường hợp), bạn có thể làm như sau:

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

Thay thế regex để xóa một var duy nhất có thể trông giống như sau:

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

Đây là thời gian của một số phương pháp khác nhau, đảm bảo thời gian được đặt lại giữa các lần chạy.

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

trình diễn

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 thắng và cho đến nay là mã nhỏ nhất.


Ok, tôi đã đổi ý. cách strtok trông thậm chí còn tốt hơn. Các chức năng khác không hoạt động tốt. Tôi đã thử các hàm trên các biến get? Cbyear = 2013 & test = value và viết echo removeqsvar ($ current_url, 'cbyear'); và nhận được kết quả: amp; test = giá trị
Jens Tornell

à vâng ... regex chưa hoàn chỉnh - nó sẽ cần phải thay thế dấu phân cách ở cuối và bỏ sót dấu đứng đầu (đã viết nó mù). Chức năng dài hơn vẫn sẽ hoạt động tốt. preg_replace ('/([?&])'.$ varname.' = [^ &] + (& | $) / ',' $ 1 ', $ url) sẽ hoạt động
Justin

1
PHP 5.4 dường như phàn nàn về @unset - nó không thích biểu tượng @, thật kỳ lạ.
Artem Russakovskii

1
không có gì đáng ngạc nhiên - toán tử @ (ẩn lỗi) dù sao cũng là một thứ xấu xa - có lẽ có một cách tốt hơn để làm điều đó trong PHP 5.4 bây giờ, nhưng tôi đã không viết PHP gần 2 năm nay nên tôi hơi thất vọng thực hành.
Justin

đá strtok, +1
FrancescoMM

33

Làm thế nào về:

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

1
Chắc chắn là đẹp hơn. Tôi tự hỏi cái nào sẽ hoạt động tốt hơn. +1
MitMaro

Điều này đã giúp tôi tiết kiệm được một vài hàng và đối với tôi thì nó ngắn và đẹp. Cảm ơn bạn!
Jens Törnell

5
Sử dụng /(\\?|&)the-var=.*?(&|$)/để loại bỏ chỉ một biến cụ thể ( the-vartại đây).

10

Nếu URL mà bạn đang cố gắng xóa chuỗi truy vấn là URL hiện tại của tập lệnh PHP, bạn có thể sử dụng một trong các phương pháp đã đề cập trước đó. Nếu bạn chỉ có một biến chuỗi với URL trong đó và bạn muốn loại bỏ mọi thứ qua dấu '?' bạn có thể làm:

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

+1 vì nó là câu trả lời khác duy nhất ở đây trả lời câu hỏi và cung cấp một phương án thay thế.
MitMaro

2
Bạn nên xem xét rằng URL có thể không chứa a ?. Sau đó, mã của bạn sẽ trả về một chuỗi trống.
Gumbo

Vâng để quay lại những gì @Gumbo đã nói, tôi sẽ thay đổi dòng thứ hai thành:$url = ($pos)? substr($url, 0, $pos) : $url;
CenterOrbit

7

Lấy cảm hứng từ nhận xét của @MitMaro, tôi đã viết một điểm chuẩn nhỏ để kiểm tra tốc độ của các giải pháp của @Gumbo, @Matt Bridges và @justin đề xuất trong câu hỏi:

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

Kết quả: @ justin's strtok là nhanh nhất.

Lưu ý: đã thử nghiệm trên hệ thống Debian Lenny cục bộ với Apache2 và PHP5.


thời gian thực hiện regexp: 0,14591598510742 giây; thời gian thực hiện nổ: 0,07137393951416 giây; thời gian thực hiện strpos: 0,080883026123047 giây; thời gian thực hiện tok: 0,042459011077881 giây;
Justin

Rất đẹp! Tôi nghĩ tốc độ là quan trọng. Đó không phải là điều duy nhất sẽ xảy ra. Một ứng dụng web có thể có hàng trăm chức năng. "Tất cả đều nằm trong chi tiết". Cảm ơn, bình chọn!
Jens Törnell

Justin, cảm ơn. Tập lệnh hiện đã được làm sạch và có tính đến giải pháp của bạn.
Scharrels

7

Một giải pháp khác ... Tôi thấy chức năng này thanh lịch hơn, nó cũng sẽ loại bỏ dấu '?' nếu khóa cần xóa là khóa duy nhất trong chuỗi truy vấn.

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

Kiểm tra:

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

Sẽ xuất:

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

»Chạy các thử nghiệm này trên 3v4l


3

Bạn không thể sử dụng các biến máy chủ để thực hiện việc này?

Hay điều này sẽ hoạt động ?:

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

Chỉ là một suy nghĩ.


2

Bạn có thể sử dụng các biến máy chủ cho điều này, ví dụ $_SERVER['REQUEST_URI'], hoặc thậm chí tốt hơn: $_SERVER['PHP_SELF'].


4
Tất nhiên, điều này giả định rằng url mà anh ta đang phân tích cú pháp là trang đang phân tích cú pháp.
MitMaro


0

Làm thế nào về một hàm để viết lại chuỗi truy vấn bằng cách lặp qua mảng $ _GET

! Phác thảo sơ bộ về một chức năng phù hợp

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

Một cái gì đó như thế này sẽ tốt để giữ cho các liên kết phân trang, v.v.

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

0

basename($_SERVER['REQUEST_URI']) trả về mọi thứ sau và bao gồm cả dấu '?',

Trong mã của tôi, đôi khi tôi chỉ cần các phần, vì vậy hãy tách nó ra để tôi có thể nhận được giá trị của những gì tôi cần ngay lập tức. Không chắc chắn về tốc độ thực hiện so với các phương pháp khác, nhưng nó thực sự hữu ích đối với tôi.

$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

Theo tôi, cách tốt nhất sẽ là:

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

Nó kiểm tra xem có tham số 'i' GET hay không và loại bỏ nó nếu có.


0

chỉ cần sử dụng javascript echo'd để loại bỏ URL của bất kỳ biến nào bằng biểu mẫu trống, tự gửi:

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

Sau đó tạo hàm javascript này:

    function unsetter() {
    $('<form id = "unset" name = "unset" METHOD="GET"><input type="submit"></form>').appendTo('body');
    $( "#unset" ).submit();
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.