PHP_SELF vs PATH_INFO vs SCRIPT_NAME vs REQUEST_URI

Viewed 84347

I am building a PHP application in CodeIgniter. CodeIgniter sends all requests to the main controller: index.php. However, I don't like to see index.php in the URI. For example, http://www.example.com/faq/whatever will route to http://www.example.com/index.php/faq/whatever. I need a reliable way for a script to know what it's address is, so it will know what to do with the navigation. I've used mod_rewrite, as per CodeIgniter documentation.

The rule is as follows:

RewriteEngine on
RewriteCond $1 !^(images|inc|favicon\.ico|index\.php|robots\.txt)
RewriteRule ^(.*)$ /index.php/$1 [L] 

Normally, I would just check php_self, but in this case it's always index.php. I can get it from REQUEST_URI, PATH_INFO, etc., but I'm trying to decide which will be most reliable. Does anyone know (or know where to find) the real difference between PHP_SELF, PATH_INFO, SCRIPT_NAME, and REQUEST_URI? Thanks for your help!

Note: I've had to add spaces, as SO sees the underscore, and makes it italic for some reason.

Updated: Fixed the spaces.

9 Answers

Some practical examples of the differences between these variables:
Example 1. PHP_SELF is different from SCRIPT_NAME only when requested url is in form:
http://example.com/test.php/foo/bar

[PHP_SELF] => /test.php/foo/bar
[SCRIPT_NAME] => /test.php

(this seems to be the only case when PATH_INFO contains sensible information [PATH_INFO] => /foo/bar) Note: this used to be different in some older PHP versions (<= 5.0 ?).

Example 2. REQUEST_URI is different from SCRIPT_NAME when a non-empty query string is entered:
http://example.com/test.php?foo=bar

[SCRIPT_NAME] => /test.php
[REQUEST_URI] => /test.php?foo=bar

Example 3. REQUEST_URI is different from SCRIPT_NAME when server-side redirecton is in effect (for example mod_rewrite on apache):

http://example.com/test.php

[REQUEST_URI] => /test.php
[SCRIPT_NAME] => /test2.php

Example 4. REQUEST_URI is different from SCRIPT_NAME when handling HTTP errors with scripts.
Using apache directive ErrorDocument 404 /404error.php
http://example.com/test.php

[REQUEST_URI] => /test.php
[SCRIPT_NAME] => /404error.php

On IIS server using custom error pages
http://example.com/test.php

[SCRIPT_NAME] => /404error.php
[REQUEST_URI] => /404error.php?404;http://example.com/test.php

The PHP documentation can tell you the difference:

'PHP_SELF'

The filename of the currently executing script, relative to the document root. For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar would be /test.php/foo.bar. The __FILE__ constant contains the full path and filename of the current (i.e. included) file. If PHP is running as a command-line processor this variable contains the script name since PHP 4.3.0. Previously it was not available.

'SCRIPT_NAME'

Contains the current script's path. This is useful for pages which need to point to themselves. The __FILE__ constant contains the full path and filename of the current (i.e. included) file.

'REQUEST_URI'

The URI which was given in order to access this page; for instance, '/index.html'.

PATH_INFO doesn't seem to be documented...

PATH_INFO is only available when using htaccess like this:

Example 1

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]

Remains the same

[SCRIPT_NAME] => /index.php

Root

http://domain.com/

[PHP_SELF]     => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)
[REQUEST_URI]  => /
[QUERY_STRING] => 

Path

http://domain.com/test

[PHP_SELF]     => /index.php/test
[PATH_INFO]    => /test
[REQUEST_URI]  => /test
[QUERY_STRING] => 

Query String

http://domain.com/test?123

[PHP_SELF]     => /index.php/test
[PATH_INFO]    => /test
[REQUEST_URI]  => /test?123
[QUERY_STRING] => 123

Example 2

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php?url=$1 [L,QSA]

Remains the same

[SCRIPT_NAME]  => /index.php
[PHP_SELF]     => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)

Root

http://domain.com/

[REQUEST_URI]  => /
[QUERY_STRING] => 

Path

http://domain.com/test

[REQUEST_URI]  => /test
[QUERY_STRING] => url=test

Query String

http://domain.com/test?123

[REQUEST_URI]  => /test?123
[QUERY_STRING] => url=test&123

Example 3

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(([a-z]{2})|(([a-z]{2})/)?(.*))$ index.php/$5 [NC,L,E=LANGUAGE:$2$4]

or

RewriteRule ^([a-z]{2})(/(.*))?$ $3 [NC,L,E=LANGUAGE:$1]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !^(favicon\.ico|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]

Remains the same

[SCRIPT_NAME] => /index.php

Root

http://domain.com/

[PHP_SELF]          => /index.php
[PATH_INFO] IS NOT AVAILABLE (fallback to REQUEST_URI in your script)
[REQUEST_URI]       => /
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] IS NOT AVAILABLE

Path

http://domain.com/test

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /test
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] => 

Language

http://domain.com/en

[PHP_SELF]          => /index.php/
[PATH_INFO]         => /
[REQUEST_URI]       => /en
[QUERY_STRING]      => 
[REDIRECT_LANGUAGE] => en

Language path

http://domain.com/en/test

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /en/test
[REDIRECT_LANGUAGE] => en

Language Query string

http://domain.com/en/test?123

[PHP_SELF]          => /index.php/test
[PATH_INFO]         => /test
[REQUEST_URI]       => /en/test?123
[QUERY_STRING]      => 123
[REDIRECT_LANGUAGE] => en

You may want to look into the URI Class and make use of $this->uri->uri_string()

Returns a string with the complete URI.

For example, if this is your full URL:

http://example.com/index.php/news/local/345

The function would return this:

/news/local/345

Or you could make use of the segments to drill down specific areas without having to come up with parsing/regex values

Personally I use the $REQUEST_URI as it references the URI entered and not the location on the server's disc.

If you ever forget which variables do what, you can write a little script that uses phpinfo() and call it from a URL with a query string. Since server software installations present the variables that PHP returns it's always a good idea to check the machine's output in case rewrites at the server config file are causing different results than expected. Save it as something like _inf0.php:

<?php
    $my_ip = '0.0.0.0';

   if($_SERVER['REMOTE_ADDR']==$my_ip){
     phpinfo();
   } else {
     //something
   }

Then you would call /_inf0.php?q=500

Backup a second, you've taken the wrong approach to begin with. Why not just do this

RewriteEngine on
RewriteCond $1 !^(images|inc|favicon\.ico|index\.php|robots\.txt)
RewriteRule ^(.*)$ /index.php?url=$1 [L]

instead? Then grab it with $_GET['url'];

Related