代码之家  ›  专栏  ›  技术社区  ›  Christian

PHP评估和捕获错误(尽可能多)

  •  23
  • Christian  · 技术社区  · 14 年前

    免责声明 ; 我完全了解eval的缺陷和“弊病”,包括但不限于:性能问题、安全性、可移植性等。

    问题

    eval()返回NULL,除非返回值为 在求值代码中调用,其中 case传递给return的值为 返回。如果中存在分析错误 代码正常继续。不是的 可能在中捕捉到解析错误

    简言之,没有错误捕获除了返回假这是非常有帮助的,但我相信可以做得更好!

    原因是什么

    我正在使用的网站功能的一部分依赖于执行表达式。我不想通过沙盒或执行模块的路径,所以我结束了使用eval。在你喊“如果客户变坏了怎么办?!”知道客户是非常值得信任的;他不想破坏自己的站点,任何访问此功能的人几乎都拥有服务器,不管eval如何。

    到目前为止,我的情况是:

    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变量)

    克里斯。

    5 回复  |  直到 14 年前
        1
  •  25
  •   NikiC    6 年前

    因为PHP 7 eval()将生成 ParseError

    try {
        $result = eval($code);
    } catch (ParseError $e) {
        // Report error somehow
    }
    

    在php5中eval()将生成一个解析错误,这是一个特殊情况,不会中止执行(解析错误通常会这样做)。但是,它也不能通过错误处理程序捕获。一种可能是捕获打印的错误消息,假设 display_errors=1 :

    ob_start();
    $result = eval($code);
    if ('' !== $error = ob_get_clean()) {
        // Report error somehow
    }
    
        2
  •  15
  •   Franz Holzinger    8 年前

    我找到了一个很好的选择/答案来回答我的问题。

    首先,我要说的是,当我设置错误报告(E\u 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;
    }
    

        3
  •  9
  •   Robin van Baalen    8 年前

    如何在eval()中测试分析错误:

    $result = @eval($evalcode . "; return true;");
    

    如果 $result == false , $evalcode 有解析错误,不执行“return true”部分。很明显 $评估代码 返回 它本身就是一个问题,但是有了这个技巧,您可以有效地测试表达式中的解析错误。。。

        4
  •  2
  •   barbushin    11 年前

    $filePath = '/tmp/tmp_eval'.mt_rand();
    file_put_contents($filePath, $evalCode);
    register_shutdown_function('unlink', $filePath);
    require($filePath);
    

    所以$evalCode中的任何错误都将由错误处理程序处理。

        5
  •  2
  •   Sz.    6 年前

    好消息: As of PHP 7 , eval() 现在*抛出一个 ParseError

    try
    {
        eval("Oops :-o");
    }
    catch (ParseError $err)
    {
        echo "YAY! ERROR CAPTURED: $err";
    }
    

    好吧,有一段时间……;)