Beautiful way to remove GET-variables with PHP?
Solution 1
Ok, to remove all variables, maybe the prettiest is
$url = strtok($url, '?');
See about strtok
here.
Its the fastest (see below), and handles urls without a '?' properly.
To take a url+querystring and remove just one variable (without using a regex replace, which may be faster in some cases), you might do something like:
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;
}
A regex replace to remove a single var might look like:
function removeqsvar($url, $varname) {
return preg_replace('/([?&])'.$varname.'=[^&]+(&|$)/','$1',$url);
}
Heres the timings of a few different methods, ensuring timing is reset inbetween runs.
<?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; ";
shows
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 wins, and is by far the smallest code.
Solution 2
How about:
preg_replace('/\\?.*/', '', $str)
Solution 3
If the URL that you are trying to remove the query string from is the current URL of the PHP script, you can use one of the previously mentioned methods. If you just have a string variable with a URL in it and you want to strip off everything past the '?' you can do:
$pos = strpos($url, "?");
$url = substr($url, 0, $pos);
Solution 4
Another solution... I find this function more elegant, it will also remove the trailing '?' if the key to remove is the only one in the query string.
/**
* 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;
}
Tests:
$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/>';
}
Will output:
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
Solution 5
Inspired by the comment of @MitMaro, I wrote a small benchmark to test the speed of solutions of @Gumbo, @Matt Bridges and @justin the proposal in the question:
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;
Result: @justin's strtok is the fastest.
Note: tested on a local Debian Lenny system with Apache2 and PHP5.
Related videos on Youtube
Jens Törnell
Updated on April 23, 2020Comments
-
Jens Törnell about 4 years
I have a string with a full URL including GET variables. Which is the best way to remove the GET variables? Is there a nice way to remove just one of them?
This is a code that works but is not very beautiful (I think):
$current_url = explode('?', $current_url); echo $current_url[0];
The code above just removes all the GET variables. The URL is in my case generated from a CMS so I don't need any information about server variables.
-
MitMaro over 14 yearsI would stick with what you have unless performance is not an issue. The regex solution supplied by Gumbo is going to be be as pretty as it gets.
-
Question Mark over 14 yearsIt Doesn't need to be beautiful if it's going in functions.php or whereever you hide your ugly bits, you'll only need to see qs_build() to call it
-
doublejosh almost 11 yearsHere's a way to do this via a nice anonymous function. stackoverflow.com/questions/4937478/…
-
Marten Koetsier almost 5 yearsHow about the url fragment? The solutions I see below all discard the fragment as well, just as your code does.
-
-
MitMaro over 14 yearsThis assumes of course that the url he is parsing is the page doing the parsing.
-
MitMaro over 14 yearsDefinitely prettier. I wonder which one would perform better though. +1
-
MitMaro over 14 years+1 because its the only other answer here that answers the question and provides an alternative.
-
Jens Törnell over 14 yearsThis saved me a few rows and for me this is short and beautiful. Thank you!
-
Gumbo over 14 yearsYou should consider that the URL might not contain a
?
. Your code will then return an empty string. -
Justin over 14 yearsregexp execution time: 0.14591598510742 seconds; explode execution time: 0.07137393951416 seconds; strpos execution time: 0.080883026123047 seconds; tok execution time: 0.042459011077881 seconds;
-
Jens Törnell over 14 yearsVery nice! I think speed is important. It's not the only thing that is going to happen. A web application could have hundreds of functions. "It's all in the details". Thanks, vote up!
-
Scharrels over 14 yearsJustin, thanks. The script is now cleaned up and takes your solution into account.
-
Jens Törnell over 14 yearsOk, I changed my mind. strtok way looks even better. The other functions did not work that well. I tried the functions on these get variables ?cbyear=2013&test=value and wrote echo removeqsvar($current_url, 'cbyear'); and got the result: amp;test=value
-
Justin over 14 yearsah yeah... the regex is not complete - it'll need to replace the trailing delimiter and miss the leading one (wrote it blind). The longer function should still work fine though. preg_replace('/([?&])'.$varname.'=[^&]+(&|$)/','$1',$url) should work
-
Artem Russakovskii over 10 yearsPHP 5.4 seems to complain about @unset - it doesn't like the @ symbol, oddly.
-
Justin over 10 yearsnot surprising - the @ operator (hide errors) is sort of evil anyway - theres probably a better way of doing it in PHP 5.4 now, but I haven't been writing PHP for almost 2 years now so I'm a bit out of practice.
-
Admin over 9 yearsUse
/(\\?|&)the-var=.*?(&|$)/
to remove only a specific variable (the-var
here). -
FrancescoMM about 7 yearsstrtok rocks, +1
-
CenterOrbit over 5 yearsYeah to back what @Gumbo said, I would change the second line to:
$url = ($pos)? substr($url, 0, $pos) : $url;