miércoles, 19 de septiembre de 2012

Enviar errores 500 cuando el php detecta errores


Hola amiguitos, despues de unos meses de inactividad bloguera vuelvo a vosotros para escribir sobre una problematica con la que seguro más de uno, se ha encontrado.

Esta no es ni más ni menos que el control de los status code que php devuelve ante un error y el cacheo de los mismos cuando no lo deseamos.


Sin más preambulos, al turrón:

Tenemos que distinguir entre dos tipos de errores, los "parser errors", que son los errores detectados en tiempo de compilación por el interprete antes de ser ejecutado el script, como por ejemplo un syntax error y los "fatal error", son errores detectados en tiempo de ejecución, como por ejemplo una funcion que no existe o el include de un fichero que no existe.


Un parser error siempre escupe un 500 Internal Server Error, en cambio un fatar error depende del valor de la variable display_errors. Si display_errors está desacitvada, la valor del script sera un error 500, por el contrario si está activada el error es pintado por pantalla y un 200 Ok es devuelto por el servidor.

Cuando tienes un sistema de caches por delante es bastante importante que esos errores no se cacheen por lo que seria interesante el que el status code cuando un error es detectado sea un 500, ya que el comportamiento normal de un sistemas de caches es no cachear esos codigos.

Para conseguir esto y puesto que no puedes garantizar siempre que a algún desarrollador se le haya colado un display_errors a On en alguna parte del código, lo que proponemos es lo siguiente.

En el php.ini existe la directiva auto_prepend_file, en esta directiva le puedes pasar un script php para ser ejecutado antes del php principal.
Para este proposito vamos a configurar esta directiva asi:

  auto_prepend_file = /etc/php5/apache2/prepend.php


En contenido de /etc/php5/apache2/prepend.php es el siguiente:

  <?php
  function my_error_handler_manda_500()
  {
        $error=error_get_last();
        if (!empty($error)) {
                header('HTTP/1.1 500 Internal Server Error');
                die();
        }
  }
  register_shutdown_function("my_error_handler_manda_500");
  ?>

Como podemos ver aqui, lo que estamos haciendo es crear una funcion que nos pinta un error 500 en caso de que se haya generado algún error por el php principal. Esta funcion es lanzada desde la funcion de php register_shutdown_function que se ejecuta siempre al finaliar un script.

Para que esto funcione la directiva output_buffering debe estar activada (*) ya que las cabeceras deben ser sobreescritas.

(*) El activar el output_buffering podria llegar a causar al usuario una sensacion inicial de lentitud en la carga de la página ya que lo que hace es almacenar en el buffer todo la pñagina hasta que esta preparada para ser pintada.