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)
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.
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
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));