捕获正则表达式编译错误

时间:2010-08-21 00:39:06

标签: php regex

我正在尝试设置类似于rubular的服务,但使用PHP作为使用preg系列函数的语言。它将采用输入正则表达式,测试字符串,然后运行preg_match()

如何确定是否发生了编译错误(例如:无效的正则表达式),如果是这种情况,那么错误是什么?通常它会抛出警告,如:

Warning: preg_match() [function.preg-match]: Compilation failed: missing ) at offset x in ****** on line y

pcre_last_error()在这里完全没用,因为如果正则表达式无法编译,它将返回0(PREG_NO_ERROR)。

我正在考虑的一个选项是使用输出缓冲捕获警告,但必须有更好的方法。

2 个答案:

答案 0 :(得分:2)

您可以做的最好的事情是省略@的错误讯息,检查返回值,如果false,请拨打error_get_last

您还可以在pcre_compile周围编写自己的包装器。它接收用于存储错误代码和字符串的指针。不应该太难; preg_match是一个薄的包装器。

答案 1 :(得分:0)

您可以通过注册自己的错误处理程序轻松检查PHP中的正则表达式编译错误。我编写了一个PHP正则表达式测试程序,可以检测正则表达式编译错误并将其报告给用户,而不会显示文件名和行号等敏感信息。这里的关键部分是自定义错误处理程序可以捕获正则表达式编译错误。您不必抛出异常或捕获它。其余的是一个方便的演示。

我使用set_error_handler()来注册抛出ErrorException的函数。我在运行preg_match()时捕获异常,然后使用跟踪信息来验证从我运行preg_match()的同一文件,行和函数抛出异常(如果没有,则错误或异常是由某些东西引起的)否则就像在同一行中调用不同的函数或PHP耗尽内存一样)。然后我只向用户输出错误消息。

请注意,此脚本实际上使用变量函数运行正则表达式函数。输入输入,不带前导和尾部斜杠的正则表达式,以及任何修饰符。

以下是完整代码:

<!DOCTYPE html>
<html>
<head>
    <title>Test</title>
    <style type="text/css">
        body {
            font-family: monospace;
        }

        input[type=text], textarea {
            letter-spacing: .25em;
            font-weight: bold;
            font-size: larger;
        }

        textarea {
            width: 100%;
            height: 25%;
        }

        fieldset {
            display: inline;
        }

        .error {
            color: red;
        }
    </style>
</head>
<body onload="document.getElementById('patterninput').focus();">
    <?php
        // Translate old-style PHP errors to OO approach
        // http://www.php.net/manual/en/class.errorexception.php
        function testRegexErrorHandler($errno, $errstr, $errfile, $errline, $errcontext) {
            throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
        }

        $pattern = isset($_REQUEST["pattern"]) ? $_REQUEST["pattern"] : "";
        $mods = isset($_REQUEST["mods"]) ? $_REQUEST["mods"] : "";
        $input = isset($_REQUEST["input"]) ? $_REQUEST["input"] : "";

        $regex = "/$pattern/$mods";
        $fns = array("match" => "preg_match", "matchall" => "preg_match_all");
        $fnKey = isset($_REQUEST["function"]) ? $_REQUEST["function"] : "matchall";
        $fn = isset($fns[$fnKey]) ? $fns[$fnKey] : "preg_match_all";

        try {
            set_error_handler("testRegexErrorHandler");
            $result = $fn($regex, $input, $matches);
        } catch (Exception $ex) {
            // $ex is used later
        }
        restore_error_handler();
    ?>
    <form action="" method="post">
        <input type="text" size="100" id="patterninput" name="pattern" value="<?php echo htmlspecialchars($pattern); ?>" placeholder="Pattern" />
        <input type="text" size="10" name="mods" value="<?php echo htmlspecialchars($mods); ?>" placeholder="Modifiers" />
        <fieldset><legend>Function</legend>
            <label for="fnmatch">preg_match()</label><input type="radio" name="function" value="match" id="fnmatch" <?php echo $fnKey == "match" ? "checked" : ""; ?> />
            <label for="fnmatchall">preg_match_all()</label><input type="radio" name="function" value="matchall" id="fnmatchall" <?php echo $fnKey == "matchall" ? "checked" : ""; ?> />
        </fieldset>
        <input type="submit" name="submit" />
        <textarea name="input" rows="10" placeholder="Input"><?php echo htmlspecialchars($input); ?></textarea>
    </form>
    <br/>
<?php
if(isset($ex)) {
    $trace = $ex->getTrace();
    if(is_array($trace) && isset($trace[1]) && is_array($trace[1])) {
        $errFn = isset($trace[1]["function"]) ? $trace[1]["function"] : "";
        $errLine = isset($trace[1]["line"]) ? $trace[1]["line"] : "";
        $errFile = isset($trace[1]["file"]) ? $trace[1]["file"] : "";

        if($errFn != "" && $errFn == $fn && $errLine != "" && $errLine == $ex->getLine() && $errFile != "" && $errFile == $ex->getFile() && get_class($ex) == "ErrorException") {
            $regexErr = true;
        }
    }

    if(empty($regexErr)) {
        throw $ex;
    } else {
        echo "<p class=\"error\">The following error has occurred and is probably an error in your regex syntax:<br/>" .htmlspecialchars($ex->getMessage()) ."</p>\n\n";
    }
}

// result will be unset if error or exception thrown by regex function
//  such as if expression is syntactically invalid
if(isset($_REQUEST["submit"]) && isset($result)) {
    echo "Result: $result<br/>\n";
    echo "Matches:<pre>" .htmlspecialchars(print_r($matches, true)) ."</pre>\n\n";
}
?>
</body>
</html>