How to remove the querystring and get only the URL?
Asked Answered
L

17

254

I'm using PHP to build the URL of the current page. Sometimes, URLs in the form of

www.example.com/myurl.html?unwantedthngs

are requested. I want to remove the ? and everything that follows it (querystring), such that the resulting URL becomes:

www.example.com/myurl.html

My current code is this:

<?php
function curPageURL() {
    $pageURL = 'http';
    if ($_SERVER["HTTPS"] == "on") {
        $pageURL .= "s";
    }
    $pageURL .= "://";
    if ($_SERVER["SERVER_PORT"] != "80") {
        $pageURL .= $_SERVER["SERVER_NAME"] . ":" .
            $_SERVER["SERVER_PORT"] . $_SERVER["REQUEST_URI"];
    } else {
        $pageURL .= $_SERVER["SERVER_NAME"] . $_SERVER["REQUEST_URI"];
    }
    return $pageURL;
}
?>
Lieberman answered 6/8, 2011 at 23:20 Comment(1)
BTW, that's called the "query string".Dermatoplasty
P
721

You can use strtok to get string before first occurence of ?

$url = strtok($_SERVER["REQUEST_URI"], '?');

strtok() represents the most concise technique to directly extract the substring before the ? in the querystring. explode() is less direct because it must produce a potentially two-element array by which the first element must be accessed.

Some other techniques may break when the querystring is missing or potentially mutate other/unintended substrings in the url -- these techniques should be avoided.

A demonstration:

$urls = [
    'www.example.com/myurl.html?unwantedthngs#hastag',
    'www.example.com/myurl.html'
];

foreach ($urls as $url) {
    var_export(['strtok: ', strtok($url, '?')]);
    echo "\n";
    var_export(['strstr/true: ', strstr($url, '?', true)]); // not reliable
    echo "\n";
    var_export(['explode/2: ', explode('?', $url, 2)[0]]);  // limit allows func to stop searching after first encounter
    echo "\n";
    var_export(['substr/strrpos: ', substr($url, 0, strrpos( $url, "?"))]);  // not reliable; still not with strpos()
    echo "\n---\n";
}

Output:

array (
  0 => 'strtok: ',
  1 => 'www.example.com/myurl.html',
)
array (
  0 => 'strstr/true: ',
  1 => 'www.example.com/myurl.html',
)
array (
  0 => 'explode/2: ',
  1 => 'www.example.com/myurl.html',
)
array (
  0 => 'substr/strrpos: ',
  1 => 'www.example.com/myurl.html',
)
---
array (
  0 => 'strtok: ',
  1 => 'www.example.com/myurl.html',
)
array (
  0 => 'strstr/true: ',
  1 => false,                       // bad news
)
array (
  0 => 'explode/2: ',
  1 => 'www.example.com/myurl.html',
)
array (
  0 => 'substr/strrpos: ',
  1 => '',                          // bad news
)
---
Pham answered 7/8, 2011 at 19:2 Comment(14)
+1 for using $_SERVER directly instead of rebuilding the url only to parse it again. would give another +1 if possible, for concision.Tectonic
explode() will return the full string if the delimiter is not found. PHP 5.4 $uri = explode($_SERVER["REQUEST_URI"],'?')[0]; PHP before 5.4 array_shift(explode($_SERVER["REQUEST_URI"],'?'));Alfeus
Oops -- reverse those arguments for explode(), delimiter goes first. array_shift(explode('?',$_SERVER["REQUEST_URI"]))Alfeus
How about ... (strtok($_SERVER["REQUEST_URI"],'?') !== FALSE) ? strtok($_SERVER["REQUEST_URI"],'?') : $_SERVER["REQUEST_URI"]; I like the array_shift version too (more succinct than my boolean test.)Dialectologist
It doesn't return bool(false) if ? is not present in the string, it returns the string.Manno
Great!.. It's still returning the url even if ? is not present.Archduke
@Alfeus it seems explode returns the full string as first array key when the delimiter is not found even in old versions. check hereRenick
@Pham I prefer strtok instead of explode because it returns a string and not an array but is there any other reason behind that? Please edit your answer and include your reasoning there so peaple have a better understanding of why to use strtok. thanksRenick
@sepehr, I just don't see any point not to use function that does exactly what you need and use another one and parse it result (i.e get [0] after exploding) (unless of course there is a specific reason like better performance, lack of unneeded dependency, etc).Pham
@Pham you're right, I think the reason behind my comment was that I didn't like using a less known function over a well known one, but there isn't any logic behind this reasoning.Renick
What if we are using seo url?Seminal
strtok is forgotten because its usage is inconsistent with logic (like only needing to pass arguments on the first usage), just use explode.Cerise
With array destructuring assignment (php ^7.1): [$url] = explode('?', $_SERVER['REQUEST_URI']);Photomap
I like this solution, but is there a way to include the first subfolder/page as well? Like: example.com/subfolder/another-map/?test=test Will return: example.com/subfolderScandal
H
77

Use PHP Manual - parse_url() to get the parts you need.

Edit (example usage for @Navi Gamage)

You can use it like this:

<?php
function reconstruct_url($url){
    $url_parts = parse_url($url);
    $constructed_url = $url_parts['scheme'] . '://' . $url_parts['host'] . $url_parts['path'];

    return $constructed_url;
}

?>

Edit (second full example):

Updated function to make sure scheme will be attached and none notice msgs appear:

function reconstruct_url($url){
    $url_parts = parse_url($url);
    $constructed_url = $url_parts['scheme'] . '://' . $url_parts['host'] . (isset($url_parts['path'])?$url_parts['path']:'');

    return $constructed_url;
}

$test = array(
    'http://www.example.com/myurl.html?unwan=abc',
    `http://www.example.com/myurl.html`,
    `http://www.example.com`,
    `https://example.com/myurl.html?unwan=abc&ab=1`
);

foreach($test as $url){
    print_r(parse_url($url));
}

Will return:

Array
(
    [scheme] => http
    [host] => www.example.com
    [path] => /myurl.html
    [query] => unwan=abc
)
Array
(
    [scheme] => http
    [host] => www.example.com
    [path] => /myurl.html
)
Array
(
    [scheme] => http
    [host] => www.example.com
)
Array
(
    [path] => example.com/myurl.html
    [query] => unwan=abc&ab=1
)

This is the output from passing example URLs through parse_url() with no second parameter (for explanation only).

And this is the final output after constructing URL using:

foreach($test as $url){
    echo reconstruct_url($url) . '<br/>';
}

Output:

http://www.example.com/myurl.html
http://www.example.com/myurl.html
http://www.example.com
https://example.com/myurl.html
Hectare answered 6/8, 2011 at 23:22 Comment(0)
I
72

best solution:

echo parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);

No need to include your http://example.com in your <form action=""> if you're submitting a form to the same domain.

Imperfect answered 31/7, 2014 at 3:54 Comment(3)
Note that parse_url expects an absolute URL, so you will get incorrect results in some cases, e.g. if your REQUEST_URL starts with multiple consecutive slashes. Those will be interpreted as a protocol-relative URI.Vapor
@AndyLorenz have you even tried it? because it actually does remove the querystring.Imperfect
@Ludo-Offtherecord you are right - I've deleted my comment. apologies!Turnaround
C
16
$val = substr( $url, 0, strrpos( $url, "?"));
Collative answered 6/8, 2011 at 23:23 Comment(6)
Guys cording to your answers Im done..thanks for your help..It cleas query section in the url...Lieberman
> www.mydomain.com/myurl.html?unwantedthings result is Okay! > www.mydomian.com/myurl.html Done... But when it comes with normal url > www.mydomain.com/myurl.html result is nothing..EmptyLieberman
New php code code <?php function curPageURL() { $pageURL = 'http'; if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";} $pageURL .= "://"; if ($_SERVER["SERVER_PORT"] != "80") { $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"]; } else { $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"]; $pageURL = substr( $pageURL, 0, strrpos( $pageURL, "?")); } return $pageURL; } ?> codeLieberman
I think this is a rather sweet and simple solution to the problem. No need for loads of extentions or functions. I used this to get the current called file name. $base = basename($_SERVER['REQUEST_URI']); $page = substr($base, 0, strrpos($base, "?"));Dapplegray
As stated by Navi, this answer is not reliable. 3v4l.org/nhVii If the querystring is absent in the url, the entire url is removed! This technique is not url-component-aware. This answer is inadvisable.Reclinate
You could wrap the whole function in if (strrpos( $requestString, "?") !== false) { ... }. This works fine for me.Team
O
9

Most Easiest Way

$url = 'https://www.youtube.com/embed/ROipDjNYK4k?rel=0&autoplay=1';
$url_arr = parse_url($url);
$query = $url_arr['query'];
print $url = str_replace(array($query,'?'), '', $url);

//output
https://www.youtube.com/embed/ROipDjNYK4k
Overage answered 9/9, 2016 at 15:53 Comment(4)
I disagree that this is the Most Easiest Way. No, bold text doesn't make your statement more compelling. This answer is lacking an explanation.Reclinate
@Reclinate Could you please elaborate your comment? Where do I need to explain my answer? I will grateful to you.Overage
All answers on Stackoverflow should include an explanation of how the solution works and why you feel it is an ideal technique. Links to documentation are also welcome. I fully understand your solution, but other researcher may not. Code-only answers are low value on Stackoverflow because they do very little to educate/empower thousands of future researchers. About not being simplest -- 3v4l.org/RE0GD would be a simpler version of your answer because it has fewer declared variables and makes just one replacement instead of two. The accepted answer is simplest of all.Reclinate
Another difference is that the accepted answer also takes care of a possible fragment, but yours will not. 3v4l.org/ERr4V or worse it could mangle the url to the left of the querystring 3v4l.org/L61q1Reclinate
P
8

You'll need at least PHP Version 5.4 to implement this solution without exploding into a variable on one line and concatenating on the next, but an easy one liner would be:

$_SERVER["HTTP_HOST"].explode('?', $_SERVER["REQUEST_URI"], 2)[0];

Server Variables: http://php.net/manual/en/reserved.variables.server.php
Array Dereferencing: https://wiki.php.net/rfc/functionarraydereferencing

Pyonephritis answered 23/3, 2016 at 18:57 Comment(0)
T
8

You can use the parse_url build in function like that:

$baseUrl = $_SERVER['SERVER_NAME'] . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
Talishatalisman answered 25/5, 2019 at 16:11 Comment(0)
T
5
explode('?', $_SERVER['REQUEST_URI'])[0]
Tove answered 3/9, 2022 at 8:45 Comment(1)
In keeping with SO's style, please add some English description of what it's doing. (Like your answer, btw.)Vagarious
S
2

You can try:

<?php
$this_page = basename($_SERVER['REQUEST_URI']);
if (strpos($this_page, "?") !== false) $this_page = reset(explode("?", $this_page));
?>
Shipmaster answered 6/8, 2011 at 23:23 Comment(0)
T
2

If you want to get request path (more info):

echo parse_url($_SERVER["REQUEST_URI"])['path']

If you want to remove the query and (and maybe fragment also):

function strposa($haystack, $needles=array(), $offset=0) {
        $chr = array();
        foreach($needles as $needle) {
                $res = strpos($haystack, $needle, $offset);
                if ($res !== false) $chr[$needle] = $res;
        }
        if(empty($chr)) return false;
        return min($chr);
}
$i = strposa($_SERVER["REQUEST_URI"], ['#', '?']);
echo strrpos($_SERVER["REQUEST_URI"], 0, $i);
Tuneberg answered 9/10, 2013 at 4:49 Comment(0)
D
2

could also use following as per the php manual comment

$_SERVER['REDIRECT_URL']

Please note this is working only for certain PHP environment only and follow the bellow comment from that page for more information;

Purpose: The URL path name of the current PHP file, path-info is N/A and excluding URL query string. Includes leading slash.

Caveat: This is before URL rewrites (i.e. it's as per the original call URL).

Caveat: Not set on all PHP environments, and definitely only ones with URL rewrites.

Works on web mode: Yes

Works on CLI mode: No

Developer answered 4/4, 2019 at 7:12 Comment(0)
L
1

To remove the query string from the request URI, replace the query string with an empty string:

function request_uri_without_query() {
    $result = $_SERVER['REQUEST_URI'];
    $query = $_SERVER['QUERY_STRING'];
    if(!empty($query)) {
        $result = str_replace('?' . $query, '', $result);
    }
    return $result;
}
Looseleaf answered 2/5, 2013 at 18:58 Comment(1)
I think there would be a potential problem with www.example.com/myurl.html?.Team
S
1

Because I deal with both relative and absolute URLs, I updated veritas's solution like the code below.
You can try yourself here: https://ideone.com/PvpZ4J

function removeQueryStringFromUrl($url) {
    if (substr($url,0,4) == "http") {
        $urlPartsArray = parse_url($url);
        $outputUrl = $urlPartsArray['scheme'] . '://' . $urlPartsArray['host'] . ( isset($urlPartsArray['path']) ? $urlPartsArray['path'] : '' );
    } else {
        $URLexploded = explode("?", $url, 2);
        $outputUrl = $URLexploded[0];
    }
    return $outputUrl;
}
Setting answered 10/2, 2015 at 23:1 Comment(0)
S
0

Try this

$url_with_querystring = 'www.example.com/myurl.html?unwantedthngs';
$url_data = parse_url($url_with_querystring);
$url_without_querystring = str_replace('?'.$url_data['query'], '', $url_with_querystring);
Schrecklichkeit answered 14/7, 2014 at 9:38 Comment(0)
D
0

Assuming you still want to get the URL without the query args (if they are not set), just use a shorthand if statement to check with strpos:

$request_uri = strpos( $_SERVER['REQUEST_URI'], '?' ) !== false ? strtok( $_SERVER["REQUEST_URI"], '?' ) : $_SERVER['REQUEST_URI'];
Diplopod answered 19/10, 2019 at 19:38 Comment(0)
C
0

I am surprised that this does not have an answer to do this really safe and clean, so let me do that. This checks if the URL can be parsed, and it keeps the #hash in the URL. strtok won't do that.

<?php

echo remove_url_query('https://foo.bar?arg1=alpha&arg2=beta#hash'); # https://foo.bar#hash

function remove_url_query( string $url ): ?string {

    $parsed_url = parse_url( $url );

    if ( ! $parsed_url ) {
        return null;
    }

    $scheme   = isset( $parsed_url['scheme'] ) ? $parsed_url['scheme'] . '://' : '';
    $host     = isset( $parsed_url['host'] ) ? $parsed_url['host'] : '';
    $port     = isset( $parsed_url['port'] ) ? ':' . $parsed_url['port'] : '';
    $user     = isset( $parsed_url['user'] ) ? $parsed_url['user'] : '';
    $pass     = isset( $parsed_url['pass'] ) ? ':' . $parsed_url['pass'] : '';
    $pass     = ( $user || $pass ) ? "$pass@" : '';
    $path     = isset( $parsed_url['path'] ) ? $parsed_url['path'] : '';
    $fragment = isset( $parsed_url['fragment'] ) ? '#' . $parsed_url['fragment'] : '';

    return "$scheme$user$pass$host$port$path$fragment";
}

Removing the types will make this work and all kinds of outdated PHP versions.

Cavetto answered 24/2 at 0:6 Comment(2)
When you are not performing concatenation, you can more simply use the null coalescing operator to fall back to an empty string instead of calling isset().Reclinate
@Reclinate I know this, in fact I thought about adding a more modern function but this way this function is better backwards comparable by just removing the types. You can also just do it to the $host and $path lines I think, so this code just looks nice this way because it aligns.Cavetto
A
-3

Try this:

$urrl=$_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME']

or

$urrl=$_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']
Algonkian answered 23/1, 2016 at 13:45 Comment(2)
Sorry but this is wrong - URI can be rewritten by htaccess - this would result in returning the script name but not the current URI.Duisburg
Dangerous as it can be spoofed.Jaffe

© 2022 - 2024 — McMap. All rights reserved.