Completed
Push — 6.0 ( 351621...a41474 )
by liu
05:22
created

Handle::getCode()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 4
nc 2
nop 1
dl 0
loc 9
ccs 0
cts 5
cp 0
crap 12
rs 10
c 0
b 0
f 0
1
<?php
2
// +----------------------------------------------------------------------
3
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
4
// +----------------------------------------------------------------------
5
// | Copyright (c) 2006-2016 http://thinkphp.cn All rights reserved.
6
// +----------------------------------------------------------------------
7
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
8
// +----------------------------------------------------------------------
9
// | Author: yunwuxin <[email protected]>
10
// +----------------------------------------------------------------------
11
12
namespace think\exception;
13
14
use Exception;
15
use think\App;
16
use think\console\Output;
17
use think\db\exception\DataNotFoundException;
18
use think\db\exception\ModelNotFoundException;
19
use think\Request;
20
use think\Response;
21
use think\response\Json;
22
use Throwable;
23
24
/**
25
 * 系统异常处理类
26
 */
27
class Handle
28
{
29
    /** @var App */
0 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
30
    protected $app;
31
32
    protected $ignoreReport = [
33
        HttpException::class,
34
        HttpResponseException::class,
35
        ModelNotFoundException::class,
36
        DataNotFoundException::class,
37
        ValidateException::class,
38
    ];
39
40
    protected $isJson = false;
41
42
    public function __construct(App $app)
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function __construct()
Loading history...
43
    {
44
        $this->app = $app;
45
    }
46
47
    /**
48
     * Report or log an exception.
49
     *
50
     * @access public
51
     * @param  Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
52
     * @return void
53
     */
54
    public function report(Throwable $exception): void
55
    {
56
        if (!$this->isIgnoreReport($exception)) {
57
            // 收集异常数据
58
            if ($this->app->isDebug()) {
59
                $data = [
60
                    'file'    => $exception->getFile(),
61
                    'line'    => $exception->getLine(),
62
                    'message' => $this->getMessage($exception),
63
                    'code'    => $this->getCode($exception),
64
                ];
65
                $log = "[{$data['code']}]{$data['message']}[{$data['file']}:{$data['line']}]";
66
            } else {
67
                $data = [
68
                    'code'    => $this->getCode($exception),
69
                    'message' => $this->getMessage($exception),
70
                ];
71
                $log = "[{$data['code']}]{$data['message']}";
72
            }
73
74
            if ($this->app->config->get('log.record_trace')) {
75
                $log .= PHP_EOL . $exception->getTraceAsString();
76
            }
77
78
            $this->app->log->record($log, 'error');
79
        }
80
    }
81
82
    protected function isIgnoreReport(Throwable $exception): bool
0 ignored issues
show
Coding Style introduced by
Missing doc comment for function isIgnoreReport()
Loading history...
83
    {
84
        foreach ($this->ignoreReport as $class) {
85
            if ($exception instanceof $class) {
86
                return true;
87
            }
88
        }
89
90
        return false;
91
    }
92
93
    /**
94
     * Render an exception into an HTTP response.
95
     *
96
     * @access public
97
     * @param Request   $request
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
98
     * @param Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
99
     * @return Response
100
     */
101
    public function render($request, Throwable $e): Response
102
    {
103
        $this->isJson = $request->isJson();
104
        if ($e instanceof HttpException) {
105
            return $this->renderHttpException($e);
106
        } else {
107
            return $this->convertExceptionToResponse($e);
108
        }
109
    }
110
111
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
112
     * @access public
113
     * @param  Output    $output
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
114
     * @param  Throwable $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
115
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
116
    public function renderForConsole(Output $output, Throwable $e): void
117
    {
118
        if ($this->app->isDebug()) {
119
            $output->setVerbosity(Output::VERBOSITY_DEBUG);
120
        }
121
122
        $output->renderException($e);
123
    }
124
125
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
126
     * @access protected
127
     * @param  HttpException $e
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
128
     * @return Response
129
     */
130
    protected function renderHttpException(HttpException $e): Response
131
    {
132
        $status   = $e->getStatusCode();
133
        $template = $this->app->config->get('app.http_exception_template');
134
135
        if (!$this->app->isDebug() && !empty($template[$status])) {
136
            return Response::create($template[$status], 'view', $status)->assign(['e' => $e]);
0 ignored issues
show
Bug introduced by
The method assign() does not exist on think\Response. It seems like you code against a sub-type of think\Response such as think\response\View. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

136
            return Response::create($template[$status], 'view', $status)->/** @scrutinizer ignore-call */ assign(['e' => $e]);
Loading history...
137
        } else {
138
            return $this->convertExceptionToResponse($e);
139
        }
140
    }
141
142
    /**
143
     * 收集异常数据
144
     * @param Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
145
     * @return array
146
     */
147
    protected function convertExceptionToArray(Throwable $exception): array
148
    {
149
        if ($this->app->isDebug()) {
150
            // 调试模式,获取详细的错误信息
151
            $data = [
152
                'name'    => get_class($exception),
153
                'file'    => $exception->getFile(),
154
                'line'    => $exception->getLine(),
155
                'message' => $this->getMessage($exception),
156
                'trace'   => $exception->getTrace(),
157
                'code'    => $this->getCode($exception),
158
                'source'  => $this->getSourceCode($exception),
159
                'datas'   => $this->getExtendData($exception),
160
                'tables'  => [
161
                    'GET Data'              => $_GET,
162
                    'POST Data'             => $_POST,
163
                    'Files'                 => $_FILES,
164
                    'Cookies'               => $_COOKIE,
165
                    'Session'               => $_SESSION ?? [],
166
                    'Server/Request Data'   => $_SERVER,
167
                    'Environment Variables' => $_ENV,
168
                    'ThinkPHP Constants'    => $this->getConst(),
169
                ],
170
            ];
171
        } else {
172
            // 部署模式仅显示 Code 和 Message
173
            $data = [
174
                'code'    => $this->getCode($exception),
175
                'message' => $this->getMessage($exception),
176
            ];
177
178
            if (!$this->app->config->get('app.show_error_msg')) {
179
                // 不显示详细错误信息
180
                $data['message'] = $this->app->config->get('app.error_message');
181
            }
182
        }
183
184
        return $data;
185
    }
186
187
    /**
0 ignored issues
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
188
     * @access protected
189
     * @param  Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
190
     * @return Response
191
     */
192
    protected function convertExceptionToResponse(Throwable $exception): Response
193
    {
194
        $data = $this->convertExceptionToArray($exception);
195
196
        if (!$this->isJson) {
197
            //保留一层
198
            while (ob_get_level() > 1) {
199
                ob_end_clean();
200
            }
201
202
            $data['echo'] = ob_get_clean();
203
204
            ob_start();
205
            extract($data);
206
            include $this->app->config->get('app.exception_tmpl') ?: __DIR__ . '/../../tpl/think_exception.tpl';
207
208
            // 获取并清空缓存
209
            $data     = ob_get_clean();
210
            $response = new Response($data);
211
        } else {
212
            $response = new Json($data);
213
        }
214
215
        if ($exception instanceof HttpException) {
216
            $statusCode = $exception->getStatusCode();
217
            $response->header($exception->getHeaders());
218
        }
219
220
        return $response->code($statusCode ?? 500);
221
    }
222
223
    /**
224
     * 获取错误编码
225
     * ErrorException则使用错误级别作为错误编码
226
     * @access protected
227
     * @param  Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
228
     * @return integer                错误编码
229
     */
230
    protected function getCode(Throwable $exception)
231
    {
232
        $code = $exception->getCode();
233
234
        if (!$code && $exception instanceof ErrorException) {
235
            $code = $exception->getSeverity();
236
        }
237
238
        return $code;
239
    }
240
241
    /**
242
     * 获取错误信息
243
     * ErrorException则使用错误级别作为错误编码
244
     * @access protected
245
     * @param  Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
246
     * @return string                错误信息
247
     */
248
    protected function getMessage(Throwable $exception): string
249
    {
250
        $message = $exception->getMessage();
251
252
        if ($this->app->runningInConsole()) {
253
            return $message;
254
        }
255
256
        $lang = $this->app->lang;
257
258
        if (strpos($message, ':')) {
259
            $name    = strstr($message, ':', true);
260
            $message = $lang->has($name) ? $lang->get($name) . strstr($message, ':') : $message;
261
        } elseif (strpos($message, ',')) {
262
            $name    = strstr($message, ',', true);
263
            $message = $lang->has($name) ? $lang->get($name) . ':' . substr(strstr($message, ','), 1) : $message;
264
        } elseif ($lang->has($message)) {
265
            $message = $lang->get($message);
266
        }
267
268
        return $message;
269
    }
270
271
    /**
272
     * 获取出错文件内容
273
     * 获取错误的前9行和后9行
274
     * @access protected
275
     * @param  Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
276
     * @return array                 错误文件内容
277
     */
278
    protected function getSourceCode(Throwable $exception): array
279
    {
280
        // 读取前9行和后9行
281
        $line  = $exception->getLine();
282
        $first = ($line - 9 > 0) ? $line - 9 : 1;
283
284
        try {
285
            $contents = file($exception->getFile()) ?: [];
286
            $source   = [
287
                'first'  => $first,
288
                'source' => array_slice($contents, $first - 1, 19),
289
            ];
290
        } catch (Exception $e) {
291
            $source = [];
292
        }
293
294
        return $source;
295
    }
296
297
    /**
298
     * 获取异常扩展信息
299
     * 用于非调试模式html返回类型显示
300
     * @access protected
301
     * @param  Throwable $exception
0 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
302
     * @return array                 异常类定义的扩展数据
303
     */
304
    protected function getExtendData(Throwable $exception): array
305
    {
306
        $data = [];
307
308
        if ($exception instanceof \think\Exception) {
309
            $data = $exception->getData();
310
        }
311
312
        return $data;
313
    }
314
315
    /**
316
     * 获取常量列表
317
     * @access private
318
     * @return array 常量列表
319
     */
320
    private static function getConst(): array
0 ignored issues
show
Coding Style introduced by
Private method name "Handle::getConst" must be prefixed with an underscore
Loading history...
321
    {
322
        $const = get_defined_constants(true);
323
324
        return $const['user'] ?? [];
325
    }
326
}
327