声明 ;我完全了解eval的陷阱和“邪恶”,包括但不限于:性能问题,安全性,可移植性等。
问题
阅读eval上的PHP手册......
eval()返回NULL,除非返回 在评估的代码中调用,其中 case传递给return的值是 回。如果有解析错误 评估的代码,eval()返回 FALSE并执行以下操作 代码继续正常。它不是 可能会捕获一个解析错误 eval()使用set_error_handler()。
简而言之,除了返回false之外没有错误捕获,这非常有帮助,但我可以做得更好!
原因
我正在研究的网站功能的一部分依赖于执行表达式。我不想通过沙盒或执行模块的路径,所以我结束了使用eval。在你喊“如果客户变坏了怎么办?!”之前知道客户非常信任;他不想破坏自己的网站,任何获得此功能的人都拥有服务器,无论eval如何。
客户端知道Excel中的表达式,并不是解释这些差异的问题,但是,有某种形式的警告几乎是标准功能。
这是我到目前为止所做的:
define('CR',chr(13));
define('LF',chr(10));
function test($cond=''){
$cond=trim($cond);
if($cond=='')return 'Success (condition was empty).'; $result=false;
$cond='$result = '.str_replace(array(CR,LF),' ',$cond).';';
try {
$success=eval($cond);
if($success===false)return 'Error: could not run expression.';
return 'Success (condition return '.($result?'true':'false').').';
}catch(Exception $e){
return 'Error: exception '.get_class($e).', '.$e->getMessage().'.';
}
}
备注
那么,您还会添加什么来进一步帮助用户?是否有任何进一步的解析功能可以更好地查明可能的错误/问题?
克里斯。
答案 0 :(得分:14)
由于PHP 7 eval()将为语法错误生成ParseError
异常:
try {
$result = eval($code);
} catch (ParseError $e) {
// Report error somehow
}
在PHP 5中,eval()将生成一个解析错误,该错误是特殊的,不会中止执行(因为解析错误通常会这样做)。但是,它也无法通过错误处理程序捕获。假设display_errors=1
:
ob_start();
$result = eval($code);
if ('' !== $error = ob_get_clean()) {
// Report error somehow
}
答案 1 :(得分:12)
我找到了一个很好的替代方案/答案。
首先,让我先说一下,当我设置error_reporting(E_ALL)时,nikic的建议有效;通知显示在PHP输出中,并且由于OB,它们可以被捕获。
接下来,我发现了这个非常有用的代码:
/**
* Check the syntax of some PHP code.
* @param string $code PHP code to check.
* @return boolean|array If false, then check was successful, otherwise an array(message,line) of errors is returned.
*/
function php_syntax_error($code){
if(!defined("CR"))
define("CR","\r");
if(!defined("LF"))
define("LF","\n") ;
if(!defined("CRLF"))
define("CRLF","\r\n") ;
$braces=0;
$inString=0;
foreach (token_get_all('<?php ' . $code) as $token) {
if (is_array($token)) {
switch ($token[0]) {
case T_CURLY_OPEN:
case T_DOLLAR_OPEN_CURLY_BRACES:
case T_START_HEREDOC: ++$inString; break;
case T_END_HEREDOC: --$inString; break;
}
} else if ($inString & 1) {
switch ($token) {
case '`': case '\'':
case '"': --$inString; break;
}
} else {
switch ($token) {
case '`': case '\'':
case '"': ++$inString; break;
case '{': ++$braces; break;
case '}':
if ($inString) {
--$inString;
} else {
--$braces;
if ($braces < 0) break 2;
}
break;
}
}
}
$inString = @ini_set('log_errors', false);
$token = @ini_set('display_errors', true);
ob_start();
$code = substr($code, strlen('<?php '));
$braces || $code = "if(0){{$code}\n}";
if (eval($code) === false) {
if ($braces) {
$braces = PHP_INT_MAX;
} else {
false !== strpos($code,CR) && $code = strtr(str_replace(CRLF,LF,$code),CR,LF);
$braces = substr_count($code,LF);
}
$code = ob_get_clean();
$code = strip_tags($code);
if (preg_match("'syntax error, (.+) in .+ on line (\d+)$'s", $code, $code)) {
$code[2] = (int) $code[2];
$code = $code[2] <= $braces
? array($code[1], $code[2])
: array('unexpected $end' . substr($code[1], 14), $braces);
} else $code = array('syntax error', 0);
} else {
ob_end_clean();
$code = false;
}
@ini_set('display_errors', $token);
@ini_set('log_errors', $inString);
return $code;
}
似乎很容易就能完成我所需要的(耶!)。
答案 2 :(得分:7)
如何测试eval()中的解析错误:
$result = @eval($evalcode . "; return true;");
如果$result == false
,$evalcode
有解析错误且未执行&#39;则返回true&#39;部分。显然$evalcode
一定不能 返回 本身,但有了这个技巧,你可以有效地测试表达式中的解析错误......
答案 3 :(得分:2)
你也可以尝试这样的事情:
$filePath = '/tmp/tmp_eval'.mt_rand();
file_put_contents($filePath, $evalCode);
register_shutdown_function('unlink', $filePath);
require($filePath);
因此,$ evalCode中的任何错误都将由错误处理程序处理。
答案 4 :(得分:2)
好消息::As of PHP 7,eval()
现在*如果所评估的代码无效,则会抛出ParseError
异常:
try
{
eval("Oops :-o");
}
catch (ParseError $err)
{
echo "YAY! ERROR CAPTURED: $err";
}
* 好吧,然后...;)