Nadav
Nadav

Reputation: 1145

Variable variables in PHP allow for illegal variable names?

I found what appears to be an abusable bug in the PHP language. When creating variable variables a seemingly illegal variable can be declared and then handled as long as you keep accessing it as a variable variable. Example:

${'0'} = 1;         //I am an illegal variable called $0
${'0'}++;           //I can be accessed and manipulated.
var_dump(${'0'});   //Output: int(2)

This behavior appears rather odd. It is briefly mentioned in the official documentation for SimpleXml as a way to create variable names that contain hyphens but my example shows it can be abused pretty badly nonetheless.

I would like to know how come this behavior is possible and is tolerated when the code is parsed?

Upvotes: 3

Views: 1722

Answers (2)

lazyCoder
lazyCoder

Reputation: 2561

@Nadav I don't have full idea about that but have a little bit idea,

Remember that curly braces({}) literally mean "evaluate what's inside the curly braces" so, you can squeeze the variable creation like you did ${'0'} = 1 reffered it from this http://php.net/manual/en/language.variables.php#73373

PHP stores variable in the array form, if you want to check then use $GLOBALS(an array) is the super global variable which has all the reference of the variables present in the script, it stores variable name as key and value as variable value, suppose below case:

<?php
    ${'0'} = 1; // here php stores it as 0th index in the array
    ${'1'} = 2; // here php stores it as 1th index in the array
    $b = "I am b"; // here php stores it as bth index in the array
    echo "<pre>";
    print_r($GLOBALS);

output:

Array
(
    [_GET] => Array
        (
        )

    [_POST] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [GLOBALS] => Array
 *RECURSION*
    [0] => 1
    [1] => 2
    [b] => I am b
)

Upvotes: 1

Joe
Joe

Reputation: 1696

Internally PHP stores variables (zend_array* symbol_table) in a same data structure that is used for arrays. This allows you to have variable names with the same constraints as array keys.

Eg. Zend API function zend_set_local_var sets a value to symbol table using zend_hash_update, which is a function used to manipulate PHP array types as well.

We can't however allow every character in variable names in PHP source code. That's because lexical analysis must distinguish labels from other tokens. Variable variables offer a workaround for this.

It's not a bug nor a way to abuse anything. That being said, the documentation states that all labels, including variables, must have a regex form [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*, so i wouldn't rely on having arbitrary characters in variable names.

What ${'0'} = 1; actually does, it sets value 1 to the current scope's symbol table at key 0. You can get that particular table with get_defined_vars function. Looking at the source code, we'll see that the function just copies the current symbol table and returns it to caller.

PHP extract function (src) actually checks that keys have a valid label format (by calling php_valid_var_name), so you can't generate variables with funky names using that.

Anyway, even though it's possible to create variables of any name using variable variable syntax (even a variable with no name ${''}), i think it's bad practice. Even worse if a library expects or enforces you to do so. Saying it's a workaround might be a bit overstatement actually. Maybe it should be considered as an implementation detail and an undocumented feature.

Upvotes: 3

Related Questions