patternphpMinor
Remove a parameter and its value from URL's query string
Viewed 0 times
queryvalueremoveitsandfromstringurlparameter
Problem
I'm coding an algorithm to remove a parameter (let's call it
Of course, after the
I'd also like to remove the leading
Details:
Input examples:
Expected output:
My initial attempt:
The regex itself is rather simple. The callback logic is as follows:
This logic seemed rather complicated, hence I rewrote it into a single regex:
Now
foo) from URL strings.Of course, after the
foo parameter removal, the query string should remain valid (with a leading ? and remaining parameters separated by &).I'd also like to remove the leading
? if foo was the only parameter.Details:
- Domain and pathname should be preserved.
- The URLs may not contain a query string. Expected output is the same as input.
- The URLs may contain a query string which does not contain the
fooparameter. Expected output is the same as input.
- The URLs are already properly URL-encoded.
- Fragments (hashes) don't necessarily need to be kept, but it would be a nice little extra.
Input examples:
http://example.com/?foo=42
http://example.com/?foo=42&bar=43
http://example.com/?bar=43&foo=42
http://example.com/?bar=43&foo=42&baz=44
http://domain.com.uk/pathname?foo=42&bar=bar%20value
http://yahoo.com/mail
http://nofoo.com/?bar=43Expected output:
http://example.com/
http://example.com/?bar=43
http://example.com/?bar=43
http://example.com/?bar=43&baz=44
http://domain.com.uk/pathname?bar=bar%20value
http://yahoo.com/mail
http://nofoo.com/?bar=43My initial attempt:
preg_replace_callback('/([?&])foo=[^&]+(&|$)/', function($matches) {
return $matches[2] ? $matches[1] : '';
}, $url);The regex itself is rather simple. The callback logic is as follows:
- If
foois not the last parameter (2nd capturing group is not end of string), then the whole match is replaced by the first capturing group (?or&). This handles:
?foo=valuefoo&bar->?bar
&foo=valuefoo&bar->&bar
- If
foois the last parameter then the whole match is replaced by an empty string. This handles:
?bar=valuebar&foo=valuefoo->?bar=valuebar
?foo=valuefoo-> (empty string)
This logic seemed rather complicated, hence I rewrote it into a single regex:
preg_replace('/[?&]foo=[^&]+$|([?&])foo=[^&]+&/', '$1', $url);Now
Solution
I would also avoid using regexes or any kind of manual string parsing, you can do it all with
Then with a simple script to test it:
You get:
parse_str() and http_build_query(), thusly:function removeAndReturn(&$url, $toRemove)
{
$parsed = [];
parse_str(substr($url, strpos($url, '?') + 1), $parsed);
$removed = $parsed[$toRemove];
unset($parsed[$toRemove]);
$url = 'http://example.com/';
if(!empty($parsed))
{
$url .= '?' . http_build_query($parsed);
}
return $removed;
}Then with a simple script to test it:
$input = ['http://example.com/?foo=42',
'http://example.com/?foo=42&bar=43',
'http://example.com/?bar=43&foo=42',
'http://example.com/?bar=43&foo=42&baz=44'];
$expected = ['http://example.com/',
'http://example.com/?bar=43',
'http://example.com/?bar=43',
'http://example.com/?bar=43&baz=44'];
$count = count($input);
for($i = 0; $i ' .
'URL: ' . $input[$i] . '';
if($input[$i] === $expected[$i])
echo 'Match';
}You get:
Foo: 42
URL: http://example.com/
Match
Foo: 42
URL: http://example.com/?bar=43
Match
Foo: 42
URL: http://example.com/?bar=43
Match
Foo: 42
URL: http://example.com/?bar=43&baz=44
MatchCode Snippets
function removeAndReturn(&$url, $toRemove)
{
$parsed = [];
parse_str(substr($url, strpos($url, '?') + 1), $parsed);
$removed = $parsed[$toRemove];
unset($parsed[$toRemove]);
$url = 'http://example.com/';
if(!empty($parsed))
{
$url .= '?' . http_build_query($parsed);
}
return $removed;
}$input = ['http://example.com/?foo=42',
'http://example.com/?foo=42&bar=43',
'http://example.com/?bar=43&foo=42',
'http://example.com/?bar=43&foo=42&baz=44'];
$expected = ['http://example.com/',
'http://example.com/?bar=43',
'http://example.com/?bar=43',
'http://example.com/?bar=43&baz=44'];
$count = count($input);
for($i = 0; $i < $count; $i++)
{
$foo = removeAndReturn($input[$i], 'foo');
echo 'Foo: ' . $foo . '<br />' .
'URL: ' . $input[$i] . '<br />';
if($input[$i] === $expected[$i])
echo 'Match<br />';
}Foo: 42
URL: http://example.com/
Match
Foo: 42
URL: http://example.com/?bar=43
Match
Foo: 42
URL: http://example.com/?bar=43
Match
Foo: 42
URL: http://example.com/?bar=43&baz=44
MatchContext
StackExchange Code Review Q#38070, answer score: 5
Revisions (0)
No revisions yet.