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

后端 未结 4 615
广开言路
广开言路 2021-01-25 09:04

I have an array of user inputs ($atts) as key=>value pairs. Some of the values could be written as an array expression, such as:

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


        
相关标签:
4条回答
  • 2021-01-25 09:36

    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.

    0 讨论(0)
  • 2021-01-25 09:40

    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()

    0 讨论(0)
  • 2021-01-25 09:43

    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

    0 讨论(0)
  • 2021-01-25 09:57
    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));
    
    0 讨论(0)
提交回复
热议问题