* @version 3.0 * @copyright http://creativecommons.org/licenses/by-sa/3.0/br/ * */ class MyErrorHandler { /** * Endereço de e-mail a qual a mensagem de erro será enviada * @var string */ private $mail_to; /** * Endereço de e-mail do remetente * @var string */ private $mail_from='no-reply@noreply.com.br'; /** * Endereço de e-mail para resposta * @var string */ private $mail_reply_to='no-reply@noreply.com.br'; /** * Define quais erros deverem ser reportados * NOTA: Os seguintes tipos de erro não podem ser manuseados * por uma função definida pelo usuário: E_ERROR, E_PARSE, * E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR e E_COMPILE_WARNING. * @var array */ private $user_errors = array( E_WARNING, // E_NOTICE, E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, // E_STRICT, // E_RECOVERABLE_ERROR ); /** * Erros a serem ignorados em ambiente diferente de desenvolvimento * @var array */ private $ignore_errors = array(E_NOTICE,E_WARNING); /** Enviar o erro para um arquivo de log * O segundo parâmetro da função errorlog controla para onde será enviado * a mensagem * '0' A mensagem é enviada para o sistema de log do PHP * usando o sistema de log do sistema operacional ou para um arquivo, * dependendo do que estiver definido na diretiva error_log. * Esta é a opção padrão. * * '1' A mensagem é enviada para o endereço de email no terceiro parâmentro. * Este é o unico tipo de mensagem onde o quarto parâmetro extra_headers é usado. * Este tipo de mensagem usa a mesma função interna que a função mail() usa. * * '2' A mensagem é enviada através de conexão de debug do PHP. * Esta opção só esta disponível se o debug remoto estiver ativado. * Neste caso, o terceiro parâmetro define o nome do servidor ou * endereço IP e opcionalmente, o número da porta, do socket recebendo a * informação de debug. * * '3' A mensagem é adicionada ao arquivo definido no terceiro parâmentro. * @var int */ private $log_mode=0; /** * Arquivo a qual se deseja que o erro seja enviado * @var string */ private $log_file; /** * Url que se deseja redirecionar o fluxo do processamento em caso de erro * evitando as famigeradas telas brancas * @var string */ private $redirect_to; /** * Armazena o manipulador existentes antes de se registrar * para que possa ser restaurado em caso de problemas * @var mixed */ private $old_handler; /** * Variável que guarda uma auto instancia (singleton) * @var myErrorHandler * static private $instance; */ /** * Construtor da classe * Caso a classe seja configurada diretamente no código não há necessidade * de chamar o método register através da instancia e portando bastaria * instanciá-la para que ela se registre como manipulador padrão * O método pode inclusive não ser o construtor e sim um método estático * porém neste caso deverá ser reescrito alguns métodos * @return MyErrorHandler */ public function MyErrorHandler() { // Código que deve ser inicializado // $this->register(); } /** * Registra uma auto-instancia como manipulador de erros padrão do PHP * @return unknown_type */ public function register() { $this->old_handler = set_error_handler( array(&$this,'catchMyErrors')); } /** * Desregistra a instancia como manipulador de erros retornando ao que era anteriormente * @return MyErrorHandler for Fluent API */ public function restore() { set_error_handler($this->old_handler); return $this; } /** * Função definida para manipular os erros de execução evitando mostrar os erros * para o usuário e enviando os erros para um tratamento específico * @param Integer $errno Código do erro gerado * @param String $errmsg Mensagem de erro * @param String $filename Nome do arquivo onde o erro foi gerado * @param Integer $linenum Linha do arquivo que gerou o erro * @param mixed $vars Variáveis no momento do erro * @return void */ public function catchMyErrors($errno, $errmsg, $filename, $linenum, $vars) { try{ // Matriz associativa com as strings dos erros // Caso não precise da tradução do tipo de erro pode-se // usar o código comentado $errortype = array ( E_ERROR => "ERRO FATAL", E_WARNING => "ALERTA", E_PARSE => "ERRO DE SINTAXE", E_NOTICE => "AVISO", E_CORE_ERROR => "ERRO DE PROCESSAMENTO", E_CORE_WARNING => "ALERTA DE PROCESSAMENTO", E_COMPILE_ERROR => "ERRO DE COMPILAÇÃO", E_COMPILE_WARNING => "ALERTA DE COMPILAÇÃO", E_USER_ERROR => "ERRO DO USUÁRIO", E_USER_WARNING => "ALERTA DO USUÁRIO", E_USER_NOTICE => "AVISO DO USUÁRIO", E_STRICT => "AVISO ESTRITO", // E_RECOVERABLE_ERROR => "Erro Recuperável" ); if (!in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1')) && in_array($errno, $this->getIgnoreErrors())) { return ; } // timestamp para a entrada do erro $dt = date("d-m-Y H:i"); // Corpo da mensagem if(function_exists('mb_convert_encoding')) // Para evitar problemas com acentos exibidos de forma errada $errmsg = $str = mb_convert_encoding($errmsg, "ISO-8859-1", "ASCII,JIS,UTF-8,ISO-8859-1"); $corpomsg = "\r\n
\r\n" . "############ Informações sobre o erro: ############\r\n" . "\r\n" . "
\r\n"; // Adicionando informações da origem do erro if(isset($_SERVER['HTTP_HOST'],$_SERVER['REQUEST_URI'])){ $corpomsg.="

Outras informações:

\r\n" . "\r\n"; } $corpomsg .= "############ ######################### ############"; /* * Neste momento $corpomsg possui as informações relevantes sobre o erro * e podemos direcionar para algum tratamento * No caso dos portais, para evitar uma visualização poluída ou mesmo * evitar que erros fiquem ocultos nos fontes do HTML podemos imprimir * em forma de alerta. */ if(in_array(@$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '::1'))) { // O erro será exibido na janela em forma de box flutuante echo '
' . $corpomsg . '
'; } else { // O erro será enviado utilizando a função error_log ou mail // Redirecionando o fluxo de execução ao encontrar um erro // que normalmente paralizaria a execução do script if (in_array($errno, $this->user_errors)) { // Verificando para onde será enviado o erro switch($this->log_mode) { case 3: if($this->log_file!=ini_get('error_log')) { ini_set('error_log',$this->log_file); } case 1: // Tentando enviar por email if($this->mail_to!=NULL){ // /* assunto */ $subject = "Alerta de erro em {$_SERVER['REQUEST_URI']}"; // /* Para enviar email HTML, definido o header Content-type. */ $headers = "MIME-Version: 1.0\r\n"; $headers .= "Content-type: text/html; charset=ISO-8859-1\r\n"; // /* headers adicionais */ $headers .= 'To: '. $this->mail_to ."\r\n"; $headers .= 'From: '. $this->mail_from ."\r\n"; $mensagem = '' . '' . 'Erro no Site '. $_SERVER['SERVER_NAME'] .'' . '' . '' . '' . '' . '' . ''. $corpomsg .''; /* Enviar o email com a mensagem de erro*/ mail($this->mail_to, $this->normalizeSubject($subject), $mensagem, $headers); } case 2: // @todo de acordo com o manual não é mais uma opção default: error_log(implode("",array_unique(explode("\n",html_entity_decode(strip_tags($corpomsg)))))); } // se o erro for grave redireciona para uma página definida $this->redirect(); } } } catch (Excpetion $e) { $this->restore(); } } /** * Envia instrução de redirecionamento para a saída */ protected function redirect() { if($this->redirect_to!=NULL) { if(!headers_sent()) { header('Location: ' . $this->redirect_to); exit; } else { die(''); } } } /** * Trata uma string convertendo caracteres especiais para seu equivalente * em hexadecimal. Imprescindível para os cabeçalhos de e-mail se necessitar usar caracteres acentuados * @param string $string Texto a ser tratado * @return string Texto tratado */ protected function charToHex($string) { return preg_replace("#([ãáàâäéèêëíìîïõóòôöúùûüçñ])#ie",'"=". dechex(ord("\\1"))',$string); } /** * Converte o texto do assunto para o formato de acordo com o RFC que não me lembro * @param string $subject * @return string */ protected function normalizeSubject($subject) { if(preg_match("#([ÃÁÀÂÄÉÈÊËÍÌÎÏÕÓÒÔÖÚÙÛÜÇÑãáàâäéèêëíìîïõóòôöúùûüçñ])#i",$subject)) { $subject = '=?iso-8859-1?Q?' . $this->charToHex($subject) .'?='; } return $subject; } /** * Retorna o valor da propriedade mail_to * @return string mail_to */ public function getMailTo(){ return $this->mail_to; } /** * Set value for property mail_to * @param string {mail_to} * @access public * @return myErrorHandler for Fluent API */ public function setMailTo($mail_to) { if (preg_match("#^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$#", $mail_to)) // validando o endereço de email $this->mail_to=$mail_to; return $this; } /** * Retorna o valor da propriedade mail_from * @return string mail_from */ public function getMailFrom(){ return $this->mail_from; } /** * Set value for property mail_from * @param string {mail_from} * @access public * @return myErrorHandler for Fluent API */ public function setMailFrom($mail_from) { if (preg_match("#^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$#", $mail_from)) // validando o endereço de email $this->mail_from=$mail_from; return $this; } /** * Retorna o valor da propriedade mail_reply_to * @return string mail_reply_to */ public function getMailReplyTo(){ return $this->mail_reply_to; } /** * Set value for property mail_reply_to * @param string {mail_reply_to} * @access public * @return myErrorHandler for Fluent API */ public function setMailReplyTo($mail_reply_to) { if (preg_match("#^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$#", $mail_reply_to)) // validando o endereço de email $this->mail_reply_to=$mail_reply_to; return $this; } /** * Retorna o valor da propriedade ignore_errors * @return array ignore_errors */ public function getIgnoreErrors(){ return $this->ignore_errors; } /** * Set value for property ignore_errors * @param array {ignore_errors} * @access public * @return myErrorHandler for Fluent API */ public function setIgnoreErrors(array $ignore_errors) { // Somente os existem os tipo de erros abaixo e portanto somente estes poderão ser ignorados $errortype = array ( E_ERROR, E_WARNING, E_PARSE, E_NOTICE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, E_STRICT, // E_RECOVERABLE_ERROR ); $tobeignored=array(); foreach($ignore_errors as $item) { if(in_array($item,$errortype)) $tobeignored[]=$item; } if(count($tobeignored)>0) $this->ignore_errors=$tobeignored; return $this; } /** * Retorna o valor da propriedade user_errors * @return array $user_errors */ public function getUserErrors(){ return $this->user_errors; } /** * Set value for property user_errors * @param array {user_errors} * @access public * @return myErrorHandler for Fluent API */ public function setUserErrors(array $user_errors) { // Somente os existem os tipo de erros abaixo e portanto somente estes poderão ser ignorados $errortype = array ( E_ERROR, E_WARNING, E_PARSE, E_NOTICE, E_CORE_ERROR, E_CORE_WARNING, E_COMPILE_ERROR, E_COMPILE_WARNING, E_USER_ERROR, E_USER_WARNING, E_USER_NOTICE, E_STRICT, // E_RECOVERABLE_ERROR ); $tobemanipulated=array(); foreach($user_errors as $item) { if(in_array($item,$errortype)) $tobemanipulated[]=$item; } if(count($tobemanipulated)>0) $this->user_errors=$tobemanipulated; return $this; } /** * Retorna o valor da propriedade log_mode * @return int log_mode */ public function getLogMode(){ return $this->log_mode; } /** * Se * t value for property log_mode * @param int {log_mode} * @access public * @return myErrorHandler for Fluent API */ public function setLogMode($log_mode) { $this->log_mode=(int)($log_mode); return $this; } /** * Retorna o valor da propriedade log_file * @return string log_file */ public function getLogFile(){ return ($this->log_file==NULL?ini_get('error_log'):$this->log_file); } /** * Set value for property log_file * Deve ser passado um caminho completo para o arquivo * Será verificado se o PHP tem permissão de escrita neste arquivo * @param string {log_file} * @access public */ public function setLogFile($log_file) { if(!is_file($log_file)) // verificando se o arquivo já existe, caso contrário tenta criá-lo { if(is_writable(dirname($log_file))) // PHP tem permissão de escrita no diretório { if(file_put_contents($log_file,'#########################################\\r\\nArquivo de log criado em '. date('Y-m-d H:i:s'). '\\r\\n#########################################\\r\\n')>0) { $this->log_file=$log_file; } } } else { if(is_writable($log_file)){ $this->log_file=$log_file; } } return $this; } /** * Retorna o valor da propriedade redirect_to * @return string redirect_to */ public function getRedirectTo(){ return $this->redirect_to; } /** * Set value for property redirect_to * O valor deve ser uma url completa ou relativa para uma página de erro * @param string {redirect_to} * @access public */ public function setRedirectTo($redirect_to) { $this->redirect_to=$redirect_to; } }