So many options for self-referencing URLs in PHP. Which one should you use?
In PHP, if you need a self-referencing URL to point to the current script (for example, in a form submission ACTION) you have several options —
- $_SERVER[‘PHP_SELF’]
- $_SERVER[‘SCRIPT_NAME’]
- $_SERVER[‘REQUEST_URI’]
- getenv(‘SCRIPT_NAME’)
- getenv(‘SCRIPT_URL’)
- getenv(‘REQUEST_URI’)
Which one should you use? The manual skimps on any advice.
So off I went to micro-time these options in a loop. Basically, I echo the script path 2000 times in each of these ways, and came up with varying results. Following is the code used:
<?
$timeArray = array();
// PHP_SELF
$start_time = array_sum(explode(’ ‘,microtime()));
for ($i = 0; $i < 2000; $i++){ echo ‘<! — ’ . $_SERVER[‘PHP_SELF’] . ‘ — >’; }
$end_time = array_sum(explode(’ ‘,microtime()));
array_push ($timeArray, bcsub($end_time, $start_time, 2). ’ seconds taken by PHP SELF ($_SERVER)’);
// SCRIPT_NAME
$start_time = array_sum(explode(’ ‘,microtime()));
for ($i = 0; $i < 2000; $i++){ echo ‘<! — ‘. $_SERVER[‘SCRIPT_NAME’] .’ — >’; }
$end_time = array_sum(explode(’ ‘,microtime()));
array_push ($timeArray, bcsub($end_time, $start_time, 2). ’ seconds taken by SCRIPT NAME ($_SERVER)’);
// GETENV
$start_time = array_sum(explode(’ ‘,microtime()));
for ($i = 0; $i < 2000; $i++){ echo ‘<! — ’ . getenv(‘SCRIPT_NAME’) .’ — >’;}
$end_time = array_sum(explode(’ ‘,microtime()));
array_push ($timeArray, bcsub($end_time, $start_time, 2). ’ seconds taken by SCRIPT NAME (GETENV) ’);
// SCRIPT URL
$start_time = array_sum(explode(’ ‘,microtime()));
for ($i = 0; $i < 2000; $i++){ echo ‘<! — ’ . getenv(‘SCRIPT_URL’) .’ — >’;}
$end_time = array_sum(explode(’ ‘,microtime()));
array_push ($timeArray, bcsub($end_time, $start_time, 2). ’ seconds taken by SCRIPT URL (GETENV)’);
// REQUEST URI
$start_time = array_sum(explode(’ ‘,microtime()));
for ($i = 0; $i < 2000; $i++){ echo ‘<! — ’ . $_SERVER[‘REQUEST_URI’].’ — >’; }
$end_time = array_sum(explode(’ ‘,microtime()));
array_push ($timeArray, bcsub($end_time, $start_time, 2). ’ seconds taken by REQUEST URI ($_SERVER) ’);
// GETENV
$start_time = array_sum(explode(’ ‘,microtime()));
for ($i = 0; $i < 2000; $i++){ echo ‘<! — ’ . getenv(‘REQUEST_URI’) .’ — >’;}
$end_time = array_sum(explode(’ ‘,microtime()));
array_push ($timeArray, bcsub($end_time, $start_time, 2). ’ seconds taken by REQUEST URI (GETENV) ’);
// DISPLAY RESULTS
sort($timeArray);
reset($timeArray);
echo "\n\n\n".’<p><span style="color:#f00;"><b>IN ASCENDING ORDER:</b></span> </p><ol>’;
for ($i=0;$i<sizeof($timeArray);$i++) {echo ‘<li>’.$timeArray[$i].’</li>’;}
echo ’</ol>’;
?>
So, PHP_SELF, SCRIPT_NAME or GETENV?
ON LINUX, WITH PHP AS CGI
IN ASCENDING ORDER:
- 0.00 seconds taken by SCRIPT URL (GETENV)
- 0.02 seconds taken by REQUEST_URI (GETENV)
- 0.17 seconds taken by REQUEST URI ($_SERVER)
- 0.17 seconds taken by SCRIPT NAME (GETENV)
- 0.32 seconds taken by SCRIPT NAME
($_SERVER) - 0.65 seconds taken by PHP SELF ($_SERVER)
ON LINUX, WITH PHP AS MODULE
IN ASCENDING ORDER:
- 0.23 seconds taken by REQUEST URI (GETENV)
- 0.27 seconds taken by SCRIPT URL (GETENV)
- 0.29 seconds taken by SCRIPT NAME (GETENV)
- 0.44 seconds taken by REQUEST URI ($_SERVER)
- 1.93 seconds taken by PHP SELF ($_SERVER)
- 3.43 seconds taken by SCRIPT NAME ($_SERVER)
ON WINDOWS, WITH PHP AS CGI/FastCGI
IN ASCENDING ORDER:
- 0.05 seconds taken by SCRIPT NAME ($_SERVER)
- 0.09 seconds taken by PHP SELF ($_SERVER)
- 0.12 seconds taken by REQUEST URI (GETENV)
- 0.17 seconds taken by SCRIPT NAME (GETENV)
- 0.17 seconds taken by SCRIPT URL (GETENV)
- 0.49 seconds taken by REQUEST URI ($_SERVER)
ON WINDOWS, WITH PHP AS APACHE MODULE
IN ASCENDING ORDER:
- 0.00 seconds taken by PHP SELF ($_SERVER)
- 0.04 seconds taken by SCRIPT NAME ($_SERVER)
- 0.26 seconds taken by SCRIPT URL (GETENV)
- 0.35 seconds taken by REQUEST URI ($_SERVER)
- 0.44 seconds taken by SCRIPT NAME (GETENV)
- 0.63 seconds taken by REQUEST URI (GETENV)
Summary
Note that the exact time taken is not important because the above testing (Linux) was done on different hosting environments, of course with different CPU capabilities. What matters is the relative time (i.e., which option is fastest).
It seems from above results that Windows generally seems to point towards using $_SERVER variables [‘PHP_SELF’] or [‘SCRIPT_NAME’].
But Linux setups seem to have a preference for GETENV. If you use PHP as an Apache Module on Linux (which seems to be the most prevalent setup on hosting systems) then REQUEST_URI may be good. If you use it as a CGI, SCRIPT_URL may be. But importantly, both REQUEST_URI and SCRIPT_URL outpace SCRIPT_NAME as well as $_SERVER variables on Linux!
Why this is so? Will add to this note when I come up with a good reasoning.
This post is tagged Tips/Tricks

19 Comments
thanks for the tip ;-)
This is silly, you should use $_SERVER because the information is already available in a variable, there is no need to call getenv() when that’s the case. There is NO way that using getenv() will be faster than calling on a variable. I believe these the test results are bogus.
Funny you should say that because I performed this little test after posting a message such as yours on thelist (http://lists.evolt.org ) last week. Assuming you did not get the idea from my own post, have you even tried running the above code on your servers? I would love to know how it performs on your setup before dismissing it so quickly.
When PHP is running as a module, especially on *nix variants, perhaps the environment variables are in-memory, which I would think is a very compelling reason to make getenv() function perform the way it does.
Martin, I used PHP 4.3.2 on all setups. The CGI version on Linux is fast because it’s from a friend’s dedicated server. Windows versions are fast because they are on localhost. As I said in the summary to this note, please pay attention to the RELATIVE times, not absolute times.
useful! thanks although some explanation about why this happans would be cool.
I think the results for the module version are ok, as is the speculation about environment variables. I am on Solaris. Thanks for the pointer.
anyone tried to see how these results change when you’re constantly refreshing the page?
they are _RANDOMLY_ sorted.
you know.. these tests with microtime() are just for fun.
use Apache Bench and _maybe_ you will see some difference.
but I do really doubt.
Tony, as I have made adequately clear I am not exactly popping champagne corks at a whole new discovery. This is something I noticed, and OVER MANY REPITIONS I may add, so if you have experienced otherwise, that info is most welcome but please be kind enough to let us know what OS you are working with.
(1) Linux, apache module, PHP running as a module — I have NOT seen the order changing one bit regardless of how many times you refresh. Windows XP pro, PHP running as a module — ditto. No change when you refresh.
(2) If you run a script to refresh this script automatically and see the results, and then see minor changes in the sorting order, that doesnt mean much because you may be experiencing internal caching of executed code. It *is* thus important which one you choose to use.
Actually there are many differences across PHP CGI and PHP Module so this is not surprising, but interesting.
I had a problem with cookies. CGI version likes cookies to be set with “setcookie” function like this (I had to investigate this issue further when my host moved from PHP’s Apache module to PHPSUEXEC which requires CGI version of PHP) — $cookieLife = 60000000;
setcookie(“a”, “50”, time()+$cookieLife);
setcookie(“b”, “60”, time()+$cookieLife);
But with a PHP module, you would be better off using the header commands:
$cookieLife = 60000000;
$cookieExpire = gmstrftime(“%A, %d-%b-%Y %H:%M:%S GMT”,time()+$cookieLife);
header(“Set-Cookie: a=50; expires=$cookieExpire”);
header(“Set-Cookie: b=60; expires=$cookieExpire”);
Hope this helps someone.
Thanks for leaving the note Ben. Btw, one good way of setting cookies’ expiry date is like this:
time() + (3600*24*365)
More intuitive that way.
is there a way to get the complete url-string, including GET-parameters ??
something like: http://www.google.com/search?q=some+text&sourceid=opera&num=0&ie=utf-8&oe=utf-8
I was wondering this too.
You could do it manually but if there is a function that can do it for you that would be great.
Klemens,
use $_SERVER[“REQUEST_URI”]
look at phpinfo();
i think this test is useless because each of them returns different result on different platforms
for example in windows : /file.php?var=1&var2=2
windows XP, php 5.01 as apache2 modules
$_SERVER[‘PHP_SELF’] =/file.php
$_SERVER[‘SCRIPT_NAME’] =/file.php
$_SERVER[‘REQUEST_URI’] =/file.php?var=1&var2=2
gx, the test is not to check the return value but to test the performance of the functions.
ya gotta love fools who come in, read the first two responses, and then blurt out the obvious. what a common waste.
anyhow, i’ll confirm approximately the same results on:
1. redhat8 on p2 400mhz, 512m, php500rc1 apache2051
2. redhat72 on p3 500, 512m, php504 apache2055
3. ubuntu504/debian p200 64m php504 apache 2055
Note the following:
“$_SERVER[‘PHP_SELF’] and $_SERVER[‘SCRIPT_NAME’] may not always be set correctly.
Some web hosts implement php as a CGI in such a way that they can turn it on or off for each virtual domain. Several $_SERVER and $_ENV variable values may be incorrect for documents in subdirectory subdomains of these virtual domains.”
see: http://us2.php.net/reserved.variables
Great Site - really useful information!+
Thank you for your site. I have found here much useful information…
Incoming Links