Прекрасний спосіб видалити GET-змінні за допомогою PHP?


92

У мене є рядок із повною URL-адресою, включаючи змінні GET. Який найкращий спосіб видалити змінні GET? Чи є хороший спосіб видалити лише один з них?

Це код, який працює, але не дуже гарний (я думаю):

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

Наведений вище код просто видаляє всі змінні GET. У моєму випадку URL-адреса генерується із системи управління вмістом, тому мені не потрібна інформація про змінні сервера.


1
Я б дотримувався того, що у вас є, якщо продуктивність не є проблемою. Рішення регулярних виразів, яке постачає Gumbo, буде настільки ж гарним, наскільки воно стає.
MitMaro

Не потрібно бути красивим, якщо це відбувається у functions.php або де б ви не ховали свої потворні шматочки, вам потрібно буде лише побачити qs_build (), щоб його викликати
знак запитання

Ось спосіб зробити це за допомогою приємної анонімної функції. stackoverflow.com/questions/4937478 / ...
doublejosh

Як щодо фрагмента URL-адреси? Рішення, які я бачу нижче, також відкидають фрагмент, як і ваш код.
Marten Koetsier

Відповіді:


232

Гаразд, щоб видалити всі змінні, можливо, найкрасивіше

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

Подивіться про strtokтут .

Це найшвидше (див. Нижче), і обробляє URL-адреси без знака "?" належним чином.

Щоб взяти url + рядок запиту та видалити лише одну змінну (без використання заміни регулярного виразу, що в деяких випадках може бути швидшим), ви можете зробити щось на зразок:

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

Заміна регулярного виразу для видалення одного варіанта може виглядати так:

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 шлях виглядає ще краще. Інші функції працювали не так добре. Я спробував функції цих змінних get? Cbyear = 2013 & test = value і написав echo removeqsvar ($ current_url, 'cbyear'); і отримав результат: amp; test = value
Єнс Торнелл

а, так ... регулярний вираз не закінчений - йому потрібно буде замінити кінцевий роздільник і пропустити провідний (написав його сліпим). Більш довга функція все одно повинна працювати нормально. preg_replace ('/([?&])'.$ varname.' = [^ &] + (& | $) / ',' $ 1 ', $ url) повинен працювати
Джастін,

1
Здається, PHP 5.4 скаржиться на @unset - як не дивно, йому не подобається символ @.
Артем Руссаковський

1
не дивно - оператор @ (приховувати помилки) у будь-якому випадку є злом - є, мабуть, зараз кращий спосіб зробити це в PHP 5.4, але я майже 2 роки не пишу PHP, тому я трохи не в курсі практика.
Джастін

Стріток Скеля, +1
FrancescoMM

33

Як щодо:

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

1
Безумовно, гарніша. Цікаво, хто з них міг би виступати краще. +1
MitMaro

Це врятувало мене кілька рядків, і для мене це коротко і красиво. Дякую!
Йенс Тернелл

5
Використовуйте /(\\?|&)the-var=.*?(&|$)/для видалення лише певної змінної ( the-varтут).

10

Якщо URL-адреса, з якої ви намагаєтеся видалити рядок запиту, є поточною URL-адресою сценарію PHP, ви можете скористатися одним із раніше згаданих методів. Якщо у вас просто є рядкова змінна з URL-адресою, і ви хочете видалити все, що минуло "?" Ви можете зробити:

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

+1, оскільки тут єдина відповідь, яка відповідає на запитання та пропонує альтернативу.
MitMaro

2
Вам слід врахувати, що URL-адреса може не містити символу ?. Потім ваш код поверне порожній рядок.
Гамбо

Так, щоб підтримати те, що сказав @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; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;
strtok: 0,12; вибух: 0,19; регулярний вираз: 0,31; strpos: 0,18;

Результат: @ justin's strtok - найшвидший.

Примітка: протестовано на локальній системі Debian Lenny з Apache2 та PHP5.


час виконання регулярного виразу: 0,14591598510742 секунди; час виконання вибуху: 0,07137393951416 секунд; час виконання strpos: 0,080883026123047 секунд; час виконання току: 0,042459011077881 секунд;
Джастін

Дуже хороша! Я думаю, що швидкість важлива. Це не єдине, що станеться. Веб-програма може мати сотні функцій. "Все в подробицях". Дякую, проголосуйте!
Йенс Тернелл

Джастін, дякую. Сценарій тепер очищений і враховує ваше рішення.
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

На мій погляд, найкращим способом буде такий:

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

Він перевіряє, чи є параметр 'i' GET, і видаляє його, якщо він є.


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();
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.