Know Your Variables
January 29, 2015 ยท View on GitHub
In the old age, register_globals used to pour all incoming HTTP variables, extracted from the query string into the global variables. This is over, for the best.
On the other hand, there are still some PHP native functions that are able to create dynamically variables. Applied to externals sources of data, like the query string, they may create interferences in the script.
parse_str
For example, parse_str and the related mb_parse_str, are able to parse a query string, and will return the found variables in a variable passed as second parameter. If the second parameter is omitted, the function will pour those variables into the global registry.
<?php
$queryString = "a=2";
var_dump($a);
// produce NULL and an error
parse_str($queryString);
var_dump($a);
// produce 2
?>
It is recommended to always use parse_str and mb_parse_str with a second argument.
extract
extract takes an array with string keys, and turn each of the key into a variable with the same name.
It is very dangerous to use this function on incoming values, like $_GET, $_POST, $_REQUEST, $_FILES, $_COOKIES, $_SERVER, $_ENV.
The default behavior is set by the second parameter : EXTR_OVERWRITE means that extract will overwrite existing variables. Not only you will lose the current value, but it will be replaced by another value for which you have no control.
If the variable doesn't exist, extract may pollute the current scope with a lot of variables, some of them may interfere with the current one.
It is recommended to use extract as rarely as possible. Arrays which index are fully under control is the right situation for its usage. Using it with the option EXTR_OVERWRITE is highly discouraged.
Alternatives
Finally, it is possible to create lots of variables dynamically with the $$ notation and loops.
<?php
$variableArray = array('a' => 'b', 'c' => 'd');
foreach($variableArray as $name => $value) {
$$name = $value;
}
?>
This is an alternative to the usage of extract and should receive the same recommendations. It should be used rarely, and with arrays whose keys are under control.
Rule Details
The following are considered a warning :
<?php
// parse_str : wrong usage
parse_str($queryString);
// alternative parse_str : wrong usage
parse_str($queryString, $var);
extract($vars);
// register_global look alike : DANGER
extract($_POST, EXTR_SKIP);
// old style register_global : DANGER
foreach($_GET as $name => $value) {
$$name = $value;
}
?>
The following pattern is considered OK :
<?php
// parse_str usage
parse_str($queryString, $vars);
// extract usage
function juggle() {
$args = func_get_args();
$args = array_filter($args, function($k) {
return in_array($k, array('foo', 'bar'));
}, ARRAY_FILTER_USE_KEY);
// will at most produce $a and $b;
extract($args);
}
?>