深圳升蓝软件
数据库开发 .Net技术  |  ASP技术 PHP技术 JSP技术 应用技术类   
Hiblue Software

Coding PHP with register_globals Off


March 23,2004
Intended Audience
Introduction
register_globals
How do the variables get to PHP?

From the URL

From a Form

From a Cookie

From the Environment or the Server
Use the superglobals!

Why are they called superglobals?
Other Coding Techniques

Ways to Hack
Summary
About The Author

Intended Audience
Prior to PHP 4.2.0, the default value for the PHP configuration parameter register_globals was On. Many PHP programmers took advantage of the ease of use this configuration provided.

This article is intended for PHP programmers who have, in the past, relied on the register_globals On, and now wish to change their coding style to reflect the new default for this parameter. It will also be of interest to programmers using an ISP hosted PHP environment where they do not control the values of the PHP configuration file.

Introduction
I consider one of the strengths of PHP the easy learning curve. PHP allows for embedding small portions of PHP into an HTML file, allowing HTML authors to ease into the language. PHP has a very C-like syntax, allowing for easy transition of programmers familiar with C. Weak variable typing, the flexibility and power of PHP many extensions, and abundant examples and articles on the Internet also contribute to the easy learning curve for PHP.

One recent change in PHP may increase the learning curve some. With the release of PHP 4.2.0, the default value for register_globals is now Off. This takes away one of the features that made PHP so easy to learn (a problem which it is the goal of this article to rectify).

Why was this done? In a word: security. You code is inherently more stable when you initialize and know where each variable in your source is coming from. Caution must always be taken when receiving input from a user, and allowing the user to arbitrarily make variables in your code is not good coding practice. This is perhaps better explained by the PHP developers themselves in http://www.php.net/release_4_1_0.php (see the section titled SECURITY: NEW INPUT MECHANISM) and http://www.php.net/manual/en/security.registerglobals.php.
register_globals
The register_globals configuration parameter is controlled in your php.ini file. See http://www.php.net/manual/en/configuration.php for more information on the configuration file. The register_globals parameter http://www.php.net/manual/en/configuration.php#ini.register-globals can take two values, On or Off. Prior to PHP version 4.2, On was the default, but this has now changed, and modifying your coding to accommodate this change is the subject of this article.

How do the variables get to PHP?
Experienced PHP programmers who have used URL query parameters, forms and cookies will find this section redundant, and may wish to go directly to the section on superglobals.

Variables come from many sources. Once source is initializing them yourself, $var = ’value’;. Described in the following sections are several other ways to get variables into your script, including as part of the URL, a form, a cookie, or part of the environment the server runs in. These examples are described from the perspective of a server using register_globals On, and you will learn later in the article how and where to get these values with register_globals Off.

From the URL
One of the most common ways to get information is by passing query parameters. The following is the anatomy of a URL (for more information on parsing a URL in PHP see http://www.php.net/manual/en/function.parse-url.php ):

screen.width-550)this.width=screen.width-550" border=0>


Scheme controls the protocol used by the client and server for the request. Http and https are the most common protocols used, but you might specify another like ftp.
User and password information for basic HTTP authentication can be passed as part of the URL.
Host is the IP address or DNS name for the server reference by this URL.
Port is the TCP/IP port to use on the server, 80 is standard for HTTP, and 443 is standard for HTTPS.
Path is the location and name of the script on the server.
Query is parameters passed by the URL.
Fragment is the scroll target within the HTML document.
The portion of the URL we are most interested in here is the query parameters portion. With the register_globals On, the script.php would automatically have $var = ’val’; and $foo = ’bar’; set as global variables for the script to access.

Whenever a query parameter is specified in the script’s URL, PHP will create a global array called $HTTP_GET_VARS. This is an associative array of the key => value pairs from the URL query parameters. From the example above, PHP will automatically create $HTTP_GET_VARS = array (’var’ => ’val’, ’foo’ => ’bar’);.

Since PHP 4.1.0, a global variable called $_GET will contain the same array as $HTTP_GET_VARS. This array is a superglobal and will be discussed in greater detail later in this article.

From a Form
Another very common way to get input variable to a script is from a form on a web page. Included below is an example of how a web page might render, including the HTML source:
screen.width-550)this.width=screen.width-550" border=0>

When a user clicks the "Send!" button, the browser will submit the form to script.php with a post variable called $foo having the value the user entered into the text box on the web form. With register_globals On, the script.php would have $foo = ’bar’; available as a global variable by default.

Similar to the query parameter example, whenever a browser submits a form to a PHP script, PHP will automatically create $HTTP_POST_VARS as an associative array of key => value pairs for all of the form inputs. The example above would result in the automatic creation of $HTTP_POST_VARS[’foo’] = ’bar’;.

With PHP 4.1.0 and greater, the variable $_POST will contain the same associative array.

From a Cookie
Web pages by nature are stateless, meaning that each time a web page is retrieved it is generated using information passed in the request. This fact presented a challenge for early web development, where designers wanted to maintain state throughout an entire interaction with a user, possibly across many web page requests on the site. The concept of cookies was developed to pass the information required to maintain this state, both for the duration of the user’s current browsing session, and longer term by "dropping" a cookie on the user’s hard drive.

If the following code was placed on a script, before any other output was sent, a cookie will be set:

/* Set Cookie for 1 day */
setcookie(’foo’, ’bar’, time()+86400, ’’, $HTTP_HOST);

Note: Astute observers will notice an obsolete global variable in the $HTTP_HOST used in the example. With register_globals = ’off’, this would need to be $_SERVER[’HTTP_HOST’].

A link on this page, to the same server, will pass $foo = ’bar’; as a cookie variable for the script.

From the Environment or the Server
The operating system environment, and the web server, has many variables that can be used by the script. One of the most common uses of a server variable is to retrieve the name of the script itself or, as in the example above, the name of the host.

PHP creates additional associative arrays as $HTTP_ENV_VARS and $HTTP_SERVER_VARS. After PHP 4.1.0, these same arrays are defined in $_ENV and $_SERVER.

Use the superglobals!
Now that you understand how these variables get to PHP, and that they are not automatically created for you by PHP when the register_globals setting Off, it is time to identify what you can do with your coding style to adjust to the new default.

Your first choice is to use the new superglobal arrays, after all, that is what they were added for! This should be your preferred method, especially if you only intend to use the value once in your script (print ’Your IP Address is:’ . $_SERVER[’REMOTE_ADDR’]; ).

If you intend to use a value more than once, you can assign the value to a variable ($mode = $_GET[’mode’]; ) instead of explicitly referencing the superglobal each time.

Why are they called superglobals?
Normally, any variable used in a function is local in scope to that function. This means if you wanted to use the global $HTTP_GET_VARS array values in a function, you would need to first use the statement global $HTTP_GET_VARS; before referencing this array.

Superglobals are an exception to this rule. You may use the variables $_GET, $_POST, $_COOKIE, $_ENV, $_SERVER and $_SESSION without having to reference them as globals first. There is also one additional superglobal array, $_REQUEST. This array contains all of the variables from GET, POST or COOKIE methods (basically anything that could be sent by the user, and which is therefore suspect).

Note: You cannot use a variable variable to access the superglobal arrays in functions. For example, the following code will not work:

<?php
function foo()
{
$sg = ’_GET’;
return ${$sg}[$var];
}
?>

the foo() function described above will not return values from the $_GET superglobal array.

Other Coding Techniques
I found myself wanting to revert back to the easy way of having my variables registered for me. However, knowing the security risks, I instead wrote some helper functions to ease the transition.

The first function I wrote was register() :
<?php
/**
* return a value from the global arrays
*
* @author Jason E. Sweat
* @since 2002-02-05
* @param string $varname
* the name of the variable to register
*
* @param string $defval optional
* the value to return if not found
*
* @return string the value of the variable if
* registered, else the default
*/
function register($varname, $defval=NULL)
{
if (array_key_exists($varname, $_SERVER)) {
$retval = $_SERVER[$varname];
} elseif (array_key_exists($varname, $_COOKIE)) {
$retval = $_COOKIE[$varname];
} elseif (array_key_exists($varname, $_POST)) {
$retval = $_POST[$varname];
} elseif (array_key_exists($varname, $_GET)) {
$retval = $_GET[$varname];
} elseif (array_key_exists($varname, $_ENV)) {
$retval = $_ENV[$varname];
} else {
$retval = $defval;
}

return $retval;
}
?>


This function now allows you to "register" variables you expect to have passed to the script. I normally use this by doing $mode = register(’mode’);. The function is defined to follow the default variables_order parameter from the php.ini file (http://www.php.net/manual/en/configuration.php#ini.variables-order ), and therefore will return an identical result to PHP with register_globals on (if assigned to a variable with the same name as you are registering). This function also allows you to specify a default value you would like to have the variable initialized with if the value is not found in any of the superglobal arrays.

This function had one drawback, it will always return a value, and therefore always initialize a variable to something. I had some instances in my code where I wanted to use isset() to determine if a value had been passed. In order to accommodate this behavior, I used a different function to register the values.

<?php
/**
* set a global variable if the specified get
* or post var exists
*
* @author Jason E. Sweat
* @since 2002-04-25
* @param string $test_vars
* the array of the vars to
* register, will accept a string
* name for a single var as well
*
* @global the variable, if it is set
*/
function getpost_ifset($test_vars)
{
if (!is_array($test_vars)) {
$test_vars = array($test_vars);
}

foreach($test_vars as $test_var) {
if (isset($_POST[$test_var])) {
global $$test_var;
$$test_var = $_POST[$test_var];
} elseif (isset($_GET[$test_var])) {
global $$test_var;
$$test_var = $_GET[$test_var];
}
}
}
?>


This function will allow you to pass an array of strings for variables to register. If any of the variable were passed in either the GET or POST methods, they will be set as global values, otherwise you will still be able to check the values using isset() to see if they were passed.

This function is also particularly good for writing a form handler script since you can initialize an array of values easily (getpost_ifset(array(’username’, ’password’, ’password2’)); ).

Ways to Hack
I can already hear the excuses: "I don’t have enough time", or "The program is third party code and I do not want to learn and maintain it".

If you must hack your way around the register_globals Off default value, I would suggest reading up on the import_request_variables() function (http://www.php.net/manual/en/function.import-request-variables.php) or reviewing some of the reader posted comments related to the extract() function (http://www.php.net/manual/en/function.extract.php).

Summary
You should now be familiar with the various means of getting variables into a PHP script, and a variety of coding methods available to you to accommodate the change of the register_globals default from On to Off. Best of luck to you, and happy (and secure) coding!

About The Author
Jason has worked as an IT professional since graduating from Colorado State University in 1992. He is currently an application developer, and the web master, for a business unit of a fortune 100 company, and maintains a server at home for educational and home business purposes. He currently resides in Iowa with his wife and two children. Please feel free to post any comments or questions below, or send them to [email protected].
Copyright © 2001-2008 Shenzhen Hiblue Software Team All rights reserved