Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 11
CRAP
0.00% covered (danger)
0.00%
0 / 115
iaErrorReporter
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 11
1406.00
0.00% covered (danger)
0.00%
0 / 115
 __construct
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 4
 process
0.00% covered (danger)
0.00%
0 / 1
110.00
0.00% covered (danger)
0.00%
0 / 29
 errorException
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 14
 errorManual
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 7
 dbtrace
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 6
 errorSql
0.00% covered (danger)
0.00%
0 / 1
30.00
0.00% covered (danger)
0.00%
0 / 13
 errorPhp
0.00% covered (danger)
0.00%
0 / 1
6.00
0.00% covered (danger)
0.00%
0 / 7
 errorJson
0.00% covered (danger)
0.00%
0 / 1
20.00
0.00% covered (danger)
0.00%
0 / 12
 errorPreg
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 9
 errorXml
0.00% covered (danger)
0.00%
0 / 1
12.00
0.00% covered (danger)
0.00%
0 / 12
 logErrorAdd
0.00% covered (danger)
0.00%
0 / 1
2.00
0.00% covered (danger)
0.00%
0 / 2
<?php
namespace ia\Lib;
use ia\Util\Str;
/**
 * iaErrorReporter,
 *
 *
 * @example
 *  $errRep = new iaErrorReporter($db, $mailErrorsTo);
 *  $errRep->process(true); // at bottom of script, stores and emails new errors. true also displays,
 *
 * @author Informatica Asociada
 * @copyright 2015
 * @version 1.1.2
 *
 * requires php 5.2, traits imply 5.4
 */
class iaErrorReporter {
    /** @var string email to send new errors, empty no email sent */
    protected $emailTo;
    /** @var object db class */
    protected $db;
    /** @var array error logged */
    protected $logError = array();
    /**
     * __construct()
     *
     * @param object $db
     * @param string $emailTo
     * @return void
     */
    public function __construct($db) {
        $this->db = $db;
        global $gConfig;
        $this->emailTo = isset($gConfig['mailErrorsTo']) ? $gConfig['mailErrorsTo'] : null;
    }
    /**
     * Registers last errors, if any, emails new errors & optionally displays them
     *
     * @param bool $display on true echos error
     * @return void
     *
     * @see pageDisplayErrors pageDisplayErrors
     * @see emailSend emailSend
     */
    public function process($display=false) {
        $this->errorPhp();
        $this->errorJson();
        $this->errorPreg();
        $this->errorXml();
        $this->errorSql();
        $count = array('newbug'=>0,'Fixed'=>0,'Bug'=>0,'Wont Fix'=>0,'?'=>0);
        $html = '';
        foreach($this->logError as $error) {
            try {
                if($this->db != null) {
                    $sql = "SELECT `status` FROM icac_error WHERE file=".Str::strit($error['file'])." AND line=".Str::strit($error['line']).
                        " AND error_type=".Str::strit($error['error_type'])." AND coded=".Str::strit($error['coded']);
                    $error_status = $this->db->single_read($sql,'newbug');
                } else {
                    $error_status='newbug';
                }
                if(empty($error_status)) $error_status='newbug';
                if(array_key_exists($error_status,$count)) {
                    $count[$error_status]++;
                }
                $html .= "<li style='padding-bottom:0.4em;'>".htmlentities($error['message']).
                    (!empty($error['Sql']) ? " <br />".htmlentities($error['Sql']) : '' ).(!empty($error['retries']) ? " ".htmlentities($error['retries']) : '' ).
                    "<br />".htmlentities($error['file'])." Line: ".$error['line']." Type: ".htmlentities($error['error_type']);
            // log error in db
                if($this->db != null) {
                    $sql = "INSERT INTO icac_error(file,line,error_type,coded,error_message,first_seen,last_seen,seen_times) VALUES("
                            .Str::stritc($error['file']).Str::stritc($error['line']).Str::stritc($error['error_type']).Str::stritc($error['coded']).
                             Str::stritc($error['message'].(empty($error['Sql']) ? '' : "\r\n".$error['Sql']  ))
                            ."NOW(),NOW(),1 )"
                            ." ON DUPLICATE KEY UPDATE last_seen=NOW(),seen_times=seen_times+1,error_message=VALUES(error_message), `status`=IF(`status`='Fixed','Bug',`status`)";
                    $this->db->query($sql);
                }
            } catch(\Exception $err) {
                // DO NOTHING
            }
        }
        $output = new iaErrorReporterDisplay();
        $output->reportErrors($display, $this->emailTo, $html, $count, $this->dbtrace());
    }
//////////////////////
// Manually log an error
//////////////////////
    /**
     * Register an exception in the error log
     *
     * @param object $exception an exception
     * @param string $error_type
     * @return void
     */
    public function errorException($exception,$error_type='exception') {
        try {
            $this->logErrorAdd(array(
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
                'error_type' => $error_type,
                'coded'=>'',
                'message' => $exception->getMessage(),
                )
            );
        } catch(\Exception $e) {
            // just in case, defensive programming
            $this->logErrorAdd(array(
                'file' => $_SERVER['SCRIPT_NAME'],
                'line' => 0,
                'error_type' => 'exception',
                'coded'=>'',
                'message' => "Registering exception trhough IacErrorReporter::errorException",
                )
            );
        }
    }
    /**
     * Manually set an error
     *
     * @param string $file
     * @param integer $line
     * @param string $error_type
     * @param string $message
     * @param string $md5
     * @return void
     */
    public function errorManual($message, $file, $error_type='Manual', $line=0, $md5='') {
        $this->logErrorAdd( array(
            'file' => empty($file) ? $_SERVER['SCRIPT_NAME'] : $file,
            'line' => $line,
            'error_type' => $error_type,
            'coded' => $md5,
            'message' => $message
            )
        );
    }
//////////////////////
// Manually log an error
//////////////////////
    /**
     * report Sql trace
     *
     * @return
     */
    protected function dbtrace() {
        if($this->db === null) {
            return '';
        }
        $log = $this->db->trace_get();
        if(empty($log)) {
            return "";
        }
        return "<ol><li>" . implode("<li>",$log)."</ol>";
    }
    /**
     * Register Sql error log
     *
     * @return void
     */
    protected function errorSql() {
        if($this->db === null) {
            return ;
        }
        foreach($this->db->errorLog_get() as $error) {
            $sqlNormalized = Str::sqlNormalized($error['Sql']);
            $this->logErrorAdd( array(
                'file' => empty($_SERVER['SCRIPT_NAME']) ? 'Sql' : $_SERVER['SCRIPT_NAME'],
                'line' => 1,
                'error_type' => 'Sql',
                'coded' => md5($sqlNormalized),
                'Sql' => $sqlNormalized,
                'sqlNormalized' => $sqlNormalized,
                'message' => (empty($error['errno']) ? '' : $error['errno'].': ').$error['error'],
                )
            );
        }
    }
    /**
     * Register last php error
     *
     * @return void
     */
    protected function errorPhp() {
        $error = error_get_last();
        if(empty($error)) {
            return;
        }
        $error['error_type'] = 'php';
        $error['coded'] = '';
        $this->logErrorAdd($error);
    }
    /**
     * Register last json error
     *
     * @return void
     */
    protected function errorJson() {
        if(!function_exists('json_last_error')) {
            return;
        }
        $error = json_last_error();
        if($error === JSON_ERROR_NONE) {
            return;
        }
        $this->logErrorAdd( array(
            'file' => $_SERVER['SCRIPT_NAME'],
            'line' => 1,
            'error_type' => 'json',
            'coded' => '',
            'message' => function_exists('json_last_error_msg') ? json_last_error_msg() : iaLib::constant2name('json',$error)
            )
        );
    }
    /**
     * Register last  regexp error
     *
     * @return void
     */
    protected function errorPreg() {
        if(!function_exists('preg_last_error') || ($error=preg_last_error()) === PREG_NO_ERROR ) {
            return null;
        }
        $this->logErrorAdd( array(
            'file' => $_SERVER['SCRIPT_NAME'],
            'line' => 1,
            'error_type' => 'pcre',
            'coded' => '',
            'message' => iaLib::constant2name('pcre',$error)
            )
        );
    }
    /**
     * Register last xml error
     *
     * @return void
     */
    protected function errorXml() {
        if(!function_exists('libxml_get_last_error')) {
            return;
        }
        $error = libxml_get_last_error();
        if($error == false) {
            return;
        }
        $this->logErrorAdd( array(
            'file' =>  $_SERVER['SCRIPT_NAME'],
            'line' => 1,
            'error_type' => 'libxml',
            'coded' => md5($error->file."xml"),
            'message' => "Error code: ".$error->code.", Level: ".$error->level.' File: '.$error->file.", Line: ".$error->line.", Column: ".$error->column
            )
        );
    }
//////////////////////
// Auxiliares
//////////////////////
    /**
     * Store errors by hash key
     *
     * @param array $error
     * @return void
     */
    protected function logErrorAdd($error) {
        $this->logError[ $error['file'].$error['line'].$error['error_type'].$error['coded'] ] = $error;
    }
}