2010-08-21 14 views
6

Próbuję skonfigurować usługę podobną do rubular, ale z PHP jako języka używającego rodziny preg funkcji. Będzie to wymagało wejściowego wyrażenia regularnego, ciągu testowego i uruchomienia preg_match().Przechwytywanie błędów kompilacji regex

Jak mogę się dowiedzieć, czy wystąpił błąd kompilacji (np. Nieprawidłowe wyrażenie regularne), a jeśli tak, to jaki był błąd? Normalnie będzie rzucać ostrzeżenia jak:

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

pcre_last_error() jest tutaj całkowicie bezużyteczne, ponieważ zwróci 0 (PREG_NO_ERROR) jeśli regex nie skompilować.

Jedną z opcji, którą rozważam, jest zastosowanie bufora wyjściowego do przechwycenia ostrzeżenia, ale musi być lepszy sposób.

Odpowiedz

2

Najlepsze, co można zrobić, to pominąć komunikat o błędzie za pomocą @, sprawdzić wartość zwracaną i, jeśli false, zadzwonić pod numer error_get_last.

Możesz również napisać własną okładkę wokół numeru pcre_compile. Otrzymuje wskaźniki do przechowywania kodów błędów i łańcuchów. Nie powinno być zbyt trudne; preg_match to cienkie opakowanie.

+0

'error_get_last()' jest wystarczająco dobre :) – NullUserException

0

Możesz łatwo sprawdzić błędy kompilacji regex w PHP, rejestrując swój własny moduł obsługi błędów. Napisałem tester regex PHP, który wykrywa błędy kompilacji regex i zgłasza je użytkownikowi bez wyświetlania poufnych informacji, takich jak nazwy plików i numery linii. Kluczową częścią jest to, że niestandardowy moduł obsługi błędów może pułapkować błędy kompilacji regex. Nie musisz wyrzucać wyjątku ani go łapać. Reszta to wygodna demonstracja.

Używam set_error_handler(), aby zarejestrować funkcję, która zgłasza wyjątek ErrorException. Przechwytuję wyjątek podczas uruchamiania preg_match(), a następnie używam informacji o śledzeniu do sprawdzenia, czy wyjątek został zgłoszony z tego samego pliku, linii i funkcji, z której uruchamiam preg_match() z (jeśli nie, błąd lub wyjątek został spowodowany przez coś inaczej jak inne wywołanie funkcji w tej samej linii lub brak pamięci w PHP). Następnie wysyłam tylko komunikat o błędzie do użytkownika.

Należy zauważyć, że ten skrypt faktycznie uruchamia funkcję regex za pomocą funkcji zmiennej. Wprowadź dane wejściowe, wyrażenie regularne bez przedniego i końcowego ukośnika oraz dowolne modyfikatory osobno.

Oto pełny kod:

<!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> 
Powiązane problemy