* @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" .
"\t- Data/Hora : $dt
\r\n" .
"\t- Tipo : [$errno] ". htmlentities($errortype[$errno]) ."
\r\n" .
"\t- Descrição : ". htmlentities($errmsg) ."
\r\n" .
"\t- Arquivo : $filename
\r\n" .
"\t- Linha : $linenum
\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" .
"\t- IP do usuário: {$_SERVER['REMOTE_ADDR']}
\r\n" .
"\t- Url: {$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}
\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;
}
}