PHP_SELF vs PATH_INFO vs SCRIPT_NAME vs REQUEST_URI
Asked Answered
C

10

118

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.

Colostomy answered 11/11, 2008 at 4:0 Comment(0)
U
54

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'

Contains any client-provided pathname information trailing the actual script filename but preceding the query string, if available. For instance, if the current script was accessed via the URI http://www.example.com/php/path_info.php/some/stuff?foo=bar, then $_SERVER['PATH_INFO'] would contain /some/stuff.

Ursala answered 11/11, 2008 at 5:14 Comment(3)
This is most likely not about the PHP documentation but the CGI :) And there PATH_INFO is documented: tools.ietf.org/html/rfc3875#section-4 But there are some known issues that Apache and nginx are not always giving this variable.Befog
Odin's answer below adds useful explanations that are complemented with examples. I find it hard to understand what these variables represent in a general context with a path_info, a query string, some redirection, some aliases, on different operating systems, from CLI vs SERVER, etc.Unsphere
-1 Just as an explanation as to why I downvoted: the entire reason I came to this post is because the documentation is not clear. Odin's answer below provides a clear explanation of the differences between these variables. I feel like it's an insufficient answer to just copy and paste easily found yet also insufficient documentation. I believe most people would have had to already visit the documentation to even know about the list of elements in the $_SERVER variable mentioned above.Melchior
B
255

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
Bombazine answered 28/11, 2008 at 17:59 Comment(11)
+1, "An example is not a way to learn, it's the only way to learn." - I always have to recheck this stuff, very nice research on the 404 errors. =)Toth
+1: 1st time in my life I understood the difference. They should update PHP documentaion with your answerBacon
Example1: [SCRIPT_NAME] => /test.php/ There should be no "/" at the end: Example1: [SCRIPT_NAME] => /test.php Anyway that's what I see in PHP 5.3.6 . Nice examples.Reede
You are correct JohnM2, i have now checked on PHP 5.4 and the result for URL /pinfo.php/first/second?third=fourth is as follows: QUERY_STRING => third=fourth REQUEST_URI => /pinfo.php/first/second?third=fourth SCRIPT_NAME => /pinfo.php PATH_INFO => /first/secondBombazine
I've tested this on 5.2.17 too and there's no / at the end of the SCRIPT_NAME. This seems to be consistent in PHP 5.2-5.4 then, considering editing the answer to reflect that.Evania
You missed off REQUEST_URI vs PHP_SELF here they differ if you request example.com : [REQUEST_URI] => / and [PHP_SELF] => /index.phpQuarry
This is very helpful especially the Example 4 error handling part. Recently I find that some programmers are using REQUEST_URI as conditions, then provide different header/footer respectively. It works in most cases but will have problems with 404/403 pages. I think a better way is to use SCRIPT_NAME to get the REAL requested page on Apache.Bengali
I know that it is not part of the question, but it is useful to mention that [REQUEST_URI] is defined before URL rewriting, including mod_dir rewrite as pointed out by @icc97. [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO] is defined after mod_dir and mod_rewrite, but before aliases are resolved. Aliases can change the complete URL path (which PHP names [PHP_SELF]) to obtain the [SCRIPT_FILENAME], which is the actual script on the file system. To be slightly more complete, let's add that the script can include other files and __FILE__ is the current file.Unsphere
Example 1 also says that [REQUEST_URI] is different from [SCRIPT_NAME] when [PATH_INFO] is not empty. It was understood, but it was not explicitly written. Example [REQUEST_URI] => /test.php/foo.bar, [SCRIPT_NAME] => /test.phpUnsphere
worth noting this apache bug: bz.apache.org/bugzilla/show_bug.cgi?id=40102Bramwell
Also worth putting in an example of domain traversal, as they differ in this way as well. For instance in http://example.com/something/../test.php, the REQUEST_URI will be /something/../test.php and the SCRIPT_NAME will be /test.php. :)Photosphere
U
54

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'

Contains any client-provided pathname information trailing the actual script filename but preceding the query string, if available. For instance, if the current script was accessed via the URI http://www.example.com/php/path_info.php/some/stuff?foo=bar, then $_SERVER['PATH_INFO'] would contain /some/stuff.

Ursala answered 11/11, 2008 at 5:14 Comment(3)
This is most likely not about the PHP documentation but the CGI :) And there PATH_INFO is documented: tools.ietf.org/html/rfc3875#section-4 But there are some known issues that Apache and nginx are not always giving this variable.Befog
Odin's answer below adds useful explanations that are complemented with examples. I find it hard to understand what these variables represent in a general context with a path_info, a query string, some redirection, some aliases, on different operating systems, from CLI vs SERVER, etc.Unsphere
-1 Just as an explanation as to why I downvoted: the entire reason I came to this post is because the documentation is not clear. Odin's answer below provides a clear explanation of the differences between these variables. I feel like it's an insufficient answer to just copy and paste easily found yet also insufficient documentation. I believe most people would have had to already visit the documentation to even know about the list of elements in the $_SERVER variable mentioned above.Melchior
D
27

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
Dogear answered 7/3, 2012 at 11:22 Comment(1)
This answer is written in a way that suggests that only url rewritting can create a path_info, but, of course, the path info can be entered directly in the original URL.Unsphere
R
17

PHP Paths

    $_SERVER['REQUEST_URI']    = Web path, requested URI
    $_SERVER['PHP_SELF']    = Web path, requested file + path info
    $_SERVER['SCRIPT_NAME']    = Web path, requested file
    $_SERVER['SCRIPT_FILENAME']   = File path, requested file
    __FILE__    = File path, current file

Where

  • File path is a system file path like /var/www/index.php, after alias resolution
  • Web path is a server document path like /index.php from http://foo.com/index.php, and may not even match any file
  • Current file means the included script file, not any script that includes it
  • Requested file means the includer script file, not the included one
  • URI is the HTTP request like /index.php?foo=bar, before any URL rewriting
  • Path info is any extra Apache data located after the script name but before the query string

Order of Operation

  1. Client sends server an HTTP request REQUEST_URI
  2. Server performs any URL rewriting from .htaccess files, etc. to get PHP_SELF
  3. Server separates PHP_SELF into SCRIPT_FILENAME + PATH_INFO
  4. Server performs alias resolution and converts the entire url path to a system file path to get SCRIPT_FILENAME
  5. Resulting script file may include others, where __FILE__ refers to the path to the current file
Rouse answered 10/4, 2015 at 5:12 Comment(4)
This is good. Here are my comments. First, both $_SERVER['SCRIPT_NAME'] and $_SERVER['SCRIPT_FILENAME'] are script name, except that the later is after aliases are executed. Second, $_SERVER['PHP_SELF'] is not the script, but the script + the path info. Again, $_SERVER['SCRIPT_NAME'] is the script (before aliases). Finally, it is useful to know at what stage, after or before rewrite-rules, after or before aliases, these variables are defined. See my answer.Unsphere
@Dominic108 I revised my answer based on your suggestions, tidied things up a bit, and added an Order of Operation section. Let me know what you think. Thanks!Rouse
In your order, you have to swap $_SERVER['SCRIPT_NAME'] and  $_SERVER['PHP_SELF'] , because mod_rewrite create the entire path, which is $_SERVER['PHP_SELF'] . The separation occurs next. Note that aliases also consider the entire path to define the script filename, but the separation that defined script_name and path_info already occurred, so they will not be affected.Unsphere
@Dominic108 I revised my answer again. For some reason your edit proposal was rejected, though as far as I know, you are correct that two of my items were out of order. I'm not as familiar with aliases, so I'm relying on your expertise for that part. Thanks again!Rouse
C
5

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

Catamenia answered 11/11, 2008 at 5:9 Comment(1)
Thank you - this is a good idea, but I am using these in a pre-system hook that will need to run before the controller is up and running.Colostomy
I
4

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

Indignant answered 11/11, 2008 at 4:17 Comment(2)
Is it always the complete URI?Colostomy
Typically, you can run into issues with apache on windows, but it's only for URI's that don't resolve.Indignant
U
4

There is very little to add to Odin's answer. I just felt to provide a complete example from the HTTP request to the actual file on the file system to illustrate the effects of URL rewriting and aliases. On the file system the script /var/www/test/php/script.php is

<?php
include ("script_included.php")
?>

where /var/www/test/php/script_included.php is

<?php
echo "REQUEST_URI: " .  $_SERVER['REQUEST_URI'] . "<br>"; 
echo "PHP_SELF: " .  $_SERVER['PHP_SELF'] . "<br>";
echo "QUERY_STRING: " .  $_SERVER['QUERY_STRING'] . "<br>";
echo "SCRIPT_NAME: " .  $_SERVER['SCRIPT_NAME'] . "<br>";
echo "PATH_INFO: " .  $_SERVER['PATH_INFO'] . "<br>";
echo "SCRIPT_FILENAME: " . $_SERVER['SCRIPT_FILENAME'] . "<br>";
echo "__FILE__ : " . __FILE__ . "<br>";  
?>

and /var/www/test/.htaccess is

RewriteEngine On
RewriteRule before_rewrite/script.php/path/(.*) after_rewrite/script.php/path/$1 

and the Apache configuration file includes the alias

Alias /test/after_rewrite/ /var/www/test/php/

and the http request is

www.example.com/test/before_rewrite/script.php/path/info?q=helloword

The output will be

REQUEST_URI: /test/before_rewrite/script.php/path/info?q=helloword
PHP_SELF: /test/after_rewrite/script.php/path/info
QUERY_STRING: q=helloword
SCRIPT_NAME: /test/after_rewrite/script.php
PATH_INFO: /path/info
SCRIPT_FILENAME: /var/www/test/php/script.php
__FILE__ : /var/www/test/php/script_included.php

The following always holds

PHP_SELF = SCRIPT_NAME + PATH_INFO = full url path between domain and query string. 

If there is no mod_rewrite, mod_dir, ErrorDocument rewrite or any form of URL rewriting, we also have

REQUEST_URI = PHP_SELF + ? + QUERY_STRING 

The aliases affect the system file paths SCRIPT_FILENAME and __FILE__, not the URL paths, which are defined before - see exceptions below. Aliases might use the entire URL path, including PATH_INFO. There could be no connection at all between SCRIPT_NAME and SCRIPT_FILENAME .

It is not totally exact that aliases are not resolved at the time the URL path [PHP_SELF] = [SCRIPT_NAME] + [PATH_INFO] is defined, because aliases are considered to search the file system and we know from example 4 in Odin's answer that the file system is searched to determine if the file exists, but this is only relevant when the file is not found. Similarly, mod_dir calls mod_alias to search the file system, but this is only relevant if you have an alias such as Alias \index.php \var\www\index.php and the request uri is a directory.

Unsphere answered 16/12, 2015 at 4:34 Comment(1)
Hi Dominic108, thanks for the revision. I do think it's useful to include the rewrite info. To me it was implied, but to others it may not be that intuitive.Rouse
C
1

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

Cartel answered 23/7, 2018 at 14:46 Comment(0)
T
-1

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'];

Tabanid answered 28/12, 2008 at 2:0 Comment(2)
Why reinvent the wheel? This data is much more easily accessed!Dyandyana
And there is additional complexity if the original request is expected to have a query string. In its current state, the above code will simply overwrite the query string. If you merge query strings (QSA flag) then query string params can potentially be overwritten (for instance, if you needed a url param on the initial request) or worse, be vulnerable to XSS attacks.Nineteenth
L
-1

easy peasy simple answer:

assume scheme://host/path/script.php
after script.php there will be two possiblitiy:
1- query string like scheme://host/path/script.php?qs=a
2- more path info like scheme://host/path/script.php/more/path


now we have a very simple rules:

property what is included e.g.: http://localhost/dashboard/paln5/st1.php/a/b?c=d
REQUEST_URI everything afterward is included /dashboard/paln5/st1.php/a/b?c=d
PHP_SELF just more path included /dashboard/paln5/st1.php/a/b
SCRIPT_NAME nothing afterward is included /dashboard/paln5/st1.php
Leeds answered 23/5, 2023 at 14:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.