downloads | documentation | faq | getting help | mailing lists | licenses | wiki | reporting bugs | php.net sites | conferences | my php.net

search for in the

Variable scope  Basics
[edit] Last updated: Fri, 01 Mar 2013

view this page in

Predefined Variables

PHP provides a large number of predefined variables to any script which it runs. Many of these variables, however, cannot be fully documented as they are dependent upon which server is running, the version and setup of the server, and other factors. Some of these variables will not be available when PHP is run on the command line. For a listing of these variables, please see the section on Reserved Predefined Variables.

Warning

In PHP 4.2.0 and later, the default value for the PHP directive register_globals is off. This is a major change in PHP. Having register_globals off affects the set of predefined variables available in the global scope. For example, to get DOCUMENT_ROOT you'll use $_SERVER['DOCUMENT_ROOT'] instead of $DOCUMENT_ROOT, or $_GET['id'] from the URL www.example.com/test.php?id=3 instead of $id, or $_ENV['HOME'] instead of $HOME.

For related information on this change, read the configuration entry for register_globals, the security chapter on Using Register Globals , as well as the PHP » 4.1.0 and » 4.2.0 Release Announcements.

Using the available PHP Reserved Predefined Variables, like the superglobal arrays, is preferred.

From version 4.1.0 onward, PHP provides an additional set of predefined arrays containing variables from the web server (if applicable), the environment, and user input. These new arrays are rather special in that they are automatically global--i.e., automatically available in every scope. For this reason, they are often known as "superglobals". (There is no mechanism in PHP for user-defined superglobals.) The superglobals are listed below; however, for a listing of their contents and further discussion on PHP predefined variables and their natures, please see the section Reserved Predefined Variables. Also, you'll notice how the older predefined variables ($HTTP_*_VARS) still exist. As of PHP 5.0.0, the long PHP predefined variable arrays may be disabled with the register_long_arrays directive.

Note: Variable variables

Superglobals cannot be used as variable variables inside functions or class methods.

Note:

Even though both the superglobal and HTTP_*_VARS can exist at the same time; they are not identical, so modifying one will not change the other.

If certain variables in variables_order are not set, their appropriate PHP predefined arrays are also left empty.



Variable scope  Basics
[edit] Last updated: Fri, 01 Mar 2013
 
 add a note User Contributed Notes Predefined Variables - [40 notes]
up
down
3
dompody [at] gmail [dot] com
7 years ago
To urbanheroes:

version_compare() is only in PHP version 4.1.0 and up. This completely negates your function, since if the version is less than 4.1.0 it will generate an error anyway. The better solution is to do what is stated in the post above yours:

<?php
if (!isset($_SERVER))
{
  
$_GET    = &$HTTP_GET_VARS;
  
$_POST    = &$HTTP_POST_VARS;
  
$_ENV    = &$HTTP_ENV_VARS;
  
$_SERVER  = &$HTTP_SERVER_VARS;
  
$_COOKIE  = &$HTTP_COOKIE_VARS;
  
$_REQUEST = array_merge($_GET, $_POST, $_COOKIE);
}
?>

Include that before everything else in your script and it will fix the flaw.
up
down
1
pinkgothic at gmail dot com
5 years ago
Dealing with "superglobals" and functions is not as straightforward as it may seem when you're doing plenty manipulations.

For example:

<?php
 
function some_other_method() {
    echo
$_REQUEST['id'];
  }
  function
some_method() {
   
$_REQUEST['id'] = 440;
   
some_other_method();
  }
?>

Calling some_method() will cause a warning-level error by PHP informing you that "id" is not set in some_other_method(). However, if you instead use:

<?php
  $_REQUEST
['id'] = 0;
  function
some_other_method() {
    echo
$_REQUEST['id'];
  }
  function
some_method() {
   
$_REQUEST['id'] = 440;
   
some_other_method();
  }
?>

Then the script will echo 440.

In consequence, if you manually attempt to add keys to the superglobals, those keys *aren't* automatically superglobal. The above example isn't very sensible, of course, but this can be a huge gotcha if you're juggling user data between functions and you're unwittingly being forced to work inside a function (e.g. via PHP include in TYPO3).

Unfortunately, global $_REQUEST['id'] won't save you, either - it causes a parse error - nor will a global $_REQUEST change anything after you've set the keys... consequently making it hard to conviniently 'hack' outdated scripts by making them believe they're still running in a different environment.

The only "solution" to this issue is to use parameters.
up
down
1
myfirstname dot barros at gmail dot com
7 years ago
vars in $_REQUEST are *not* a reference to the respective $_POST and $_GET and $_COOKIE ones.

Consider:
site.com/index.php?avar=abc

index.php:
<?php
$_GET
['avar'] = 'b';
print_r($_GET); print('<br>');
print_r($_REQUEST);
?>

output:
Array ( [avar] => 'b' )
Array ( [avar] => 'abc' )
up
down
1
kasey at cornerspeed dowt com
8 years ago
I have a few points to note to (debabratak at softhome dot net).  Firstly, extracting all your variables from the global variable arrays is rather cumbersome and possibly unsafe.  This causes longer run times, and wastes more memory.  Then, your script is starting the session before it parses the superglobals.  Bad things can happen because of this:

<?php

// user sent a GET header with key = secret_access, val = true, so

echo $_GET["secret_access"]; // output: true
echo $secret_access; // output:

session_start();

// in previous logic, you set session variable $secret_access = false

echo $_SESSION["secret_access"]; // output: false
echo $secret_access; // output: false

extract_globals();  // Globals put into "normal" variables

echo $_GET["secret_access"]; // output: true
echo $_SESSION["secret_access"]; // output: false
echo $secret_access; // output: true

// VARIABLES ARE COMPROMISED!
// DO NOT USE $secret_access !
// USE $_SESSION["secret_access"] instead !!!

?>

Secondly, I would like to point out the fact that all $_POST, $_GET, and $_COOKIE variables are intrinsically unsafe anyway.  Users can create their own scripts in the language of their choosing (PHP, ASP, JSP, etc.) that generate those headers to send to your PHP program via socket connections.  PHP cannot determine that these headers are any less valid than the ones sent by a web browser, so it parses them and places them in the $_POST, $_GET, or $_COOKIE variables.

The best practice is to use $_SESSION variables to validate the user before making any decisions based on form data.  e.g.:

<?php
session_start
();
if (isset(
$_SESSION["valid"]))
{
   
// all your program decisions and database interactions can go here
   
if (isset($_POST["button_name"]))
    {
        ...
    }
    ...
}
elseif (isset(
$_POST["submit_login"]))
{
    if ((
$_POST["username"] == "foo") AND ($_POST["password"] == "bar"))
    {
       
$_SESSION["valid"] = true;
        ...
    }
    else
    {
       
session_unset();
       
session_destroy();
       
$error_msg = "Invalid username or password";
       
$result_page = "login.php";
    }
}
elseif (isset(
$logoff))
{
   
session_unset();
   
session_destroy();
   
$success_msg = "You have logged off successfully";
   
$result_page = "login.php";
}
else
{
   
session_unset();
   
session_destroy();
   
$result_page = "login.php";
}
require (
$result_page);
?>

Session variables are orders of magnitude harder to compromise than POST, GET, and COOKIE data, since the server keeps track of session id's, and the session id is unique to each client and somewhat randomly generated.  If security is an ultimate concern, then you need to use SSL in case your traffic can be sniffed (since the session cookie is passed plain text to the client).

In summary, extracting out all the superglobals to normal variable names is not a good idea for reasons of security and ambiguity, not to mention wasted CPU cycles.  For private applications (ones that you don't want just anyone to be able to access), the only ways you can prevent malicious access is to 1) use sessions to ensure that the user is valid (for that page), and 2) use SSL-encryption to prevent session-hijacking.

Kasey

in reply to:
--------------------------------------------------------------
 debabratak at softhome dot net
14-Mar-2003 12:59
After having register_globals = off, I am using the following piece of code to get all the variables created for me. I have put this code in a separate file and just make it require_once() on top of every page.

session_start();
$ArrayList = array("_GET", "_POST", "_SESSION", "_COOKIE", "_SERVER");
foreach($ArrayList as $gblArray)
{
   $keys = array_keys($$gblArray);
   foreach($keys as $key)
   {
       $$key = trim(${$gblArray}[$key]);
   }
}

This pulls out all the possible variables for me, including the predefined variables, so I can keep coding the old style. Note that, this code does not handle the $_FILE.

Hope this helps someone.
up
down
1
Anonymous
9 years ago
In reply to destes at ix dot netcom dot com dot nospam:

It's possible for a HTTP client to spoof HTTP_X_FORWARDED_FOR, and set it to a fake IP number.  It's more secure to use this code and log BOTH the ip and the proxy ip.

if ($_SERVER["HTTP_X_FORWARDED_FOR"]) {
   if ($_SERVER["HTTP_CLIENT_IP"]) {
    $proxy = $_SERVER["HTTP_CLIENT_IP"];
  } else {
    $proxy = $_SERVER["REMOTE_ADDR"];
  }
  $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
} else {
  if ($_SERVER["HTTP_CLIENT_IP"]) {
    $ip = $_SERVER["HTTP_CLIENT_IP"];
  } else {
    $ip = $_SERVER["REMOTE_ADDR"];
  }
}

echo "Your IP $ip<BR>\n";
if (isset($proxy)) {
  echo "Your proxy IP is $proxy<BR>\n";
}
up
down
1
mike at dbeat dot com
12 years ago
If you're running PHP as a shell script, and you want to use the argv and argc arrays to get command-line arguments, make sure you have register_argc_argv  =  on.  If you're using the 'optimized' php.ini, this defaults to off.
up
down
1
johnphayes at gmail dot com
6 years ago
I haven't found it anywhere else in the manual, so I'll make a note of it here - PHP will automatically replace any dots ('.') in an incoming variable name with underscores ('_'). So if you have dots in your incoming variables, e.g.:

example.com/page.php?chuck.norris=nevercries

you can not reference them by the name used in the URI:
//INCORRECT
echo $_GET['chuck.norris'];

instead you must use:
//CORRECT
echo $_GET['chuck_norris'];
up
down
1
sendoshin[at]noodleroni[dot]com
7 years ago
There is one way to safely execute PHP code files without running the risk of compromising your own code.  A prior note pointed out that the code being evaluated would still have access to globals using the global keyword.  While this is a valid point, there's one other approach to be looked at - one which actually gives you much more ability than just unsetting some variable references.  It's known as code parsing.

The specifics would be different and much more complex in a deployed site, but here's an extremely strip-down example of how to restrict access to global variables:

<?php
   
while ($x = stristr ($code_to_eval, "global")) {
       
$temp = substr ($code_to_eval, 1, $x-1);
       
$temp .= substr ($code_to_eval, stristr ($code_to_eval, ";", $x) + 1);
       
$code_to_eval = $temp;
    }
   
$ret_val = eval ($code_to_eval);
?>

Of course, that's just a rudimentary example, and a deployment version would have much more checking involved, but parsing the file before you eval it lets you remove any code you don't want to let run, thus making it as safe as your parsing rules.
up
down
0
fabrizio at bibivu dot com
5 years ago
theonly_DD32, I refined your function a little bit

<?php
   
function long_to_GET($PATH_INFO=''){
       
/**
        * This function converts info.php/a/1/b/2/c?d=4 TO
        * array ( [d] => 4 [a] => 1 [b] => 2 [c] => array ( [d] => 4 ) )
        * got this function from php.net/GLOBALS
        **/
       
if($PATH_INFO=='' && isset($_SERVER['PATH_INFO']) && $_SERVER['PATH_INFO'] != ''){
           
$PATH_INFO = $_SERVER['PATH_INFO'];
        }
        if(
$PATH_INFO != ''){
           
//Split it out.
           
$tmp = explode('/',$PATH_INFO);
           
//Remove first empty item
           
unset($tmp[0]);
           
//Loop through and apend it into the $_GET superglobal.
           
for($i=1;$i<=count($tmp);$i+=2){
                if(
strpos($tmp[$i],'?')!==false){
                   
$tmp1 = explode('?',$tmp[$i]);
                   
parse_str(isset($tmp1[1])?$tmp1[1]:'',$_GET[$tmp1[0]]);
                   
$i--;
                } else {
                   
$_GET[$tmp[$i]] = isset($tmp[$i+1])?$tmp[$i+1]:'';
                }
            }
        }
    }

?>
up
down
0
holger at doessing dot net
6 years ago
On the subject of permalinks and queries:
Say, you use an inexpensive subdomain of (e.g.) www.nice.net, thus www.very.nice.net, and that the domain owner has simply placed a frame at this particular location, linking to the actual address (ugly and subject-to-change) of your site.
Consequently, the actual site URI and various associated hashes and query strings are not immediately visible to the user. Sometimes this is useful, but it also makes bookmarking/permalinking impossible (the browser will only bookmark the static address in the top frame).
However, as far as the query strings go, there is workaround. Instead of providing users with permalinks to the actual URI (e.g. prtcl://weird.and.ugly/~very/ugly.php?stuff=here; may even be subject to change), I provide them with this: prtcl://www.very.nice.net?stuff=here.

In brief, I then use the following code to re-populate the $_GET array:

if (isset($_SERVER['HTTP_REFERER'])) { // If set, this page is running in a frame
    $uri = parse_url($_SERVER['HTTP_REFERER']); // grab URI of parent frame
    $querystring = ($uri['query']) ? $uri['query'] : false; // grab the querystring
    if ($querystring) {
        $vars = explode('&', $querystring); // cut into individual statements
        foreach ($vars as $varstring) { // populate $_GET
            $var = explode('=', $varstring);
            if (count($var) == 2) $_GET[$var[0]] = $var[1];
        }
    } // no, nothing to report from the parent frame
} // no, not using a parent frame today...

If the actual host address is ever changed, users entering the frame (with the nicer address) will be using the new (and ugly) URI, but this way the old query strings will be available to the new address also. The users will never again be bothered by you moving to another neighborhood.
up
down
0
yarco dot w at gmail dot com
6 years ago
And you should know

$_POST is not a reference of $HTTP_POST_VARS

So, if you change $_POST, there are no change to $HTTP_POST_VARS.
<">
gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.