PHP: How to turn a string that contains an array expression in an actual array?

寵の児 提交于 2019-12-02 03:13:43

Use the tokenizer:

function stringToArray($str) {
    $array = array();
    $toks = token_get_all("<?php $str");

    if ($toks[1][0] != T_ARRAY || $toks[2] != '(' || end($toks) != ')')
        return null;

    for($i=3; $i<count($toks)-1; $i+=2) {
        if (count($toks[$i]) != 3)
            return null;

        if ($toks[$i][0] == T_WHITESPACE) {
            $i--;
            continue;
        }

        if ($toks[$i][0] == T_VARIABLE || $toks[$i][0] == T_STRING)
            return null;

        $value = $toks[$i][1];
        if ($toks[$i][0] == T_CONSTANT_ENCAPSED_STRING)
            $value = substr($value, 1, strlen($value) - 2);

        $array[] = $value;

        if ($toks[$i + 1] != ',' && $toks[$i + 1] != ')' && $toks[$i + 1][0] != T_WHITESPACE)
            return null;
    }

    return $array;
}

The above will work only for literals. Passing a variable, a constant, an expression, a nested array or a malformed array declaration will return null:

stringToArray('array(1,2)');              // works
stringToArray('array(1,2.4)');            // works
stringToArray('array("foo",2)');          // works
stringToArray('array(\'hello\',2)');      // works
stringToArray('array()');                 // works
stringToArray('array(1,2 + 3)');          // returns null
stringToArray('array(1,2 + 3)');          // returns null
stringToArray('array("foo"."bar")');      // returns null
stringToArray('array(array("hello"))');   // returns null
stringToArray('array($a,$b)');            // returns null
stringToArray('array(new bar)');          // returns null
stringToArray('array(SOME_CONST)');       // returns null
stringToArray('hello');                   // returns null

You can also use the following to check if your string is an array expression or not:

function isArrayExpression($str) {
    $toks = token_get_all("<?php $str");
    return (
        $toks[1][0] == T_ARRAY &&
        $toks[2] == '(' &&
        end($toks) == ')'
    );
}

isArrayExpression('array(1,2,3)');         // true
isArrayExpression('array is cool');        // false
isArrayExpression('array(!!!!');           // false

You can always tweak it to your needs. Hope this helps.

function stringToArray($string) {
        $string = "return " . $string . ";";
        if (function_exists("token_get_all")) {//tokenizer extension may be disabled
            $php = "<?php\n" . $string . "\n?>";
            $tokens = token_get_all($php);
                        foreach ($tokens as $token) {
                $type = $token[0];
                if (is_long($type)) {
                    if (in_array($type, array(
                            T_OPEN_TAG, 
                            T_RETURN, 
                            T_WHITESPACE, 
                            T_ARRAY, 
                            T_LNUMBER, 
                            T_DNUMBER,
                            T_CONSTANT_ENCAPSED_STRING, 
                            T_DOUBLE_ARROW, 
                            T_CLOSE_TAG,
                            T_NEW,
                            T_DOUBLE_COLON
                            ))) {
                        continue;
                    }


                    exit("For your security, we stoped data parsing at '(" . token_name($type) . ") " . $token[1] . "'.");
                }
            }
        }

        return eval($string);
    }

$a='array(10,20)';
print_r(stringToArray($a));

As suggested in the comments of your post, eval() will do what you're looking for. However it's not really practical to store arrays as strings in the first place. If you're looking to make data more portable, I'd recommend using json_encode() or even serialize()

You can use eval, but I would highly recommend not using it, and instead try to rethink your design on a better way to handle the settings. So for your example instead of storing

'setting' => 'array(50,25)'

Could you do something like

'setting' => array('type'=>'array', 'value'=>'50, 25')

then when you load the settings you can do

switch($type)
case 'array'
  $val = explode(', ', $value)

Or something similar

But like others suggested, I would try to save the settings using serialization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!