2010-08-21 12 views
6

Ich versuche, einen Dienst ähnlich rubular einzurichten, aber mit PHP als Sprache, die die Preg-Funktionsfamilie verwendet. Es wird eine Eingabe-Regex, eine Testzeichenfolge und preg_match() ausführen.Erfassen von Regex-Kompilierungsfehlern

Wie kann ich herausfinden, ob ein Kompilierungsfehler aufgetreten ist (zB: ungültige Regex), und wenn das der Fall ist, was war der Fehler? Normalerweise wird es Warnungen werfen wie:

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

pcre_last_error() ist völlig nutzlos hier, da es 0 (PREG_NO_ERROR) zurück, wenn die Regex zu kompilieren schlägt fehl.

Eine Option, die ich in Betracht ziehe, ist die Verwendung der Ausgangspufferung, um die Warnung zu erfassen, aber es muss einen besseren Weg geben.

Antwort

2

Das beste, was Sie tun können, ist die Fehlermeldung mit @ weglassen, überprüfen Sie den Rückgabewert und, wenn false, rufen Sie error_get_last.

Sie könnten auch Ihren eigenen Wrapper um pcre_compile schreiben. Es empfängt Zeiger zum Speichern von Fehlercodes und Strings. Sollte nicht zu schwierig sein; preg_match ist ein dünner Wrapper.

+0

'error_get_last()' ist gut genug :) – NullUserException

0

Sie können leicht in PHP nach Regex-Kompilierungsfehlern suchen, indem Sie Ihren eigenen Fehlerhandler registrieren. Ich habe einen PHP-Regex-Tester geschrieben, der Regex-Kompilierungsfehler erkennt und dem Benutzer meldet, ohne sensible Informationen wie Dateinamen und Zeilennummern anzuzeigen. Der Schlüssel hier ist, dass ein benutzerdefinierter Fehlerhandler Regex-Kompilierungsfehler auffangen kann. Sie müssen die Ausnahme nicht werfen oder abfangen. Der Rest ist eine praktische Demonstration.

Ich verwende set_error_handler(), um eine Funktion zu registrieren, die eine ErrorException auslöst. Ich erhalte die Ausnahme, wenn preg_match() ausgeführt wird, und verwende dann die Ablaufverfolgungsinformationen, um zu überprüfen, ob die Ausnahme von derselben Datei, Zeile und Funktion ausgelöst wurde, von der ich preg_match() aus ausgeführt habe (wenn nicht ein Fehler oder eine Ausnahme von etwas verursacht wurde) sonst wie ein anderer Funktionsaufruf in der gleichen Zeile oder PHP läuft nicht mehr aus dem Speicher). Dann gebe ich nur die Fehlermeldung an den Benutzer aus.

Beachten Sie, dass dieses Skript tatsächlich die Regex-Funktion unter Verwendung einer Variablenfunktion ausführt. Geben Sie die Eingabe, die Regex ohne den führenden und abschließenden Schrägstrich und alle Modifikatoren getrennt ein.

Hier wird der vollständige Code ist:

<!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>