note 90752 deleted from function.eval by danbrown
| From: | danbrown@php.net | Date: | Sun, 17 May 2009 19:49:57 +0000 |
| Subject: | note 90752 deleted from function.eval by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-155275@lists.php.net to get a copy of this message | ||
Note Submitter: tsdodo at gmail dot com
----
Following is my script to validate code safety which also takes into account all lambda function
cases. Call is_eval_safe with PHP code and specify the whitelist for symbols (functions, classes,
etc.) and it returns to you whether or not you should evaluate it.
<?php
/**
* Permits evaluation of only whitelisted syntax
* Require whitelisting:
* declare, eval, global, include, include_once,
* require, require_once, throw, unset, use,
* and all functions, methods, and classes
*
* @param string $scriptText Script to evaluate
* @param array $functions Allowed functions
* @return true if the script is safe to evaluate
*/
function is_eval_safe($scriptText, $symbols)
{
$tokens = token_get_all("<?php $scriptText?>");
return safe_code($tokens, $symbols, 1, count($tokens) - 1);
}
function safe_code($tokens, $symbols, $start, $end) {
static $checkTokens = array(
T_DECLARE=>0, T_EVAL=>0, T_EXIT=>0, T_FUNCTION=>0,
T_GLOBAL=>0, T_INCLUDE=>0, T_INCLUDE_ONCE=>0, T_REQUIRE=>0,
T_REQUIRE_ONCE=>0, T_STRING=>0, T_THROW=>0, T_UNSET=>0,
T_UNSET_CAST=>0, T_USE=>0, T_VARIABLE=>0);
$symbols = array_change_key_case(array_flip($symbols))
+ array('array'=>0, 'true'=>0, 'false'=>0,
'null'=>0);
if(isset($symbols['unset']) || isset($symbols['(unset)'])) {
$symbols += array('unset'=>0, '(unset)'=>0);
}
if(isset($symbols['include']) || isset($symbols['include_once'])
|| isset($symbols['require']) || isset($symbols['require_once'])) {
$symbols += array(
'include'=>0, 'include_once'=>0, 'require'=>0,
'require_once'=>0);
}
for($i = $start; $i < $end; ++$i) {
$token = $tokens[$i];
if(is_array($token) && isset($checkTokens[$token[0]])) {
if($token[0] === T_VARIABLE) {
$i = safe_var($tokens, $symbols, $i + 1, $end);
if($i === false) {
return false;
}
} else if(!isset($symbols[strtolower($token[1])])) {
return false;
}
}
}
return true;
}
function safe_var($tokens, $symbols, $start, $end) {
while($start < $end && $tokens[$start][0] === T_WHITESPACE) {
++$start;
}
if($start >= $end) {
return false;
}
if($tokens[$start] !== '[') {
return $tokens[$start] === '(' ? false : $start;
}
$depth = 1;
for($i = $start + 1; $i < $end; ++$i) {
if($tokens[$i] === '[') {
++$depth;
continue;
}
if($tokens[$i] === ']') {
--$depth;
}
if($depth === 0) {
if(!safe_code($tokens, $symbols, $start, $i - $start - 1)) {
return false;
}
break;
}
}
return safe_var($tokens, $symbols, $i + 1, $end);
}
?>