| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 | <?php// +----------------------------------------------------------------------// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]// +----------------------------------------------------------------------// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.// +----------------------------------------------------------------------// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )// +----------------------------------------------------------------------// | Author: yunwuxin <448901948@qq.com>// +----------------------------------------------------------------------namespace think\exception;use Exception;use think\App;use think\Config;use think\console\Output;use think\Lang;use think\Log;use think\Response;class Handle{    protected $render;    protected $ignoreReport = [        '\\think\\exception\\HttpException',    ];    public function setRender($render)    {        $this->render = $render;    }    /**     * Report or log an exception.     *     * @param  \Exception $exception     * @return void     */    public function report(Exception $exception)    {        if (!$this->isIgnoreReport($exception)) {            // 收集异常数据            if (App::$debug) {                $data = [                    'file'    => $exception->getFile(),                    'line'    => $exception->getLine(),                    'message' => $this->getMessage($exception),                    'code'    => $this->getCode($exception),                ];                $log = "[{$data['code']}]{$data['message']}[{$data['file']}:{$data['line']}]";            } else {                $data = [                    'code'    => $this->getCode($exception),                    'message' => $this->getMessage($exception),                ];                $log = "[{$data['code']}]{$data['message']}";            }            if (Config::get('record_trace')) {                $log .= "\r\n" . $exception->getTraceAsString();            }            Log::record($log, 'error');        }    }    protected function isIgnoreReport(Exception $exception)    {        foreach ($this->ignoreReport as $class) {            if ($exception instanceof $class) {                return true;            }        }        return false;    }    /**     * Render an exception into an HTTP response.     *     * @param  \Exception $e     * @return Response     */    public function render(Exception $e)    {        if ($this->render && $this->render instanceof \Closure) {            $result = call_user_func_array($this->render, [$e]);            if ($result) {                return $result;            }        }        if ($e instanceof HttpException) {            return $this->renderHttpException($e);        } else {            return $this->convertExceptionToResponse($e);        }    }    /**     * @param Output    $output     * @param Exception $e     */    public function renderForConsole(Output $output, Exception $e)    {        if (App::$debug) {            $output->setVerbosity(Output::VERBOSITY_DEBUG);        }        $output->renderException($e);    }    /**     * @param HttpException $e     * @return Response     */    protected function renderHttpException(HttpException $e)    {        $status   = $e->getStatusCode();        $template = Config::get('http_exception_template');        if (!App::$debug && !empty($template[$status])) {            return Response::create($template[$status], 'view', $status)->assign(['e' => $e]);        } else {            return $this->convertExceptionToResponse($e);        }    }    /**     * @param Exception $exception     * @return Response     */    protected function convertExceptionToResponse(Exception $exception)    {        // 收集异常数据        if (App::$debug) {            // 调试模式,获取详细的错误信息            $data = [                'name'    => get_class($exception),                'file'    => $exception->getFile(),                'line'    => $exception->getLine(),                'message' => $this->getMessage($exception),                'trace'   => $exception->getTrace(),                'code'    => $this->getCode($exception),                'source'  => $this->getSourceCode($exception),                'datas'   => $this->getExtendData($exception),                'tables'  => [                    'GET Data'              => $_GET,                    'POST Data'             => $_POST,                    'Files'                 => $_FILES,                    'Cookies'               => $_COOKIE,                    'Session'               => isset($_SESSION) ? $_SESSION : [],                    'Server/Request Data'   => $_SERVER,                    'Environment Variables' => $_ENV,                    'ThinkPHP Constants'    => $this->getConst(),                ],            ];        } else {            // 部署模式仅显示 Code 和 Message            $data = [                'code'    => $this->getCode($exception),                'message' => $this->getMessage($exception),            ];            if (!Config::get('show_error_msg')) {                // 不显示详细错误信息                $data['message'] = Config::get('error_message');            }        }        //保留一层        while (ob_get_level() > 1) {            ob_end_clean();        }        $data['echo'] = ob_get_clean();        ob_start();        extract($data);        include Config::get('exception_tmpl');        // 获取并清空缓存        $content  = ob_get_clean();        $response = new Response($content, 'html');        if ($exception instanceof HttpException) {            $statusCode = $exception->getStatusCode();            $response->header($exception->getHeaders());        }        if (!isset($statusCode)) {            $statusCode = 500;        }        $response->code($statusCode);        return $response;    }    /**     * 获取错误编码     * ErrorException则使用错误级别作为错误编码     * @param  \Exception $exception     * @return integer                错误编码     */    protected function getCode(Exception $exception)    {        $code = $exception->getCode();        if (!$code && $exception instanceof ErrorException) {            $code = $exception->getSeverity();        }        return $code;    }    /**     * 获取错误信息     * ErrorException则使用错误级别作为错误编码     * @param  \Exception $exception     * @return string                错误信息     */    protected function getMessage(Exception $exception)    {        $message = $exception->getMessage();        if (IS_CLI) {            return $message;        }        if (strpos($message, ':')) {            $name    = strstr($message, ':', true);            $message = Lang::has($name) ? Lang::get($name) . strstr($message, ':') : $message;        } elseif (strpos($message, ',')) {            $name    = strstr($message, ',', true);            $message = Lang::has($name) ? Lang::get($name) . ':' . substr(strstr($message, ','), 1) : $message;        } elseif (Lang::has($message)) {            $message = Lang::get($message);        }        return $message;    }    /**     * 获取出错文件内容     * 获取错误的前9行和后9行     * @param  \Exception $exception     * @return array                 错误文件内容     */    protected function getSourceCode(Exception $exception)    {        // 读取前9行和后9行        $line  = $exception->getLine();        $first = ($line - 9 > 0) ? $line - 9 : 1;        try {            $contents = file($exception->getFile());            $source   = [                'first'  => $first,                'source' => array_slice($contents, $first - 1, 19),            ];        } catch (Exception $e) {            $source = [];        }        return $source;    }    /**     * 获取异常扩展信息     * 用于非调试模式html返回类型显示     * @param  \Exception $exception     * @return array                 异常类定义的扩展数据     */    protected function getExtendData(Exception $exception)    {        $data = [];        if ($exception instanceof \think\Exception) {            $data = $exception->getData();        }        return $data;    }    /**     * 获取常量列表     * @return array 常量列表     */    private static function getConst()    {        return get_defined_constants(true)['user'];    }}
 |