ene
25
2008

PHP – Manejo de Errores

En cualquier aplicación que desee realizarse, el control de errores es primordial. PHP5 nos ofrece una útil función para ello que es set_error_handler(), esta función nos permitirá enmascarar los errores para podrá crear un log propio de los errores (en caso de no tener acceso al servidor como administrador) o bien como algunos programadores amigos míos dirían “no mostrar los warning y notice del sistema”; aunque es una practica que no promuevo, a veces es necesaria.

La clase que mostrare es para poder manejar los errores y poder mostrarlos a voluntad, así como crear logs cuando lo creamos necesario.

class error{
   var $_contexto;
   var $codigo;

   function error($contexto,$error){
      $this->_contexto =& $contexto;
      $GLOBALS['_OBJETO_CONTEXTO'] =& $this->_contexto;
      $this->activo($error);
   }

Al crear la clase, capturaremos el contexto (que sera el error reportado por PHP) para luego asignarlo a una variable propia de la clase para manejar la mas adelante. Así mismo crearemos una variable global con el contexto y verificaremos con una función propietaria si la clase esta activa o no para mostrar errores. La variable $error es una variable definida por el usuario que nos indicara si mostrara los errores o los ocultara.

    function activo(){
        switch(func_num_args()){
            case 1: $this->_activo = func_get_arg(0); $this->iniciar(); break;
            case 0: return $this->_activo;
        }
    }

Si mostramos los errores, comenzamos con la función iniciar(). Esta función nos permitirá crear con la variable $contexto (donde esta el error) un manejador de errores propio. Capturara el error y lo enviara a otra clase separado por NUMERO de error predefinido por PHP, MENSAJE del error, ARCHIVO donde se produjo el error, LINEA donde se produjo el error en el archivo y por ultimo el MENSAJE o CONTEXTO del error. Con estas variables tipo String separadas podremos crear mas adelante un estilo para mostrarlas.

    function iniciar(){
        if(!function_exists('adm_error')){
           function adm_error($numero, $mensaje, $archivo, $linea, $contexto, $retorna=false){
              $objContexto =& $GLOBALS['_OBJETO_CONTEXTO'];
              $objContexto->inicializar($numero, $mensaje, $archivo, $linea, $contexto);
              if($retorna)
                 return $objContexto->leer();
              else
                 print $objContexto->leer();
           }
        }

        if(!function_exists('errorFatal')){
           function errorFatal($buffer){
              $buffer_temporal = $buffer;
              $texto = strip_tags($buffer_temporal);
              if(preg_match('/Parse error X: (.+) in (.+)? on line (\d+)/', $texto, $c))
                 return adm_error(E_USER_ERROR, $c[1], $c[2], $c[3], "", true);
              if(preg_match('/Fatal error X: (.+) in (.+)? on line (\d+)/', $texto, $c))
                 return adm_error(E_USER_ERROR, $c[1], $c[2], $c[3], "", true);
              return $buffer;
           }
        }
        if( $this->activo() ){
            error_reporting(0);
            ob_start('errorFatal');
            set_error_handler('adm_error');
        } else
            error_reporting(0);
   }

   function exception_handler($exception) {
       echo "Uncaught exception: " , $exception->getMessage(), "\n";
   }
} // Aqui cerramos la clase error

Ahora crearemos la clase Contexto, que resibira los parámetros de la clase Error y los mostrara en un formato predefinido, ademas de crear un LOG en archivos de texto separados por tipo de errores. _ERRORDETALLE y _LOGS son variables globales definidas por el usuario, esto nos ayuda no mostrar los detalles del error (como archivo y codigo) una vez que este en producción el sistema, así mismo a controlar la creación de los logs.

class Contexto
{
    var $_numero = "";
    var $_mensaje = "";
    var $_Estilo = "";
    var $_Imagen = "";
    var $_lineas = 5;
    var $_noticiaEstilo = "style='font-style:italic;font-size:11px;font-family:Arial, Helvetica, sans-serif;margin:5px;color:#000000;padding: 5px;width: 90%;display:block;background-color:#FFFFCC;border: solid 1px #CFCFCF;'";
    var $_noticiaImagen = "<img src='noticia.gif' align='left' hspace='5'>";
    var $_alertaEstilo = "style='font-style:italic;font-size:11px;font-family:Arial, Helvetica, sans-serif;margin:5px;color:#000000;padding: 5px;width: 90%;display:block;background-color:#FDDAD8;border: solid 1px #CFCFCF;'";
    var $_alertaImagen = "<img src='alerta.gif' align='left' hspace='5'>";
    var $_codigoEstilo = "style='width: 90%;background-color: #F1F1F1;margin: 5px;border: solid 1px #CFCFCF;display:block;'";

    function inicializar($numero, $mensaje, $archivo, $linea, $contexto)
    {
       $errorlevels = array(2048=>'Runtime Notice',2047=>'Runtime Notice',1024=>'User Notice',512=>'User Warning',256=>'User Error',128=>'Compile Warning',64=>'Compile Error',32=>'Core Warning',16=>'Core Error',8=>'Notice',4=>'Parsing Error',2=>'Warning',1=>'Error');
       $this->_Estilo=(($numero==2048)or($numero==2047)or($numero==1024)or($numero==8))?$this->_noticiaEstilo:$this->_alertaEstilo;
       $this->_Imagen=(($numero==2048)or($numero==2047)or($numero==1024)or($numero==8))?str_replace('HOSTZOD',_HOSTZOD,$this->_noticiaImagen):str_replace('HOSTZOD',_HOSTZOD,$this->_alertaImagen);
       $this->_Imagen=(_ERRORDETALLE)?$this->_Imagen:substr($this->_Imagen,0,(strlen($this->_Imagen)-1)).' width="23" height="21" style="position:relative;top:-3px">';
       $this->_mensaje = "<pre><div ".$this->_Estilo.">".$this->_Imagen."<b>".$errorlevels[$numero].":</b> ";
       $this->_mensaje.=(_ERRORDETALLE)?"$mensaje<br><b>Archivo:</b> ".substr($archivo,strrpos($archivo, "\\")+1,strlen($archivo))."<br><b>Línea:</b> $linea<br></div><div ".$this->_codigoEstilo.">".$this->obtenerContexto($archivo, (int) $linea)."</div></pre>":date("ymdHis")."</div></pre>";
       if(_LOGS){error_log(date("YmdHis")."|".$_SERVER['HTTP_X_FORWARDED_FOR']."|$mensaje|".substr($archivo,strrpos($archivo, "\\")+1,strlen($archivo))."|$linea\r\n",3,"error".str_replace(" ", "",$errorlevels[$numero]).".log");}
    }

    function leer(){
       return $this->_mensaje;
    }

    function obtenerContexto($archivo, $linea){
        if (!file_exists($archivo)) {
            return "El contexto no puede mostrarse - ($archivo) no existe";
        } elseif ((!is_int($linea)) OR ($linea <= 0)) {
            return "El contexto no puede mostrarse - ($linea) es un número inválido de linea";
        } else {
            $codigo = file( $archivo);
            $lineas = count($codigo);
            $inicio = $linea - $this->_lineas;
            $fin = $linea + $this->_lineas;
            if ($inicio < 0) $inicio = 0;
            if ($fin >= $lineas) $fin = $lineas;
            $largo_fin= strlen($fin) + 2;
            for ($i = $inicio; $i < $fin; $i++){
               $color=($i==$linea-1?"red; font-weight:bold":"black");
               $salida[] = "<span style='color: $color'>".($i+1).str_repeat(" ", $largo_fin - strlen($i)).htmlentities($codigo[$i]).'</span>';
            }
            return trim(join("", $salida));
        }
    }
} 

Para modificar el estilo solo debe modificar las variables $_noticiaEstilo, $_noticiaImagen, $_alertaEstilo y $_alertaImagen. Dejo las que yo suelo usar porque me parecen de buen ver. Los archivos de logs se ubicaran en la misma carpeta. Creo que en si la clase Contexto no necesita mucha explicación, así que me despido esperando que sea de ayuda. Para usar la función simplemente incluimos el archivo y usamos la sentencia: $error = new error( new Contexto );





Written by Antioroku in: Informatica | Etiquetas: , , ,

3 comentarios »

  • Ddaz dice:

    jajaja los que ocultan los warning deberian de morir!!!…. hervidos en aceite caliente

    salu2

    Ddaz  (Seleccionar comentario)

  • wariodiaz dice:

    ps la verdad el ocultar los warning notices y errores es parte de la seguridad de un sistema, creanme con la informacion que provee un warning, noticie o error fatal, alguien que sepa manejar esa informacion y tecnicas de hackin podria vulnerar muy facilmente su sistema o web, creo que ocultar los warnings en un entorno de ejecucion real ya cuando se esta en iternet x ejemplo es bueno ocultarlo, si se esta testeando claro que hay que mostrarlo ya que nos proveen de ayuda para encotrar los errores que tenemos, pero esa misma informacion le puede decir muchas cosas sobre nuestro sistema a un buen hacker, creo que depende de en que entorno vas a ejecutar tu sistema si deves o no deves ocultar esos warnings  (Seleccionar comentario)

  • Antioroku dice:

    Este ejemplo es para un entorno de desarrollo, por ello viene con la opción de activo(), para poder desactivarlo una vez en producción.  (Seleccionar comentario)

RSS feed for comments on this post. TrackBack URL


Leave a Reply

Powered by WordPress | Theme: Aeros 2.0 by TheBuckmaker.com