245

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;
}
?>
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Navi Gamage
  • 2,663
  • 2
  • 19
  • 18

16 Answers16

704

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
)
---
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
RiaD
  • 46,822
  • 11
  • 79
  • 123
  • 25
    +1 for using $_SERVER directly instead of rebuilding the url only to parse it again. would give another +1 if possible, for concision. – ericsoco Sep 30 '12 at 19:48
  • `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"],'?'));` – here Oct 27 '12 at 20:10
  • 8
    Oops -- reverse those arguments for explode(), delimiter goes first. `array_shift(explode('?',$_SERVER["REQUEST_URI"]))` – here Oct 27 '12 at 20:36
  • 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.) – Bretticus Jan 25 '13 at 19:05
  • 13
    It doesn't return bool(false) if ? is not present in the string, it returns the string. – Ben C Jul 31 '13 at 16:48
  • 4
    Great!.. It's still returning the url even if `?` is not present. – Harikrishnan Feb 05 '15 at 07:13
  • @here it seems `explode` returns the full string as first array key when the delimiter is not found even in old versions. check [here](https://3v4l.org/EaXNJ#v5444) – sepehr Dec 09 '15 at 13:49
  • @RiaD 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`. thanks – sepehr Dec 09 '15 at 13:58
  • 1
    @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). – RiaD Dec 10 '15 at 17:53
  • @RiaD 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. – sepehr Dec 11 '15 at 09:33
  • What if we are using seo url? – Deepak Dholiyan Jul 17 '16 at 11:07
  • 1
    strtok is forgotten because its usage is inconsistent with logic (like only needing to pass arguments on the first usage), just use explode. – Andrew Sep 10 '18 at 18:03
  • With array destructuring assignment (php ^7.1): `[$url] = explode('?', $_SERVER['REQUEST_URI']);` – Artem Molotov Feb 22 '20 at 22:05
  • I like this solution, but is there a way to include the first subfolder/page as well? Like: https://www.example.com/subfolder/another-map/?test=test Will return: https://www.example.com/subfolder/ – Loosie94 Aug 11 '20 at 13:01
74

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
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
veritas
  • 2,034
  • 1
  • 16
  • 30
67

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.

Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
Ludo - Off the record
  • 5,153
  • 4
  • 31
  • 23
  • 1
    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. – NikiC Dec 21 '15 at 21:27
  • @AndyLorenz have you even tried it? because it actually does remove the querystring. – Ludo - Off the record Apr 24 '21 at 16:14
  • @Ludo-Offtherecord you are right - I've deleted my comment. apologies! – Andy Lorenz Apr 24 '21 at 16:52
16
$val = substr( $url, 0, strrpos( $url, "?"));
zellio
  • 31,308
  • 1
  • 42
  • 61
  • Guys cording to your answers Im done..thanks for your help..It cleas query section in the url... – Navi Gamage Aug 07 '11 at 00:10
  • > 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..Empty – Navi Gamage Aug 07 '11 at 00:11
  • New php code `code` `code` – Navi Gamage Aug 07 '11 at 00:11
  • 2
    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, "?")); – Rob May 20 '13 at 14:26
  • As stated by Navi, this answer is not reliable. https://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.** – mickmackusa Feb 26 '20 at 22:03
  • You could wrap the whole function in `if (strrpos( $requestString, "?") !== false) { ... }`. This works fine for me. – Earlee Apr 02 '20 at 08:07
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
Mukesh Saxena
  • 146
  • 2
  • 7
  • 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. – mickmackusa Feb 26 '20 at 12:06
  • @mickmackusa Could you please elaborate your comment? Where do I need to explain my answer? I will grateful to you. – Mukesh Saxena Feb 26 '20 at 14:01
  • 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 -- https://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. – mickmackusa Feb 26 '20 at 20:23
  • Another difference is that the accepted answer also takes care of a possible fragment, but yours will not. https://3v4l.org/ERr4V or worse it could mangle the url to the left of the querystring https://3v4l.org/L61q1 – mickmackusa Feb 26 '20 at 20:24
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

8

You can use the parse_url build in function like that:

$baseUrl = $_SERVER['SERVER_NAME'] . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
Muho
  • 3,188
  • 23
  • 34
5
explode('?', $_SERVER['REQUEST_URI'])[0]
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);
user1079877
  • 9,008
  • 4
  • 43
  • 54
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

Janith Chinthana
  • 3,792
  • 2
  • 27
  • 54
2

You can try:

<?php
$this_page = basename($_SERVER['REQUEST_URI']);
if (strpos($this_page, "?") !== false) $this_page = reset(explode("?", $this_page));
?>
ysrb
  • 6,693
  • 2
  • 29
  • 30
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;
}
Ryan Prechel
  • 6,592
  • 5
  • 23
  • 21
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;
}
trante
  • 33,518
  • 47
  • 192
  • 272
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);
Stephen Ostermiller
  • 23,933
  • 14
  • 88
  • 109
kwelsan
  • 1,229
  • 1
  • 7
  • 18
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'];
sMyles
  • 2,418
  • 1
  • 30
  • 44
-3

Try this:

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

or

$urrl=$_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF']
HRALDA
  • 1
  • 2