2010-08-21 12 views
6

Estoy tratando de configurar un servicio similar a rubular, pero con PHP como el idioma que usa la familia de funciones preg. Tomará una entrada regex, una cadena de prueba, y ejecutará preg_match().Captura de errores de compilación de expresiones regulares

¿Cómo puedo averiguar si se ha producido un error de compilación (por ejemplo, expresiones regulares no válidas) y, en caso afirmativo, cuál fue el error? Normalmente se tirará advertencias como:

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

pcre_last_error() es totalmente inútil aquí, puesto que devolverá 0 (PREG_NO_ERROR) si la expresión regular falla al compilar.

Una opción que estoy considerando es utilizar el almacenamiento en búfer de salida para capturar la advertencia, pero tiene que haber una manera mejor.

Respuesta

2

Lo mejor que puede hacer es omitir el mensaje de error con @, verificar el valor de retorno y, si es false, llamar al error_get_last.

También podría escribir su propio contenedor alrededor de pcre_compile. Recibe punteros para el almacenamiento de códigos de error y cadenas. No debería ser muy difícil; preg_match es una envoltura delgada.

+0

'error_get_last()' es lo suficientemente bueno :) – NullUserException

0

Puede comprobar fácilmente los errores de compilación de expresiones regulares en PHP registrando su propio controlador de errores. Escribí un probador de expresiones regulares de PHP que detecta errores de compilación de expresiones regulares y los informa al usuario sin mostrar información confidencial como nombres de archivos y números de línea. La parte clave aquí es que un controlador de error personalizado puede atrapar errores de compilación de expresiones regulares. No tiene que lanzar la excepción o atraparla. El resto es una demostración conveniente.

Uso set_error_handler() para registrar una función que arroje una ErrorException. Capté la excepción cuando ejecuté preg_match(), luego uso la información de rastreo para verificar que la excepción fue lanzada desde el mismo archivo, línea y función de la que ejecuto preg_match() (si no, un error o excepción fue causada por algo más bien como una llamada a función diferente en la misma línea o PHP se está quedando sin memoria). Luego solo envío el mensaje de error al usuario.

Tenga en cuenta que este script realmente ejecuta la función de expresión regular utilizando una función variable. Ingrese la entrada, la expresión regular sin la barra inicial y final, y los modificadores por separado.

Aquí está el código completo:

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