Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 46 |
|
0.00% |
0 / 5 |
CRAP | |
0.00% |
0 / 1 |
ErrorHandler | |
0.00% |
0 / 46 |
|
0.00% |
0 / 5 |
306 | |
0.00% |
0 / 1 |
logException | |
0.00% |
0 / 18 |
|
0.00% |
0 / 1 |
42 | |||
getAnonIp | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 | |||
getHTTPSaveExceptionCode | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
12 | |||
__invoke | |
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
30 | |||
fatal | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 |
1 | <?php |
2 | /** @noinspection PhpUnhandledExceptionInspection */ |
3 | declare(strict_types=1); |
4 | |
5 | // TODO unit test |
6 | |
7 | use Slim\Exception\HttpException; |
8 | use Slim\Http\ServerRequest as Request; |
9 | use Slim\Http\Response; |
10 | |
11 | class ErrorHandler { |
12 | static function logException(Throwable $throwable, bool $logTrace = false): string { |
13 | $errorUniqueId = uniqid('error-', true); |
14 | $code = ErrorHandler::getHTTPSaveExceptionCode($throwable); |
15 | |
16 | $logHeadline = [ErrorHandler::getAnonIp(), $errorUniqueId]; |
17 | |
18 | if (method_exists($throwable, 'getTitle') and $throwable->getTitle()) { |
19 | $logHeadline[] = "({$throwable->getTitle()})"; |
20 | } else { |
21 | $logHeadline[] = "($code)"; |
22 | } |
23 | |
24 | $logHeadline[] = "`{$throwable->getMessage()}`"; |
25 | |
26 | if (is_a($throwable, "Slim\Exception\HttpException")) { |
27 | $request = $throwable->getRequest(); |
28 | $serverParams = $request->getServerParams(); |
29 | $logHeadline[] = "on `[{$serverParams['REQUEST_METHOD']}] {$serverParams['REQUEST_URI']}`"; |
30 | } else { |
31 | $logHeadline[] = "on `[{$_SERVER['REQUEST_METHOD']}]` {$_SERVER['REQUEST_URI']}`"; |
32 | } |
33 | |
34 | if ($testMode = TestEnvironment::$testMode) { |
35 | $logHeadline[] = "(testMode = $testMode)"; |
36 | } |
37 | |
38 | if ($logTrace) { |
39 | $logHeadline[] = "at {$throwable->getFile()}:{$throwable->getLine()}"; |
40 | } |
41 | |
42 | error_log(implode(' ', $logHeadline)); |
43 | |
44 | return $errorUniqueId; |
45 | } |
46 | |
47 | private static function getAnonIp(): string { |
48 | if (isset($_SERVER['REMOTE_ADDR'])) { |
49 | $ip = explode(".", $_SERVER['REMOTE_ADDR']); |
50 | return "user-" . md5($ip[0] . ($ip[1] ?? '') . ($ip[2] ?? '') . ($_SERVER['HTTP_USER_AGENT'] ?? '')); |
51 | } |
52 | |
53 | return 'pid-' . getmypid(); |
54 | } |
55 | |
56 | static function getHTTPSaveExceptionCode(Throwable $throwable): int { |
57 | if (is_a($throwable, "Slim\Exception\HttpException") or is_a($throwable, 'HttpError')) { |
58 | return $throwable->getCode(); |
59 | } |
60 | |
61 | return 500; |
62 | } |
63 | |
64 | public function __invoke(Request $request, Throwable $throwable): Response { |
65 | global $app; |
66 | |
67 | $code = ErrorHandler::getHTTPSaveExceptionCode($throwable); |
68 | $errorUniqueId = ErrorHandler::logException($throwable, $code >= 500); |
69 | |
70 | if (!is_a($throwable, "Slim\Exception\HttpException")) { |
71 | $newThrowable = new HttpException($request, $throwable->getMessage(), $code, $throwable); |
72 | if (method_exists($throwable, 'getTitle')) { |
73 | $newThrowable->setTitle($throwable->getTitle()); |
74 | } |
75 | $throwable = $newThrowable; |
76 | } |
77 | |
78 | $response = $app |
79 | ->getResponseFactory() |
80 | ->createResponse() |
81 | ->withStatus($throwable->getCode(), $throwable->getTitle()) |
82 | ->withHeader('Content-Type', 'text/html') |
83 | ->withHeader('Error-ID', $errorUniqueId) |
84 | ->write(htmlspecialchars($throwable->getMessage() ?: $throwable->getDescription())); |
85 | |
86 | if (TestEnvironment::$testMode) { |
87 | return $response |
88 | ->withHeader('Test-Mode', TestEnvironment::$testMode); |
89 | } |
90 | |
91 | return $response |
92 | ->withHeader('Test-Mode', 'NO'); |
93 | } |
94 | |
95 | public static function fatal(): void { |
96 | |
97 | } |
98 | } |