A few days ago, I was contacted by a reader of PHP Solutions, who was confused by the following line of code in the mail-processing script:
${$key} = $temp;
He wanted to know why I had wrapped a variable in curly braces and preceded it with a dollar sign. The answer is that it’s a variable variable. No, that’s not a mistake. The repetition is deliberate. As the PHP Manual explains, it’s sometimes convenient to have variable variable names. Strictly speaking, the curly braces aren’t required. I could have used $$key instead of ${$key}, but the addition of the braces indicates that the double dollar sign is deliberate, and it makes it easier to identify a variable variable within a block of code.
So, what is a variable variable, and why did I use it in this case?
Simply put, a variable variable creates a new variable and uses the value of an existing variable as the new variable’s name. Still confused? Let me explain how it’s used in the mail-processing script.
The script uses a foreach loop to process the contents of the $_POST array, assigning the key and value of each element to $key and $value like this:
foreach($_POST as $key => $value) {
Let’s say the first element in the $_POST array is $_POST['name'] and its value is “David”, $key is “name” and $value is “David”. Inside the loop, $value is subjected to some processing, and the result is stored as $temp. Since $key is “name”, ${$key} becomes $name, and it’s assigned the value of $temp (“David”).
If the next element in the array is $_POST['country'], ${$key} becomes $country, and it is assigned the value that was originally stored in $_POST['country']. In other words, this is a simple way of converting $_POST array elements into simple variables. HOWEVER, it’s extremely insecure to use this technique on its own.
You must verify the name of each $_POST array element before using it as a variable variable. The simple way to do this is to create an array listing the name of each input element in your form, for example:
$expected = array('name', 'email', 'comments');
Then, before creating the variable variable, check that the name is in the $expected array:
if (in_array($key, $expected)) {
${$key} = $temp;
}
This prevents an attacker from injecting spurious variables into your code. If $key is not in the $expected array, the variable variable is not used.
The code in PHP Solutions also uses two other arrays, $required and $missing, to check if required fields have been completed. The full code looks like this:
$expected = array('name', 'email', 'comments');
$required = array('name', 'comments');
$missing = array();
foreach ($_POST as $key => $value) {
// assign to temporary variable and strip whitespace if not an array
$temp = is_array($value) ? $value : trim($value);
// if empty and required, add to $missing array
if (empty($temp) && in_array($key, $required)) {
$missing[] = $key;
} elseif (in_array($key, $expected)) {
// otherwise, assign to a variable of the same name as $key
${$key} = $temp;
}
}
When using this technique, if you add extra fields to your form, don’t forget to add their names to the $expected array. It’s also important to validate the values stored in the simple variables before using them.