Я пытаюсь настроить службу, похожую на 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
), если регулярное выражение не скомпилируется.
Один из вариантов, который я рассматриваю, – использовать буферизацию вывода для захвата предупреждения, но должен быть лучший способ.
Лучшее, что вы можете сделать, это опустить сообщение об ошибке с @
, проверить возвращаемое значение и, если false
, вызвать error_get_last
.
Вы также можете написать свою собственную оболочку вокруг pcre_compile
. Он получает указатели для хранения кодов ошибок и строк. Не должно быть слишком сложно; preg_match
– это тонкая оболочка.
Вы можете легко проверить ошибки компиляции регулярных выражений в PHP, зарегистрировав собственный обработчик ошибок. Я написал тег регулярного выражения PHP, который обнаруживает ошибки компиляции регулярных выражений и сообщает их пользователю без отображения конфиденциальной информации, такой как имена файлов и номера строк. Ключевая часть здесь заключается в том, что пользовательский обработчик ошибок может улавливать ошибки компиляции регулярных выражений. Вам не нужно бросать исключение или ловить его. Остальное – удобная демонстрация.
Я использую set_error_handler () для регистрации функции, которая генерирует исключение ErrorException. Я поймаю исключение при запуске preg_match (), а затем использую информацию трассировки, чтобы убедиться, что исключение было выбрано из того же файла, строки и функции, из которых я запускаю preg_match () (если нет, ошибка или исключение было вызвано чем-то иначе как другой вызов функции в той же строке или у PHP заканчивается память). Затем я вывожу пользователю сообщение об ошибке.
Обратите внимание, что этот скрипт фактически выполняет функцию regex с помощью переменной функции. Введите ввод, регулярное выражение без ведущей и конечной косой черты и любые модификаторы отдельно.
Вот полный код:
<!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>