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 '| No. | File | Line | Code |
';
+ foreach ($phpMsg as $k => $msg) {
+ $k++;
+ echo '';
+ echo '| ' . $k . ' | ';
+ echo '' . $msg['file'] . ' | ';
+ echo '' . $msg['line'] . ' | ';
+ echo '' . $msg['function'] . ' | ';
+ echo '
';
+ }
+ } else {
+ echo ' |
';
+ }
+ echo '
';
+ }
+ 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
{