首页 > 代码库 > 自定义PHP系统异常处理类

自定义PHP系统异常处理类

001    <?php002     003    // 自定义异常函数004    set_exception_handler(‘handle_exception‘);005     006    // 自定义错误函数007    set_error_handler(‘handle_error‘);008     009    /**010     * 异常处理011     *012     * @param mixed $exception 异常对象013     * @author blog.snsgou.com014     */015    function handle_exception($exception) {016        Error::exceptionError($exception);017    }018     019    /**020     * 错误处理021     *022     * @param string $errNo 错误代码023     * @param string $errStr 错误信息024     * @param string $errFile 出错文件025     * @param string $errLine 出错行026     * @author blog.snsgou.com027     */028    function handle_error($errNo, $errStr, $errFile, $errLine) {029        if ($errNo) {030            Error::systemError($errStr, false, true, false);031        }032    }033     034    /**035     * 系统错误处理036     *037     * @author blog.snsgou.com038     */039    class Error {040     041        public static function systemError($message, $show = true, $save = true, $halt = true) {042     043            list($showTrace, $logTrace) = self::debugBacktrace();044     045            if ($save) {046                $messageSave = ‘<b>‘ . $message . ‘</b><br /><b>PHP:</b>‘ . $logTrace;047                self::writeErrorLog($messageSave);048            }049     050            if ($show) {051                self::showError(‘system‘, "<li>$message</li>", $showTrace, 0);052            }053     054            if ($halt) {055                exit();056            } else {057                return $message;058            }059        }060     061        /**062         * 代码执行过程回溯信息063         *064         * @static065         * @access public066         */067        public static function debugBacktrace() {068            $skipFunc[] = ‘Error->debugBacktrace‘;069     070            $show = $log = ‘‘;071            $debugBacktrace = debug_backtrace();072            ksort($debugBacktrace);073            foreach ($debugBacktrace as $k => $error) {074                if (!isset($error[‘file‘])) {075                    // 利用反射API来获取方法/函数所在的文件和行数076                    try {077                        if (isset($error[‘class‘])) {078                            $reflection = new ReflectionMethod($error[‘class‘], $error[‘function‘]);079                        } else {080                            $reflection = new ReflectionFunction($error[‘function‘]);081                        }082                        $error[‘file‘] = $reflection->getFileName();083                        $error[‘line‘] = $reflection->getStartLine();084                    } catch (Exception $e) {085                        continue;086                    }087                }088     089                $file = str_replace(SITE_PATH, ‘‘, $error[‘file‘]);090                $func = isset($error[‘class‘]) ? $error[‘class‘] : ‘‘;091                $func .= isset($error[‘type‘]) ? $error[‘type‘] : ‘‘;092                $func .= isset($error[‘function‘]) ? $error[‘function‘] : ‘‘;093                if (in_array($func, $skipFunc)) {094                    break;095                }096                $error[‘line‘] = sprintf(‘%04d‘, $error[‘line‘]);097     098                $show .= ‘<li>[Line: ‘ . $error[‘line‘] . ‘]‘ . $file . ‘(‘ . $func . ‘)</li>‘;099                $log .= !empty($log) ? ‘ -> ‘ : ‘‘;100                $log .= $file . ‘:‘ . $error[‘line‘];101            }102            return array($show, $log);103        }104     105        /**106         * 异常处理107         *108         * @static109         * @access public110         * @param mixed $exception111         */112        public static function exceptionError($exception) {113            if ($exception instanceof DbException) {114                $type = ‘db‘;115            } else {116                $type = ‘system‘;117            }118            if ($type == ‘db‘) {119                $errorMsg = ‘(‘ . $exception->getCode() . ‘) ‘;120                $errorMsg .= self::sqlClear($exception->getMessage(), $exception->getDbConfig());121                if ($exception->getSql()) {122                    $errorMsg .= ‘<div class="sql">‘;123                    $errorMsg .= self::sqlClear($exception->getSql(), $exception->getDbConfig());124                    $errorMsg .= ‘</div>‘;125                }126            } else {127                $errorMsg = $exception->getMessage();128            }129            $trace = $exception->getTrace();130            krsort($trace);131            $trace[] = array(‘file‘ => $exception->getFile(), ‘line‘ => $exception->getLine(), ‘function‘ => ‘break‘);132            $phpMsg = array();133            foreach ($trace as $error) {134                if (!empty($error[‘function‘])) {135                    $fun = ‘‘;136                    if (!empty($error[‘class‘])) {137                        $fun .= $error[‘class‘] . $error[‘type‘];138                    }139                    $fun .= $error[‘function‘] . ‘(‘;140                    if (!empty($error[‘args‘])) {141                        $mark = ‘‘;142                        foreach ($error[‘args‘] as $arg) {143                            $fun .= $mark;144                            if (is_array($arg)) {145                                $fun .= ‘Array‘;146                            } elseif (is_bool($arg)) {147                                $fun .= $arg ? ‘true‘ : ‘false‘;148                            } elseif (is_int($arg)) {149                                $fun .= (defined(‘SITE_DEBUG‘) && SITE_DEBUG) ? $arg : ‘%d‘;150                            } elseif (is_float($arg)) {151                                $fun .= (defined(‘SITE_DEBUG‘) && SITE_DEBUG) ? $arg : ‘%f‘;152                            } else {153                                $fun .= (defined(‘SITE_DEBUG‘) && SITE_DEBUG) ? ‘\‘‘ . htmlspecialchars(substr(self::clear($arg), 0, 10)) . (strlen($arg) > 10 ? ‘ ...‘ : ‘‘) . ‘\‘‘ : ‘%s‘;154                            }155                            $mark = ‘, ‘;156                        }157                    }158                    $fun .= ‘)‘;159                    $error[‘function‘] = $fun;160                }161                if (!isset($error[‘line‘])) {162                    continue;163                }164                $phpMsg[] = array(‘file‘ => str_replace(array(SITE_PATH, ‘\\‘), array(‘‘, ‘/‘), $error[‘file‘]), ‘line‘ => $error[‘line‘], ‘function‘ => $error[‘function‘]);165            }166            self::showError($type, $errorMsg, $phpMsg);167            exit();168        }169     170        /**171         * 记录错误日志172         *173         * @static174         * @access public175         * @param string $message176         */177        public static function writeErrorLog($message) {178     179            return false; // 暂时不写入180     181            $message = self::clear($message);182            $time = time();183            $file = LOG_PATH . ‘/‘ . date(‘Y.m.d‘) . ‘_errorlog.php‘;184            $hash = md5($message);185     186            $userId = 0;187            $ip = get_client_ip();188     189            $user = ‘<b>User:</b> userId=‘ . intval($userId) . ‘; IP=‘ . $ip . ‘; RIP:‘ . $_SERVER[‘REMOTE_ADDR‘];190            $uri = ‘Request: ‘ . htmlspecialchars(self::clear($_SERVER[‘REQUEST_URI‘]));191            $message = "<?php exit;?>\t{$time}\t$message\t$hash\t$user $uri\n";192     193            // 判断该$message是否在时间间隔$maxtime内已记录过,有,则不用再记录了194            if (is_file($file)) {195                $fp = @fopen($file, ‘rb‘);196                $lastlen = 50000;       // 读取最后的 $lastlen 长度字节内容197                $maxtime = 60 * 10;     // 时间间隔:10分钟198                $offset = filesize($file) - $lastlen;199                if ($offset > 0) {200                    fseek($fp, $offset);201                }202                if ($data = fread($fp, $lastlen)) {203                    $array = explode("\n", $data);204                    if (is_array($array))205                        foreach ($array as $key => $val) {206                            $row = explode("\t", $val);207                            if ($row[0] != ‘<?php exit;?>‘) {208                                continue;209                            }210                            if ($row[3] == $hash && ($row[1] > $time - $maxtime)) {211                                return;212                            }213                        }214                }215            }216     217            error_log($message, 3, $file);218        }219     220        /**221         * 清除文本部分字符222         *223         * @param string $message224         */225        public static function clear($message) {226            return str_replace(array("\t", "\r", "\n"), " ", $message);227        }228     229        /**230         * sql语句字符清理231         *232         * @static233         * @access public234         * @param string $message235         * @param string $dbConfig236         */237        public static function sqlClear($message, $dbConfig) {238            $message = self::clear($message);239            if (!(defined(‘SITE_DEBUG‘) && SITE_DEBUG)) {240                $message = str_replace($dbConfig[‘database‘], ‘***‘, $message);241                //$message = str_replace($dbConfig[‘prefix‘], ‘***‘, $message);242                $message = str_replace(C(‘DB_PREFIX‘), ‘***‘, $message);243            }244            $message = htmlspecialchars($message);245            return $message;246        }247     248        /**249         * 显示错误250         *251         * @static252         * @access public253         * @param string $type 错误类型 db,system254         * @param string $errorMsg255         * @param string $phpMsg256         */257        public static function showError($type, $errorMsg, $phpMsg = ‘‘) {258            global $_G;259     260            $errorMsg = str_replace(SITE_PATH, ‘‘, $errorMsg);261            ob_end_clean();262            $host = $_SERVER[‘HTTP_HOST‘];263            $title = $type == ‘db‘ ? ‘Database‘ : ‘System‘;264            echo <<<EOT265    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">266    <html>267    <head>268        <title>$host - $title Error</title>269        <meta http-equiv="Content-Type" content="text/html; charset={$_G[‘config‘][‘output‘][‘charset‘]}" />270        <meta name="ROBOTS" content="NOINDEX,NOFOLLOW,NOARCHIVE" />271        <style type="text/css">272        <!--273        body { background-color: white; color: black; font: 9pt/11pt verdana, arial, sans-serif;}274        #container {margin: 10px;}275        #message {width: 1024px; color: black;}276        .red {color: red;}277        a:link {font: 9pt/11pt verdana, arial, sans-serif; color: red;}278        a:visited {font: 9pt/11pt verdana, arial, sans-serif; color: #4e4e4e;}279        h1 {color: #FF0000; font: 18pt "Verdana"; margin-bottom: 0.5em;}280        .bg1 {background-color: #FFFFCC;}281        .bg2 {background-color: #EEEEEE;}282        .table {background: #AAAAAA; font: 11pt Menlo,Consolas,"Lucida Console"}283        .info {284            background: none repeat scroll 0 0 #F3F3F3;285            border: 0px solid #aaaaaa;286            border-radius: 10px 10px 10px 10px;287            color: #000000;288            font-size: 11pt;289            line-height: 160%;290            margin-bottom: 1em;291            padding: 1em;292        }293     294        .help {295            background: #F3F3F3;296            border-radius: 10px 10px 10px 10px;297            font: 12px verdana, arial, sans-serif;298            text-align: center;299            line-height: 160%;300            padding: 1em;301        }302     303        .sql {304            background: none repeat scroll 0 0 #FFFFCC;305            border: 1px solid #aaaaaa;306            color: #000000;307            font: arial, sans-serif;308            font-size: 9pt;309            line-height: 160%;310            margin-top: 1em;311            padding: 4px;312        }313        -->314        </style>315    </head>316    <body>317    <div id="container">318    <h1>$title Error</h1>319    <div class=‘info‘>$errorMsg</div>320    EOT;321            if (!empty($phpMsg)) {322                echo ‘<div class="info">‘;323                echo ‘<p><strong>PHP Debug</strong></p>‘;324                echo ‘<table cellpadding="5" cellspacing="1" width="100%" class="table"><tbody>‘;325                if (is_array($phpMsg)) {326                    echo ‘<tr class="bg2"><td>No.</td><td>File</td><td>Line</td><td>Code</td></tr>‘;327                    foreach ($phpMsg as $k => $msg) {328                        $k++;329                        echo ‘<tr class="bg1">‘;330                        echo ‘<td>‘ . $k . ‘</td>‘;331                        echo ‘<td>‘ . $msg[‘file‘] . ‘</td>‘;332                        echo ‘<td>‘ . $msg[‘line‘] . ‘</td>‘;333                        echo ‘<td>‘ . $msg[‘function‘] . ‘</td>‘;334                        echo ‘</tr>‘;335                    }336                } else {337                    echo ‘<tr><td><ul>‘ . $phpMsg . ‘</ul></td></tr>‘;338                }339                echo ‘</tbody></table></div>‘;340            }341            echo <<<EOT342    </div>343    </body>344    </html>345    EOT;346            exit();347        }348    }349     350    /**351     * DB异常类352     *353     * @author blog.snsgou.com354     */355    class DbException extends Exception {356     357        protected $sql;358        protected $dbConfig;    // 当前数据库配置信息359     360        public function __construct($message, $code = 0, $sql = ‘‘, $dbConfig = array()) {361            $this->sql = $sql;362            $this->dbConfig = $dbConfig;363            parent::__construct($message, $code);364        }365     366        public function getSql() {367            return $this->sql;368        }369     370        public function getDbConfig() {371            return $this->dbConfig;372        }373    }

效果图:

技术分享

 

自定义PHP系统异常处理类