PHP: controlador de errores personalizado: manejo de análisis y errores fatales

¿Cómo puedo manejar el análisis sintáctico y los errores fatales usando un manejador de error personalizado ?

Respuesta simple: no puedes. Ver el manual :

Los siguientes tipos de error no pueden manejarse con una función definida por el usuario: E_ERROR, E_PARSE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING y la mayor parte de E_STRICT creada en el archivo donde se llama a set_error_handler ().

Para cualquier otro error, puede usar set_error_handler()

EDITAR:

Dado que parece que hay algunas discusiones sobre este tema, con respecto al uso de register_shutdown_function , deberíamos echar un vistazo a la definición de manejo: Para mí, manejar un error significa detectar el error y reactjsr de una manera que es “agradable” para el usuario y los datos subyacentes (bases de datos, archivos, servicios web, etc.).

Usando register_shutdown_function no puedes manejar un error desde dentro del código donde fue llamado, lo que significa que el código aún dejará de funcionar en el punto donde ocurre el error. Sin embargo, puede presentar al usuario un mensaje de error en lugar de una página en blanco, pero no puede, por ejemplo, revertir nada de lo que hizo su código antes de fallar.

En realidad, puede manejar el análisis sintáctico y los errores fatales. Es cierto que no se invocará la función del controlador de errores que definió con set_error_handler (). La forma de hacerlo es definiendo una función de apagado con register_shutdown_function (). Esto es lo que tengo trabajando en mi sitio web:

File prepend.php (este archivo se agregará previamente a todos los scripts php). Consulte a continuación para obtener sugerencias sobre cómo anteponer archivos a PHP.

 set_error_handler("errorHandler"); register_shutdown_function("shutdownHandler"); function errorHandler($error_level, $error_message, $error_file, $error_line, $error_context) { $error = "lvl: " . $error_level . " | msg:" . $error_message . " | file:" . $error_file . " | ln:" . $error_line; switch ($error_level) { case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_PARSE: mylog($error, "fatal"); break; case E_USER_ERROR: case E_RECOVERABLE_ERROR: mylog($error, "error"); break; case E_WARNING: case E_CORE_WARNING: case E_COMPILE_WARNING: case E_USER_WARNING: mylog($error, "warn"); break; case E_NOTICE: case E_USER_NOTICE: mylog($error, "info"); break; case E_STRICT: mylog($error, "debug"); break; default: mylog($error, "warn"); } } function shutdownHandler() //will be called when php script ends. { $lasterror = error_get_last(); switch ($lasterror['type']) { case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: case E_RECOVERABLE_ERROR: case E_CORE_WARNING: case E_COMPILE_WARNING: case E_PARSE: $error = "[SHUTDOWN] lvl:" . $lasterror['type'] . " | msg:" . $lasterror['message'] . " | file:" . $lasterror['file'] . " | ln:" . $lasterror['line']; mylog($error, "fatal"); } } function mylog($error, $errlvl) { ...do whatever you want... } 

PHP llamará a la función errorHandler () si detecta un error en cualquiera de los scripts. Si el error obliga al script a cerrar inmediatamente, la función shutdownHandler () maneja el error.

Esto está trabajando en el sitio que tengo en desarrollo. Todavía no lo he probado en producción. Pero actualmente está detectando todos los errores que encuentro al desarrollarlo.

Creo que existe el riesgo de detectar el mismo error dos veces, una vez por cada función. Esto podría suceder si un error que estoy manejando en la función shutdownHandler () también fue capturado por la función errorHandler ().

TODO’s:

1 – Necesito trabajar en una mejor función de registro () para manejar los errores con gracia. Como todavía estoy en desarrollo, básicamente estoy registrando el error en una base de datos y haciéndolo eco en la pantalla.

2 – Implementa el manejo de errores para todas las llamadas MySQL.

3 – Implementar el manejo de errores para mi código de JavaScript.

NOTAS IMPORTANTES:

1 – Estoy usando la siguiente línea en mi php.ini para anteponer automáticamente la secuencia de comandos anterior a todos los scripts php:

 auto_prepend_file = "/homepages/45/d301354504/htdocs/hmsee/cgi-bin/errorhandling.php" 

funciona bien.

2 – Estoy registrando y resolviendo todos los errores, incluidos los errores E_STRICT. Creo en desarrollar un código limpio. Durante el desarrollo, mi archivo php.ini tiene las siguientes líneas:

 track_errors = 1 display_errors = 1 error_reporting = 2147483647 html_errors = 0 

Cuando lo publique, cambiaré display_errors a 0 para reducir el riesgo de que mis usuarios vean mensajes de error de PHP desagradables.

Espero que esto ayude a alguien.

Puede rastrear estos errores usando un código como este:

(Los errores de análisis solo se pueden capturar si se producen en otros archivos de script mediante include() o require() , o colocando este código en un auto_prepend_file como han mencionado otras respuestas).

 function shutdown() { $isError = false; if ($error = error_get_last()){ switch($error['type']){ case E_ERROR: case E_CORE_ERROR: case E_COMPILE_ERROR: case E_USER_ERROR: $isError = true; break; } } if ($isError){ var_dump ($error);//do whatever you need with it } } register_shutdown_function('shutdown'); 

De los comentarios de PHP.net en la página http://www.php.net/manual/en/function.set-error-handler.php

Me he dado cuenta de que algunas personas aquí mencionaron que no se pueden capturar los errores de análisis (tipo 4, E_PARSE). Esto no es verdad. Así es como lo hago. Espero que esto ayude a alguien.

1) Cree un archivo “auto_prepend.php” en la raíz web y agregue esto:

  

2) A continuación, agregue este “php_value auto_prepend_file /www/auto_prepend.php” a su archivo .htaccess en la raíz web.

  • asegúrese de cambiar la dirección de correo electrónico y la ruta al archivo.

La secuencia de comandos con error de análisis se interrumpe siempre y no se puede controlar. Entonces, si el script se llama directamente o mediante include / require, no hay nada que puedas hacer. Pero si es invocado por AJAX, flash o de cualquier otra forma, hay una solución alternativa para detectar errores de análisis.

Necesitaba esto para manejar el script swfupload . Swfupload es un flash que maneja cargas de archivos y cada vez que se carga un archivo, llama a PHP para manejar archivos de datos, pero no hay salida de navegador, por lo que el script de manejo de PHP necesita estas configuraciones para fines de depuración:

  • advertencias y avisos ob_start (); al principio y almacenar el contenido en sesión por ob_get_contents (); al final del script de manejo: Esto puede mostrarse en el navegador mediante otro script
  • errores fatales register_shutdown_function () para establecer la sesión con el mismo truco que el anterior
  • analizar errores si ob_get_contents () se encuentra al final de la secuencia de comandos de manejo y el error de análisis anterior, la sesión no se completa (es nula). El script de depuración puede manejarlo de esta manera: if(!isset($_SESSION["swfupload"])) echo "parse error";

Nota 1 null significa is not set para isset()

Según mi experiencia, puede detectar todo tipo de errores, ocultar el mensaje de error predeterminado y mostrar un mensaje de error propio (si lo desea). A continuación se enumeran las cosas que necesita.

1) Un script de nivel inicial / superior, permítanos llamarlo index.php donde almacena sus funciones personalizadas de manejo de errores. Los manejadores de funciones de errores personalizados deben permanecer en la parte superior para que puedan detectar los errores debajo de ellos, me refiero a “debajo” en los archivos inclued.

2) ¡La suposición de que este script superior está libre de errores debe ser verdadera! esto es muy importante, no puede detectar errores fatales en index.php cuando su función personalizada de controlador de errores se encuentra en index.php .

3) Directivas Php (también se deben encontrar en index.php ) set_error_handler("myNonFatalErrorHandler"); #para atrapar errores no fatales register_shutdown_function('myShutdown'); #para atrapar errores fatales ini_set('display_errors', false); #para ocultar los errores mostrados al usuario por php ini_set('log_errors',FALSE); #assuming registramos los errores de nosotros mismos ini_set('error_reporting', E_ALL); # Nos gusta informar todos los errores

mientras estoy en producción (si no estoy equivocado) podemos dejar ini_set('error_reporting', E_ALL); como es para poder registrar el error, al mismo tiempo ini_set('display_errors', false); se asegurará de que no se muestren errores al usuario.

En cuanto al contenido real de las dos funciones a las que me refiero, myNonFatalErrorHandler y myShutdown , no myShutdown contenido detallado aquí para mantener las cosas simples. Además, los otros visitantes han dado muchos ejemplos. Solo muestro una idea muy simple.

 function myNonFatalErrorHandler($v, $m, $f, $l, $c){ $some_logging_var_arr1[]="format $v, $m, $f, ".$err_lvl[$l].", $c the way you like"; //You can display the content of $some_logging_var_arr1 at the end of execution too. } function myShutdown() { if( ($e=error_get_last())!==null ){ $some_logging_var_arr2= "Format the way you like:". $err_level[$e['type']].$e['message'].$e['file'].$e['line']; } //display $some_logging_var_arr2 now or later, eg from a custom session close function } 

en cuanto a $ err_lvl, puede ser:

 $err_lvl = array(E_ERROR=>'E_ERROR', E_CORE_ERROR=>'E_CORE_ERROR', E_COMPILE_ERROR=>'E_COMPILE_ERROR', E_USER_ERROR=>'E_USER_ERROR', E_PARSE=>'E_PARSE', E_RECOVERABLE_ERROR=>'E_RECOVERABLE_ERROR', E_WARNING=>'E_WARNING', E_CORE_WARNING=>'E_CORE_WARNING', E_COMPILE_WARNING=>'E_COMPILE_WARNING', E_USER_WARNING=>'E_USER_WARNING', E_NOTICE=>'E_NOTICE', E_USER_NOTICE=>'E_USER_NOTICE',E_STRICT=>'E_STRICT');