From aa18b438d4820412a75a2e37be35b4d6bad7bce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mr=C2=B7x?= Date: Mon, 30 Aug 2021 19:09:25 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/Error/Error.php | 371 +++++++++++++++++++++++++++++++++++++ http-helper/Route/Node.php | 1 + 2 files changed, 372 insertions(+) create mode 100644 core/Error/Error.php diff --git a/core/Error/Error.php b/core/Error/Error.php new file mode 100644 index 00000000..6bc58dbc --- /dev/null +++ b/core/Error/Error.php @@ -0,0 +1,371 @@ +' . $message . '
PHP:' . $logTrace; + self::writeErrorLog($messageSave); + } + if ($show) { + self::showError('system', "
  • $message
  • ", $showTrace, 0); + } + if ($halt) { + exit(); + } else { + return $message; + } + } + + /** + * 代码执行过程回溯信息 + * + * @static + * @access public + */ + public static function debugBacktrace() + { + $skipFunc[] = 'Error->debugBacktrace'; + $show = $log = ''; + $debugBacktrace = debug_backtrace(); + ksort($debugBacktrace); + foreach ($debugBacktrace as $k => $error) { + if (!isset($error['file'])) { + // 利用反射API来获取方法/函数所在的文件和行数 + try { + if (isset($error['class'])) { + $reflection = new ReflectionMethod($error['class'], $error['function']); + } else { + $reflection = new ReflectionFunction($error['function']); + } + $error['file'] = $reflection->getFileName(); + $error['line'] = $reflection->getStartLine(); + } catch (Exception $e) { + continue; + } + } + $file = str_replace(SITE_PATH, '', $error['file']); + $func = isset($error['class']) ? $error['class'] : ''; + $func .= isset($error['type']) ? $error['type'] : ''; + $func .= isset($error['function']) ? $error['function'] : ''; + if (in_array($func, $skipFunc)) { + break; + } + $error['line'] = sprintf('%04d', $error['line']); + $show .= '
  • [Line: ' . $error['line'] . ']' . $file . '(' . $func . ')
  • '; + $log .= !empty($log) ? ' -> ' : ''; + $log .= $file . ':' . $error['line']; + } + return array($show, $log); + } + + /** + * 异常处理 + * + * @static + * @access public + * @param mixed $exception + */ + public static function exceptionError($exception) + { + if ($exception instanceof DbException) { + $type = 'db'; + } else { + $type = 'system'; + } + if ($type == 'db') { + $errorMsg = '(' . $exception->getCode() . ') '; + $errorMsg .= self::sqlClear($exception->getMessage(), $exception->getDbConfig()); + if ($exception->getSql()) { + $errorMsg .= '
    '; + $errorMsg .= self::sqlClear($exception->getSql(), $exception->getDbConfig()); + $errorMsg .= '
    '; + } + } else { + $errorMsg = $exception->getMessage(); + } + $trace = $exception->getTrace(); + krsort($trace); + $trace[] = array('file' => $exception->getFile(), 'line' => $exception->getLine(), 'function' => 'break'); + $phpMsg = array(); + foreach ($trace as $error) { + if (!empty($error['function'])) { + $fun = ''; + if (!empty($error['class'])) { + $fun .= $error['class'] . $error['type']; + } + $fun .= $error['function'] . '('; + if (!empty($error['args'])) { + $mark = ''; + foreach ($error['args'] as $arg) { + $fun .= $mark; + if (is_array($arg)) { + $fun .= 'Array'; + } elseif (is_bool($arg)) { + $fun .= $arg ? 'true' : 'false'; + } elseif (is_int($arg)) { + $fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? $arg : '%d'; + } elseif (is_float($arg)) { + $fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? $arg : '%f'; + } else { + $fun .= (defined('SITE_DEBUG') && SITE_DEBUG) ? '\'' . htmlspecialchars(substr(self::clear($arg), 0, 10)) . (strlen($arg) > 10 ? ' ...' : '') . '\'' : '%s'; + } + $mark = ', '; + } + } + $fun .= ')'; + $error['function'] = $fun; + } + if (!isset($error['line'])) { + continue; + } + $phpMsg[] = array('file' => str_replace(array(SITE_PATH, '\\'), array('', '/'), $error['file']), 'line' => $error['line'], 'function' => $error['function']); + } + self::showError($type, $errorMsg, $phpMsg); + exit(); + } + + /** + * 记录错误日志 + * + * @static + * @access public + * @param string $message + */ + public static function writeErrorLog($message) + { + return false; // 暂时不写入 + $message = self::clear($message); + $time = time(); + $file = LOG_PATH . '/' . date('Y.m.d') . '_errorlog.php'; + $hash = md5($message); + $userId = 0; + $ip = get_client_ip(); + $user = 'User: userId=' . intval($userId) . '; IP=' . $ip . '; RIP:' . $_SERVER['REMOTE_ADDR']; + $uri = 'Request: ' . htmlspecialchars(self::clear($_SERVER['REQUEST_URI'])); + $message = "\t{$time}\t$message\t$hash\t$user $uri\n"; + // 判断该$message是否在时间间隔$maxtime内已记录过,有,则不用再记录了 + if (is_file($file)) { + $fp = @fopen($file, 'rb'); + $lastlen = 50000; // 读取最后的 $lastlen 长度字节内容 + $maxtime = 60 * 10; // 时间间隔:10分钟 + $offset = filesize($file) - $lastlen; + if ($offset > 0) { + fseek($fp, $offset); + } + if ($data = fread($fp, $lastlen)) { + $array = explode("\n", $data); + if (is_array($array)) + foreach ($array as $key => $val) { + $row = explode("\t", $val); + if ($row[0] != '') { + continue; + } + if ($row[3] == $hash && ($row[1] > $time - $maxtime)) { + return; + } + } + } + } + error_log($message, 3, $file); + } + + /** + * 清除文本部分字符 + * + * @param string $message + */ + public static function clear($message) + { + return str_replace(array("\t", "\r", "\n"), " ", $message); + } + + /** + * sql语句字符清理 + * + * @static + * @access public + * @param string $message + * @param string $dbConfig + */ + public static function sqlClear($message, $dbConfig) + { + $message = self::clear($message); + if (!(defined('SITE_DEBUG') && SITE_DEBUG)) { + $message = str_replace($dbConfig['database'], '***', $message); + //$message = str_replace($dbConfig['prefix'], '***', $message); + $message = str_replace(C('DB_PREFIX'), '***', $message); + } + $message = htmlspecialchars($message); + return $message; + } + + /** + * 显示错误 + * + * @static + * @access public + * @param string $type 错误类型 db,system + * @param string $errorMsg + * @param string $phpMsg + */ + public static function showError($type, $errorMsg, $phpMsg = ''):string + { + global $_G; + ob_end_clean(); + $host = $_SERVER['HTTP_HOST']; + $title = $type == 'db' ? 'Database' : 'System'; + return << + + + $host - $title Error + + + + + +
    +

    $title Error

    +
    $errorMsg
    +EOT; + if (!empty($phpMsg)) { + echo '
    '; + echo '

    PHP Debug

    '; + echo ''; + if (is_array($phpMsg)) { + echo ''; + foreach ($phpMsg as $k => $msg) { + $k++; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + echo ''; + } + } else { + echo ''; + } + echo '
    No.FileLineCode
    ' . $k . '' . $msg['file'] . '' . $msg['line'] . '' . $msg['function'] . '
      ' . $phpMsg . '
    '; + } + echo << + + +EOT; + exit(); + } +} + +/** + * DB异常类 + * + * @author blog.snsgou.com + */ +class DbException extends Exception +{ + protected $sql; + protected $dbConfig; // 当前数据库配置信息 + + public function __construct($message, $code = 0, $sql = '', $dbConfig = array()) + { + $this->sql = $sql; + $this->dbConfig = $dbConfig; + parent::__construct($message, $code); + } + + public function getSql() + { + return $this->sql; + } + + public function getDbConfig() + { + return $this->dbConfig; + } +} +} diff --git a/http-helper/Route/Node.php b/http-helper/Route/Node.php index 39f46ab2..12cbc958 100644 --- a/http-helper/Route/Node.php +++ b/http-helper/Route/Node.php @@ -137,6 +137,7 @@ class Node * @param $_injectParameters * @throws NotFindClassException * @throws ReflectionException + * @throws Exception */ private function injectMiddleware(string $method, $handler, $_injectParameters): void {