362 votos

¿Cómo puedo detectar un error fatal de PHP?

Puedo usar set_error_handler() para detectar la mayoría de los errores de PHP, pero no funciona para los errores fatales ( E\_ERROR ), como llamar a una función que no existe. ¿Hay alguna otra forma de detectar estos errores?

Estoy tratando de llamar mail() para todos los errores y estoy ejecutando PHP 5.2.3.

453voto

user259973 Puntos 3255

Registrar los errores fatales mediante register_shutdown_function que requiere PHP 5.2+:

register_shutdown_function( "fatal_handler" );

function fatal_handler() {
  $errfile = "unknown file";
  $errstr  = "shutdown";
  $errno   = E_CORE_ERROR;
  $errline = 0;

  $error = error_get_last();

  if( $error !== NULL) {
    $errno   = $error["type"];
    $errfile = $error["file"];
    $errline = $error["line"];
    $errstr  = $error["message"];

    error_mail(format_error( $errno, $errstr, $errfile, $errline));
  }
}

Tendrá que definir el error_mail y format_error funciones. Por ejemplo:

function format_error( $errno, $errstr, $errfile, $errline ) {
  $trace = print_r( debug_backtrace( false ), true );

  $content  = "<table><thead bgcolor='#c8c8c8'><th>Item</th><th>Description</th></thead><tbody>";
  $content .= "<tr valign='top'><td><b>Error</b></td><td><pre>$errstr</pre></td></tr>";
  $content .= "<tr valign='top'><td><b>Errno</b></td><td><pre>$errno</pre></td></tr>";
  $content .= "<tr valign='top'><td><b>File</b></td><td>$errfile</td></tr>";
  $content .= "<tr valign='top'><td><b>Line</b></td><td>$errline</td></tr>";
  $content .= "<tr valign='top'><td><b>Trace</b></td><td><pre>$trace</pre></td></tr>";
  $content .= '</tbody></table>';

  return $content;
}

Utilice Correo Rápido para escribir el error_mail función.

Véase también:

95voto

keparo Puntos 13747

PHP no le proporcionará ningún medio convencional para la captura de errores fatales porque realmente no debería ser atrapado . Es decir, no debe intentar recuperarse de un error fatal. La coincidencia de cadenas en un buffer de salida es definitivamente desaconsejable.

Llamar a la función mail() desde un método de gestión de errores también resulta problemático. Si tuviera muchos errores, su servidor de correo se cargaría de trabajo, y podría encontrarse con una bandeja de entrada muy complicada. Para evitar esto, podrías considerar ejecutar un cron para escanear los registros de errores periódicamente y enviar las notificaciones correspondientes. También puedes buscar un software de monitorización del sistema, como Nagios .


Para hablar de la parte sobre el registro de una función de apagado:

Es cierto que puedes registrar una función de apagado, y esa es una buena respuesta.

El punto aquí es que usted no debe tratar de recuperarse de los errores fatales, especialmente no mediante el uso de una expresión regular contra su buffer de salida. Yo estaba respondiendo a la respuesta aceptada que enlazaba con una sugerencia en PHP.net que ya ha sido modificada o eliminada.

Esa sugerencia era usar una regex contra el buffer de salida durante el manejo de la excepción, y en el caso de un error fatal (detectado por la coincidencia contra cualquier texto de error configurado que pudiera estar esperando), tratar de hacer algún tipo de recuperación o continuar el procesamiento. Eso no sería una práctica recomendada (creo que por eso tampoco encuentro la sugerencia original. O la he pasado por alto, o la comunidad PHP la ha rechazado).

Puede ser que valga la pena notar que las versiones más recientes de PHP (alrededor de la 5.1) parecen llamar a la función de apagado antes, antes de que la llamada de retorno al búfer de salida sea invocada. En la versión 5 y anteriores, el orden era el inverso (la llamada de retorno al búfer de salida era seguida por la función de apagado). Además, desde la versión 5.0.5 (que es muy anterior a la versión 5.2.3 del autor de la pregunta), los objetos se descargan mucho antes de que se llame a la función de apagado registrada, por lo que no podrá confiar en sus objetos en memoria para hacer mucho.

Así que registrar una función de apagado está bien, pero el tipo de tareas que debería realizar una función de apagado se limita probablemente a un puñado de procedimientos de apagado suaves.

Lo más importante aquí son algunas palabras de sabiduría para cualquiera que se tropiece con esta pregunta y vea el consejo en la respuesta originalmente aceptada. No regex su salida buffer.

81voto

periklis Puntos 4978

acaba de llegar a esta solución (PHP 5.2.0+):

register_shutdown_function('shutdownFunction');

function shutDownFunction() { 
    $error = error_get_last();
    if ($error['type'] == 1) {
        //do your stuff     
    } 
}

Diferentes tipos de error definidos en http://www.PHP.net/manual/en/errorfunc.constants.PHP

24voto

sakhunzai Puntos 2399

Bueno, parece que es posible atrapar los errores fatales de otra manera :)

ob_start('fatal_error_handler');

function fatal_error_handler($buffer){
    $error=error_get_last();
    if($error['type'] == 1){
        // type, message, file, line
        $newBuffer='<html><header><title>Fatal Error </title></header>
                    <style>                 
                    .error_content{                     
                        background: ghostwhite;
                        vertical-align: middle;
                        margin:0 auto;
                        padding:10px;
                        width:50%;                              
                     } 
                     .error_content label{color: red;font-family: Georgia;font-size: 16pt;font-style: italic;}
                     .error_content ul li{ background: none repeat scroll 0 0 FloralWhite;                   
                                border: 1px solid AliceBlue;
                                display: block;
                                font-family: monospace;
                                padding: 2%;
                                text-align: left;
                      }
                    </style>
                    <body style="text-align: center;">  
                      <div class="error_content">
                          <label >Fatal Error </label>
                          <ul>
                            <li><b>Line</b> '.$error['line'].'</li>
                            <li><b>Message</b> '.$error['message'].'</li>
                            <li><b>File</b> '.$error['file'].'</li>                             
                          </ul>

                          <a href="javascript:history.back()"> Back </a>                          
                      </div>
                    </body></html>';

        return $newBuffer;

    }

    return $buffer;

}

14voto

hipertracker Puntos 1417

No se puede lanzar una excepción dentro de una función de cierre registrada como esa:

<?php
function shutdown() {
 if (($error = error_get_last())) {
   ob_clean();
   throw new Exception("fatal error");
  }
}

try {
  $x = null;
  $x->method()
} catch(Exception $e) {
  # this won't work
}
?>

Pero puede capturar y redirigir la solicitud a otra página.

<?php
function shutdown() {
 if (($error = error_get_last())) {
   ob_clean();
   # raport the event, send email etc.
   header("Location: http://localhost/error-capture");
   # from /error-capture, you can use another redirect, to e.g. home page
  }
}
register_shutdown_function('shutdown');

$x = null;
$x->method()
?>

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X