137

I moved a WordPress installation to a new folder on a Windows/IIS server. I'm setting up 301 redirects in PHP, but it doesn't seem to be working. My post URLs have the following format:

http:://www.example.com/OLD_FOLDER/index.php/post-title/

I can't figure out how to grab the /post-title/ part of the URL.

$_SERVER["REQUEST_URI"] - which everyone seems to recommend - is returning an empty string. $_SERVER["PHP_SELF"] is just returning index.php. Why is this, and how can I fix it?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
CtrlDot
  • 3,102
  • 3
  • 25
  • 32
  • 24
    Just do a print_r($_SERVER) and see what data is available to you. If you can get the full URL then you can call pathinfo($url) to get the filename. – gradbot Oct 09 '08 at 20:53
  • 18
    It should be noted, that this question is about IIS, not PHP in general. Under Apache you'd just use $_SERVER['REQUEST_URI']. – Michał Tatarynowicz Aug 04 '09 at 21:05
  • @Pies Certainly $_SERVER['REQUEST_URI'] is the way to go...but how I can grab a specific portion of the URI.For example I have this URI:/Appointments/Administrator/events.php/219...how I can grab the number after /events.php/ – Dimitris Papageorgiou Apr 07 '14 at 11:17
  • possible duplicate of [Get the full URL in PHP](http://stackoverflow.com/questions/6768793/get-the-full-url-in-php) – T.Todua Nov 15 '14 at 10:12

15 Answers15

135

Maybe, because you are under IIS,

$_SERVER['PATH_INFO']

is what you want, based on the URLs you used to explain.

For Apache, you'd use $_SERVER['REQUEST_URI'].

hichris123
  • 10,145
  • 15
  • 56
  • 70
Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
  • hi by useing this i just receive the following error? `Notice: Undefined index: PATH_INFO in /home/tdpk/public_html/system/config.php on line 14` – chhameed Oct 19 '11 at 11:41
  • 6
    oops, drat -- just realized this question is about IIS, and I'm using. Sorry for the downvote. – Jason S May 08 '12 at 19:07
63
$pageURL = (@$_SERVER["HTTPS"] == "on") ? "https://" : "http://";
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;
Charles
  • 50,943
  • 13
  • 104
  • 142
Tyler Carter
  • 60,743
  • 20
  • 130
  • 150
  • 11
    OP clearly stated IIS - REQUEST_URI is not available under IIS – Tom Auger May 31 '11 at 20:33
  • 1
    You should never use magicquotes unless you absolutely have to in php. – Case Nov 02 '12 at 07:09
  • 2
    @TomAuger You need to look at the timeline. The OP added this long after I answered the question. The original question was asked approximately a year before I answered it. – Tyler Carter Nov 03 '12 at 16:22
  • 7
    @Stan, there is zero net performance benefit to using singles over doubles. None, nadda, zip, zero. It's an old wive's tale from the PHP3 era. Please don't perform such trivial mangling to content. – Charles Dec 16 '12 at 20:44
36

For Apache:

'http'.(empty($_SERVER['HTTPS'])?'':'s').'://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']


You can also use HTTP_HOST instead of SERVER_NAME as Herman commented. See this related question for a full discussion. In short, you are probably OK with using either. Here is the 'host' version:

'http'.(empty($_SERVER['HTTPS'])?'':'s').'://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']


For the Paranoid / Why it Matters

Typically, I set ServerName in the VirtualHost because I want that to be the canonical form of the website. The $_SERVER['HTTP_HOST'] is set based on the request headers. If the server responds to any/all domain names at that IP address, a user could spoof the header, or worse, someone could point a DNS record to your IP address, and then your server / website would be serving out a website with dynamic links built on an incorrect URL. If you use the latter method you should also configure your vhost or set up an .htaccess rule to enforce the domain you want to serve out, something like:

RewriteEngine On
RewriteCond %{HTTP_HOST} !(^stackoverflow.com*)$
RewriteRule (.*) https://stackoverflow.com/$1 [R=301,L]
#sometimes u may need to omit this slash ^ depending on your server

Hope that helps. The real point of this answer was just to provide the first line of code for those people who ended up here when searching for a way to get the complete URL with apache :)

Community
  • 1
  • 1
cwd
  • 53,018
  • 53
  • 161
  • 198
  • 2
    This should use `$_SERVER['HTTP_HOST']` instead of `$_SERVER['SERVER_NAME']`. If there is a virtual host setup, then SERVER_NAME will show that name. It may be something like `*.example.com` which is not valid. – Herman J. Radtke III Jan 30 '13 at 20:40
11

$_SERVER['REQUEST_URI'] doesn't work on IIS, but I did find this: http://neosmart.net/blog/2006/100-apache-compliant-request_uri-for-iis-and-windows/ which sounds promising.

Greg
  • 316,276
  • 54
  • 369
  • 333
9

Use this class to get the URL works.

class VirtualDirectory
{
    var $protocol;
    var $site;
    var $thisfile;
    var $real_directories;
    var $num_of_real_directories;
    var $virtual_directories = array();
    var $num_of_virtual_directories = array();
    var $baseURL;
    var $thisURL;

    function VirtualDirectory()
    {
        $this->protocol = $_SERVER['HTTPS'] == 'on' ? 'https' : 'http';
        $this->site = $this->protocol . '://' . $_SERVER['HTTP_HOST'];
        $this->thisfile = basename($_SERVER['SCRIPT_FILENAME']);
        $this->real_directories = $this->cleanUp(explode("/", str_replace($this->thisfile, "", $_SERVER['PHP_SELF'])));
        $this->num_of_real_directories = count($this->real_directories);
        $this->virtual_directories = array_diff($this->cleanUp(explode("/", str_replace($this->thisfile, "", $_SERVER['REQUEST_URI']))),$this->real_directories);
        $this->num_of_virtual_directories = count($this->virtual_directories);
        $this->baseURL = $this->site . "/" . implode("/", $this->real_directories) . "/";
        $this->thisURL = $this->baseURL . implode("/", $this->virtual_directories) . "/";
    }

    function cleanUp($array)
    {
        $cleaned_array = array();
        foreach($array as $key => $value)
        {
            $qpos = strpos($value, "?");
            if($qpos !== false)
            {
                break;
            }
            if($key != "" && $value != "")
            {
                $cleaned_array[] = $value;
            }
        }
        return $cleaned_array;
    }
}

$virdir = new VirtualDirectory();
echo $virdir->thisURL;
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sureshkumar
  • 129
  • 1
  • 5
7

Add:

function my_url(){
    $url = (!empty($_SERVER['HTTPS'])) ?
               "https://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'] :
               "http://".$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
    echo $url;
}

Then just call the my_url function.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Avery
  • 79
  • 1
  • 1
5

I use the following function to get the current, full URL. This should work on IIS and Apache.

function get_current_url() {

  $protocol = 'http';
  if ($_SERVER['SERVER_PORT'] == 443 || (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on')) {
    $protocol .= 's';
    $protocol_port = $_SERVER['SERVER_PORT'];
  } else {
    $protocol_port = 80;
  }

  $host = $_SERVER['HTTP_HOST'];
  $port = $_SERVER['SERVER_PORT'];
  $request = $_SERVER['PHP_SELF'];
  $query = isset($_SERVER['argv']) ? substr($_SERVER['argv'][0], strpos($_SERVER['argv'][0], ';') + 1) : '';

  $toret = $protocol . '://' . $host . ($port == $protocol_port ? '' : ':' . $port) . $request . (empty($query) ? '' : '?' . $query);

  return $toret;
}
Zuul
  • 16,217
  • 6
  • 61
  • 88
Jrgns
  • 24,699
  • 18
  • 71
  • 77
  • argv won't work if you're not using a CGI-based Apache or IIS, I think. I tried your code above on Apache2 in regular mode (not CGI mode) and was erroring out because $_SERVER['arv'][0] is not an index. Note also that I have full PHP error reporting turned on and these errors were notice errors. – Volomike Mar 17 '10 at 18:00
  • Works like a charm, just needs a little update to prevent errors on the query string parameter: `$query = isset($_SERVER['argv']) ? substr($_SERVER['argv'][0], strpos($_SERVER['argv'][0], ';') + 1) : '';`. I've updated your answer to include this. – Zuul Jan 03 '13 at 13:56
4

REQUEST_URI is set by Apache, so you won't get it with IIS. Try doing a var_dump or print_r on $_SERVER and see what values exist there that you can use.

Peter Bailey
  • 105,256
  • 31
  • 182
  • 206
3

The posttitle part of the URL is after your index.php file, which is a common way of providing friendly URLs without using mod_rewrite. The posttitle is actually therefore part of the query string, so you should be able to get it using $_SERVER['QUERY_STRING']

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Adam Hopkinson
  • 28,281
  • 7
  • 65
  • 99
2

Use the following line on the top of the PHP page where you're using $_SERVER['REQUEST_URI']. This will resolve your issue.

$_SERVER['REQUEST_URI'] = $_SERVER['PHP_SELF'] . '?' . $_SERVER['argv'][0];
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
beniwal
  • 21
  • 1
1

Oh, the fun of a snippet!

if (!function_exists('base_url')) {
    function base_url($atRoot=FALSE, $atCore=FALSE, $parse=FALSE){
        if (isset($_SERVER['HTTP_HOST'])) {
            $http = isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) !== 'off' ? 'https' : 'http';
            $hostname = $_SERVER['HTTP_HOST'];
            $dir =  str_replace(basename($_SERVER['SCRIPT_NAME']), '', $_SERVER['SCRIPT_NAME']);

            $core = preg_split('@/@', str_replace($_SERVER['DOCUMENT_ROOT'], '', realpath(dirname(__FILE__))), NULL, PREG_SPLIT_NO_EMPTY);
            $core = $core[0];

            $tmplt = $atRoot ? ($atCore ? "%s://%s/%s/" : "%s://%s/") : ($atCore ? "%s://%s/%s/" : "%s://%s%s");
            $end = $atRoot ? ($atCore ? $core : $hostname) : ($atCore ? $core : $dir);
            $base_url = sprintf( $tmplt, $http, $hostname, $end );
        }
        else $base_url = 'http://localhost/';

        if ($parse) {
            $base_url = parse_url($base_url);
            if (isset($base_url['path'])) if ($base_url['path'] == '/') $base_url['path'] = '';
        }

        return $base_url;
    }
}

It has beautiful returns like:

// A URL like http://stackoverflow.com/questions/189113/how-do-i-get-current-page-full-url-in-php-on-a-windows-iis-server:

echo base_url();    // Will produce something like: http://stackoverflow.com/questions/189113/
echo base_url(TRUE);    // Will produce something like: http://stackoverflow.com/
echo base_url(TRUE, TRUE); || echo base_url(NULL, TRUE); //Will produce something like: http://stackoverflow.com/questions/

// And finally:
echo base_url(NULL, NULL, TRUE);
// Will produce something like:
//      array(3) {
//          ["scheme"]=>
//          string(4) "http"
//          ["host"]=>
//          string(12) "stackoverflow.com"
//          ["path"]=>
//          string(35) "/questions/189113/"
//      }
SpYk3HH
  • 22,272
  • 11
  • 70
  • 81
0

Everyone forgot http_build_url?

http_build_url($_SERVER['REQUEST_URI']);

When no parameters are passed to http_build_url it will automatically assume the current URL. I would expect REQUEST_URI to be included as well, though it seems to be required in order to include the GET parameters.

The above example will return full URL.

Gajus
  • 69,002
  • 70
  • 275
  • 438
  • 1
    This requires pecl_http. – Omar Abid Nov 15 '13 at 11:17
  • @OmarAbid I recommend it. :-) – Gajus Nov 15 '13 at 13:50
  • I understand your position. But when building scripts that are going to be used in different platforms that you don't have control of, you need to chose something quite standard. – Omar Abid Nov 15 '13 at 14:39
  • 1
    If you are building a library, it is up to you to define the requirements. The original question does not address such scenario at all. Therefore, it makes sense to name all of the alternatives. – Gajus Nov 15 '13 at 14:42
0

I have used the following code, and I am getting the right result...

<?php
    function currentPageURL() {
        $curpageURL = 'http';
        if ($_SERVER["HTTPS"] == "on") {
            $curpageURL.= "s";
        }
        $curpageURL.= "://";
        if ($_SERVER["SERVER_PORT"] != "80") {
            $curpageURL.= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"];
        } 
        else {
            $curpageURL.= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"];
        }
        return $curpageURL;
    }
    echo currentPageURL();
?>
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • It's Working Nice If you No HTTPS then you want to remove it's line. –  Feb 28 '13 at 14:25
0

In my apache server, this gives me the full URL in the exact format you are looking for:

$_SERVER["SCRIPT_URI"]
Huseyin Yagli
  • 9,896
  • 6
  • 41
  • 50
0

Reverse Proxy Support!

Something a little more robust. Note It'll only work on 5.3 or greater.

/*
 * Compatibility with multiple host headers.
 * Support of "Reverse Proxy" configurations.
 *
 * Michael Jett <mjett@mitre.org>
 */

function base_url() {

    $protocol = @$_SERVER['HTTP_X_FORWARDED_PROTO'] 
              ?: @$_SERVER['REQUEST_SCHEME']
              ?: ((isset($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] == "on") ? "https" : "http");

    $port = @intval($_SERVER['HTTP_X_FORWARDED_PORT'])
          ?: @intval($_SERVER["SERVER_PORT"])
          ?: (($protocol === 'https') ? 443 : 80);

    $host = @explode(":", $_SERVER['HTTP_HOST'])[0]
          ?: @$_SERVER['SERVER_NAME']
          ?: @$_SERVER['SERVER_ADDR'];

    // Don't include port if it's 80 or 443 and the protocol matches
    $port = ($protocol === 'https' && $port === 443) || ($protocol === 'http' && $port === 80) ? '' : ':' . $port;

    return sprintf('%s://%s%s/%s', $protocol, $host, $port, @trim(reset(explode("?", $_SERVER['REQUEST_URI'])), '/'));
}
user1949536
  • 574
  • 5
  • 6