PHP: Gestión personalizada de errores 4 Febrero, 2008
Esta entrada ha sido publicada por Covi y está archivada en Desarrollo Web, Programación
Hace mucho tiempo que conocía la manera, o más bien la función para establecer el gestor de excepciones, con la que capturar errores en PHP4. Sí, muy tosco y tampoco es que se pudiera hablar de capturar excepciones tal y como lo hace ya PHP5.
El caso es que, aunque me curré cosas muy bonitas, nunca me gustó pues los errores graves escapaban del control de set_error_handler(). Pero como en todo… nunca estamos limitados a lo que el propio lenguaje nos ofrece, quizá hemos caído demasiadas veces en la comodidad del uso de frameworks o quizá sea lo que viene inmediatamente y la encapsulación no nos deje ver un poco más allá… precisamente
El hecho es que si quieres gestionar tus propios errores en PHP4 con niveles de informe de usuario y administrador no es tan difícil como en un principio me parecía… solo era pensar un poco ![]()
Sé que PHP4 está prácticamente muerto pero también sé que muchos servers aún no han migrado
Controla la Gestión de Errores:
Desde que me obligué a convertir el sitio web de La Guardia en un CMS en toda regla y me forcé a usar la metodología MVC, debo decir que me gusta aún más programar para la web… es esa forma de “hacer las cosas bien”, elegantes… aunque mis scripts no lleguen a esos niveles el caso es intentarlo.
El método
Así, el método básico es, desde luego, tener un control de usuarios o al menos del administrador…. obviamente para elegir un nivel de informe de errores. Aunque casi es lo de menos, usaremos por ejemplo las funciones de sesión de usuario en Wordpress y sin tocar WP_error() del que no he estudiado mucho aunque intuyo que sería muy útil.
El funcionamiento sería muy sencillo:
Mediante las funciones de usuario de Wordpress o cualquier otro sistema, o el reconocimiento del nivel administrador, bien mediante IP (avanzada para ips dinámicas en su caso y no muy recomendable en realidad), generaremos dos tipos de nivel de errores:
- Nivel administrativo
- Nivel de usuario.
Primero procederemos a establecer el informe de errores en ninguno.
Chequearemos el usuario y estableceremos los siguientes niveles:
- Admin: E_ALL ^ E_NOTICE (Todos los errores menos los avisos de PHP).
- User: E_USER_NOTICE (Todos los avisos que generemos).
A la vez que proporcionamos el nivel de error estableceremos la función que ofrecerá el reporte de errores para cada tipo:
set_error_handler('miGestorErrores');
Y aquí vienen las carencias de PHP4 que nos obligan a escribir un poco más de código:
En PHP5 solo necesitaríamos una única función de gestión de errores porque podríamos pasar a set_error_handler el nivel que queremos que muestre, en este caso para cada tipo de usuario, por ejemplo:
- Si es el administrador:
set_error_handler('MiGestorErrores',E_ALL); - Sino:
set_error_handler('MiGestorErrores',E_USER_NOTICE);
Pero para PHP4 no podemos hacerlo, ya que no podemos pasarle parámetros a set_error_handler(), así que simplemente nos costará unas cuantas líneas más para crear una función más.
Esto es: una función de gestión de errores de usuario y otra de administrador.
Sí, es muy bruto y se puede y debe pulir… pero por ahora lo dejaremos así para ilustrar.
Así, ya tenemos montado el sistema de informes de error y que podemos usar sin miedo alguno a imprimir errores de php al usuario y sabiendo que tendremos información de todos los errores en modo administrador. Digamos que, omitiendo el tema de seguridad al funcionar como admin, tenemos un entorno de desarrollo y producción en uno
El código:
Bien, en el caso de Wordpress se puede hacer más o menos así:
(Línea 5) Usa tus propios métodos de chequeo del admin, estos son a modo de ejemplo.
El código va bastante explicado y ojo!, le faltaría un poco más de depuración para controlar los datos que llegan a la función,etc,etc,etc…
Si lo usas, es a modo de ejemplo sólo, compruébalo!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | error_reporting(0); // Errores Off inicial. global $userdata; get_currentuserinfo(); if( ($userdata->user_level === 'Nivel del admin') && (//Otros datos que consideres importantes para asegurarte: $userdata->user_login, $userdata->ID, $userdata->user_nicename, etc...) ) : error_reporting(E_ALL ^ E_NOTICE); // Activamos los errores para el admin // establecer el gestor de errores definido. set_error_handler('miAdminGestorErrores'); else : error_reporting(E_USER_NOTICE); // establecer el gestor de errores de USUARIO, nivel mínimo: NOTICE. set_error_handler('miUserGestorErrores'); endif; // función de gestión de errores NIVEL ADMIN: function miUserGestorErrores($num_err, $cadena_err, $archivo_err, $linea_err) { switch ($num_err) { // USER: Este será el Nivel de errores que daremos a los usuarios. // No debemos imprimir nada más que nuestra cadena de error. case E_USER_NOTICE: echo '<strong class="red">Error:</strong> '.$cadena_err."<br />\n"; break; // Para el resto nada. default: return false; break; } /* MUY IMPORTANTE: No ejecutar el gestor de errores interno de PHP */ return true; } // función de gestión de errores NIVEL USER: function miAdminGestorErrores($num_err, $cadena_err, $archivo_err, $linea_err) { switch ($num_err) { // ADMIN: Error Grave: case E_USER_ERROR: echo '<div class="error"><h5>DEBUG: Error Grave</h5> <p>['.$num_err.'] '.$cadena_err.'<br /> Error fatal administrativo en la línea '.$linea_err.' del archivo '.$archivo_err.'<br /> ' . PHP . ' ' . PHP_VERSION . ' (' . PHP_OS . ')<br /> Abortando...</p></div>'; exit(1); break; // ADMIN: Error Alerta: case E_USER_WARNING: echo '<div class="alert"><h5>DEBUG: Advertencia</h5> <p>['.$num_err.'] '.$cadena_err.'<br /> Advertencia administrativa en la línea '.$linea_err.' del archivo '.$archivo_err.'<br /> ' . PHP . ' ' . PHP_VERSION . ' (' . PHP_OS . ')</p></div>'; break; // USER: Este será el Nivel de errores que daremos a los usuarios. // No debemos imprimir nada más que nuestra cadena de error. case E_USER_NOTICE: echo '<strong class="red">Error:</strong> '.$cadena_err."<br />\n"; break; // Para el resto nada. default: return false; break; } /* MUY IMPORTANTE: No ejecutar el gestor de errores interno de PHP */ return true; } |
Conclusiones
Hay que hacer notar que en la función de reporte del administrador, sigo usando E_USER_NOTICE aparte de que con el nivel establecido me llegarán todos menos los avisos de php (E_NOTICE) no cejo en el empeño de usar una única función! …pero será más tarde, ahora no hay tiempo
Por lo demás, creo que el código por sí mismo se explica bastante bien.
En mis scripts simplemente genero mis errores con un simple:
trigger_error('Cadena de Error', Nivel de Error);
por ejemplo:
trigger_error('No se encontró un archivo básico para el sistema', E_USER_ERROR);
Y su versión administrativa:
trigger_error('No se encontró el archivo básico para el sistema: '.$fileRequired, E_USER_ERROR); // Usamos el nivel ERROR FATAL porque se supone el sistema se caería sin ese archivo pero se puede usar E_USER_WARNING para avisos no críticos. Por ejemplo yo lo hago para avisos de cacheos de archivos que sólo quiero ver yo…
MVC
Porqué mencioné MVC???… pues porque teniendo en cuenta que puedes establecer un preformato para tus avisos de error no necesitarás incrustar más código HTML para generar errores.
La función inicial sería el Modelo de datos, las funciones de php, este caso trigger_error, serían los Controladores y tu formato de error predefinido sería la Vista, tu plantilla.
De esta forma puedes llamar a los errores siempre desde funciones con búfer, por ejemplo con, el pesado, eso sí
, sprintf() o guardándolos en búferes de salida, y luego aplicarles el formato de la Vista. Ej:
1 2 3 4 5 6 7 8 9 | // Notices: $msgError = '<strong>No se realizó la caché!</strong><br /> No se pudo <strong>%1$s</strong> en el archivo: %2$s'; $msgNotice = '<strong>Atención!</strong><br /> %1$s.'; $msgOk = '<strong>Caché!.</strong><br /> El archivo <strong>%1$s</strong> se cacheó correctamente!'; |
Y luego generar un error formateado simplemente con:
trigger_error(sprintf($msgError,'escribir',$fileCached), E_USER_WARNING);
Sabiendo que tus errores tienen un formato HTML o una Vista del tipo:
1 2 3 4 5 | <div class="error"><h5>DEBUG: Error Grave</h5> <p>[%NúmeroError%] %TextoError%<br /> Error fatal administrativo en la línea %LineaError% del archivo %ArchivoError%<br /> %DatosOpcionales%<br /> Abortando...</p></div> |
con el que puede trabajar un Diseñador Web
O incluso puedes hacer otra función que gestione a trigger_error, o lo suyo, una clase… pero es ya es liar mucho la breva para eta entrada
Fin / EOF
No soy ni siquiera un entendido… pero lo dicho, a mí me basta y me va muy bien ![]()
Es obvio que cualquier sugerencia será tremendamente bien recibida
pero eso sí, excepcionando las tipo: Usa PHP5!!, recordemos que no tiene porqué depender del administrador del software, repito, del software y que es un ejercicio práctico y de compatibilidad inversa
PD: Como es habitual en mí ya iré coorrigiendo fallos que haya tenido en la entrada y borrrando cagadas ![]()



