Dec
10

Gestión de Errores en PHP

Ya casi dos años sin Internet en casa me ha hecho controlar un poco esa horrible costumbre de chatear casi todo el día y cambiarla por programar alguna tontería (Re-Inventar la rueda obviamente puff! :P ).

Esta vez estuve pensando como solucionar el problema al que me enfrento cuando estoy a cargo de varios proyectos al mismo tiempo, y me veo en la situación de trabajar casi a ciegas, y sin revisar la entrada de datos detenidamente, o sencillamente si funciona o no… y todo debido a la presión del trabajo.

La idea es encontrar todos los errores de forma rápida, sencilla, y sin tener que navegar o testear mis aplicaciones Web una y otra vez cada que hago modificaciones o nuevas implementaciones.

Se me ocurrió que existiera la posibilidad de anular el gestor de errores de PHP, y crear un propio que me permitiera guardar los errores en un archivo, y luego de cierto tiempo revisarlo y que ahí estuviera cacheados todos los errores ocurridos… Y bueno, después de leer un rato la documentación de PHP terminé configurando el servidor a mi medida desde el php.ini, pero,… pensé ¿Se podrá crear una función aplicable a cada sistema en particular sin revolver todos los errores de todos los sistemas en el mismo log de errores? Bueno, la respuesta fue si, y no solo eso, me encontré con que las posibilidades son mayores: Puedo de cierta forma cachear el contexto en el que el error ha ocurrido, por ejemplo guardar todas las variables en GET y POST. Esto me ayudaría a darme cuenta de si alguien mal intencionado insertó alguna consulta que me halla causado el error (la IP, los datos de sesión de algún usuario, etc…).

Y bueno, he aquí los resultados:

php:
define('error_file','error_log.html');
function error_handler($num_err, $cadena_err, $archivo_err="", $linea_err="", $contexto_err=""){
        /*
            (PHP 4 >= 4.0.1, PHP 5)
            $num_err - nivel de error generado, como un entero.
            $cadena_err - mensaje de error, como una cadena.
           
            PHP >= 4.0.2   
            $archivo_err - nombre del archivo en el que se generó el error, como una cadena.
            $linea_err - número de línea en la que se generó el error, como un entero.
            $contexto_err - matriz que apunta a la tabla activa de símbolos en el punto en el que ocurrio el error.
        */

        $errores = array (
            E_ERROR              => 'E_ERROR',
            E_WARNING            => 'E_WARNING',
            E_PARSE              => 'E_PARSE',
            E_NOTICE             => 'E_NOTICE',
            E_CORE_ERROR         => 'E_CORE_ERROR',
            E_CORE_WARNING       => 'E_CORE_WARNING',
            E_COMPILE_ERROR      => 'E_COMPILE_ERROR',
            E_COMPILE_WARNING    => 'E_COMPILE_WARNING',
            E_USER_ERROR         => 'E_USER_ERROR',
            E_USER_WARNING       => 'E_USER_WARNING',
            E_USER_NOTICE        => 'E_USER_NOTICE'
        );
       
        if(defined('E_STRICT'))
            $errores[E_STRICT] = 'E_STRICT';// PHP > 5
        if(defined('E_RECOVERABLE_ERROR'))
            $errores[E_RECOVERABLE_ERRROR] = 'E_RECOVERABLE_ERRROR';// PHP > 5.2
       
        ob_start();
        echo "<strong>{$errores[$num_err]}</strong>: $cadena_err in <strong>$archivo_err</strong> on line <strong>$linea_err</strong>";
        //echo date(" Y-m-d H:i:s (T)");
       
        //PHP >= 4.0.2, para versiones anteriores habría que analizar si _GET o _POST están definidos y tienen valores
        /*Si el contexto en el que ocurrieron los errores venía acompañado de variables
        por el método _POST, estas se mostrarán en el error.*/

            if(isset($contexto_err['_POST']) and count($contexto_err['_POST'])>0){
                    echo " _POST: ";
                    echo"<pre>";       
                    print_r($contexto_err['_POST']);
                    echo"</pre>";
                }
        /* Lo mismo para _GET */
            if(isset($contexto_err['_GET']) and count($contexto_err['_GET'])>0){
                    echo"<pre>";
                    echo"_GET:";
                    print_r($contexto_err['_GET']);
                    echo"</pre>";
                }
        echo "<br />\n";
        error_log(ob_get_clean(), 3, error_file);
    }

Para utilizarla, solo hay que incluir la función en la aplicación, y decirle a php que la convierta en el manejador de errores de la siguiente forma:

php:
set_error_handler("error_handler");

donde error_handler corresponde al nombre de la función que recibirá todos los datos correspondientes a los errores, para que hagamos lo que queramos con ellos.

Y para las consultas SQL no encontré una forma de hacerlo similar a la anterior, pero si se me ocurrió hacerlo algo así como con el clásico or die(mysql_error) de la siguiente forma:

php:
define('error_file','error_log.html');
    function guardar_error($linea){
        $fh = fopen(error_file,"a");
        fwrite($fh,"<strong>Mysql_error ".mysql_errno()."</strong>: ".mysql_error()." in <strong>{$_SERVER['SCRIPT_FILENAME']}</strong> on line <strong>$linea</strong><br />\n");
    }
Mysql_query($sqlStr) or die(guardar_error(__LINE__));

Y de igual forma, ir controlando un poco los errores.

No tengo idea de si he re-inventado la rueda, o exista una solución parecida a la mia y mejor aún, pero… Me sacó del apuro en el trabajo :D

Cualquier duda, comentario, sugerencia, desacuerdo o mentada es bien recibida. ;-)

4 Comments

Make A Comment
  • a gravatar j0an Said:

    gracias! ya lo tengo a prueba a ver como funciona y si me termina sirviendo (administro cerca de 10 sitios, y me viene barbaro)

    :)

  • a gravatar Victor Said:

    :-D Suerte con eso, cualquier detalle, por aquí puedes comentarle :-)

  • a gravatar Manejo errores con php Said:

    [...] Gestión de Errores en PHP [...]

  • a gravatar tttony Said:

    hola estaba buscando algo similar a esto pero veo no solo se guarda el error en el caso de mysql y no se podria mostrar algo al usuario como: ha ocurrido un error inesperado....

    y bueno tambien para el otro caso si algun usuario como siempre pasa cambia un valor GET o POST deberia de mostrar un mensaje de error personalizado...

    saludos y espero respuestas...

Comments RSS Feed   TrackBack URL

Leave a comment

top