PHP评估和捕获错误(尽可能多)
免责声明;我完全了解eval的缺陷和“弊病”,包括但不限于:性能问题、安全性、可移植性等 问题 正在阅读有关评估的PHP手册 eval()返回NULL,除非返回为空 在求值代码中调用,其中 案例传递给return的值为 返回。如果中存在分析错误 求值代码eval()返回 错误和执行以下内容 代码正常继续。事实并非如此 可能在中捕获分析错误 使用set\u error\u handler()进行eval() 简而言之,除了返回false之外,没有错误捕获,这非常有用,但我相信eI可以做得更好 原因 我正在使用的站点功能的一部分依赖于执行表达式。我不想通过沙盒或执行模块的路径,所以我结束了使用eval。在你大喊“如果客户变坏了怎么办?!”之前,要知道客户是非常值得信任的;他不想破坏自己的网站,任何访问此功能的人几乎都拥有服务器,不管eval如何 客户机知道Excel中的表达式,解释这些小差异并不是问题,但是,具有某种形式的警告几乎是标准功能 这就是我到目前为止所做的:PHP评估和捕获错误(尽可能多),php,exception,parsing,eval,Php,Exception,Parsing,Eval,免责声明;我完全了解eval的缺陷和“弊病”,包括但不限于:性能问题、安全性、可移植性等 问题 正在阅读有关评估的PHP手册 eval()返回NULL,除非返回为空 在求值代码中调用,其中 案例传递给return的值为 返回。如果中存在分析错误 求值代码eval()返回 错误和执行以下内容 代码正常继续。事实并非如此 可能在中捕获分析错误 使用set\u error\u handler()进行eval() 简而言之,除了返回false之外,没有错误捕获,这非常有用,但我相信eI可以做得更好 原因
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().'.';
}
}
注释
- 函数在任何事件中都返回消息字符串
- 代码表达式应该是一行PHP,没有PHP标记,也没有结尾分号
- 新行将转换为空间
- 添加了一个变量来包含结果(表达式应返回true或false,并且为了不与eval的返回冲突,使用了一个temp变量。)
try {
$result = eval($code);
} catch (ParseError $e) {
// Report error somehow
}
在PHP 5中,eval()将生成一个解析错误,该错误的特殊情况是不中止执行(解析错误通常会这样做)。但是,它也不能通过错误处理程序捕获。一种可能是捕获打印的错误消息,假设display\u errors=1
:
ob_start();
$result = eval($code);
if ('' !== $error = ob_get_clean()) {
// Report error somehow
}
对于我的问题,我找到了一个好的选择/答案 首先,让我先说,当我设置错误报告(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;
}
/**
*检查一些PHP代码的语法。
*@param string$code要检查的PHP代码。
*@return boolean | array如果为false,则检查成功,否则返回错误数组(消息、行)。
*/
函数php_语法_错误($code){
如果(!定义(“CR”))
定义(“CR”,“r”);
如果(!已定义(“LF”))
定义(“LF”、“\n”);
如果(!已定义(“CRLF”))
定义(“CRLF”,“\r\n”);
$brages=0;
$inString=0;
foreach(token_get_all(“您也可以尝试以下方法:
$filePath = '/tmp/tmp_eval'.mt_rand();
file_put_contents($filePath, $evalCode);
register_shutdown_function('unlink', $filePath);
require($filePath);
因此,$evalCode中的任何错误都将由错误处理程序处理。如何测试eval()中的解析错误:
如果$result==false
,$evalcode
有一个解析错误,并且不执行“return true”部分。显然$evalcode
不能返回本身的内容,但是使用这个技巧,您可以有效地测试表达式中的解析错误…好消息:,eval()
now*如果评估的代码无效,则抛出ParseError
异常:
try
{
eval("Oops :-o");
}
catch (ParseError $err)
{
echo "YAY! ERROR CAPTURED: $err";
}
*好吧,有一段时间…;)如果你能提供更多关于你将使用什么“表达式”的反馈,也许我们可以提供更多帮助。我可以想出一些很好的标记来验证用户输入;)普通PHP代码?我计划允许对PHP的完全访问,但定义函数和类可能是个例外,这是不需要的。@Sz。尽管如此,我还是建议现在使用(10年时还没有)是的,我确实定义了它们,很抱歉没有提及。修复了上面的代码。至于异常,我很确定这两者都没有,但是,在可能添加了异常之后,这段代码将来可能会失败,所以不管怎样处理它们都不会有任何伤害。我无法找到check\u syntax
php\u check\u syntax
在5.0.5中被删除他们希望您执行类似的操作(“echo”!=
运算符的优先级高于=
。您需要添加括号:(“”!=($error=ob\u get\u clean())
@François如果赋值在RHS上就不会。这就是为什么在这里使用Yoda条件。哇,这看起来不错。我又学到了一点新东西:break
可以有一个参数!我稍后会看一看这段代码以真正理解它的作用。只需注意:如果代码中有严重的解析错误,token\u get\u all
可以自己输出错误,例如,如果您在源代码中使用“\”(在PHP中,它非常好。遗憾的是,它仍然不能提供防止错误函数调用的保护,例如函数名中的简单拼写错误。PHP应该真正考虑在eval()中捕获致命错误)非常聪明的主意!我还没有测试过它,但我会的。你不能在eval
'd代码中捕获解析错误!它只会停止脚本的执行。这对我来说非常有效,即使我的eval()返回一个值。我有$value=eval(“返回”$evalcode.”返回false;
,然后如果($value==false)返回(“错误:“.$evalcode);
当然这意味着evalcode在正常情况下永远不能返回false。但这适合我的使用。
try
{
eval("Oops :-o");
}
catch (ParseError $err)
{
echo "YAY! ERROR CAPTURED: $err";
}