1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Jasny; |
4
|
|
|
|
5
|
|
|
use Psr\Http\Message\ServerRequestInterface; |
6
|
|
|
use Psr\Http\Message\ResponseInterface; |
7
|
|
|
|
8
|
|
|
use Psr\Log\LoggerInterface; |
9
|
|
|
use Psr\Log\LoggerAwareInterface; |
10
|
|
|
use Psr\Log\LogLevel; |
11
|
|
|
use Psr\Log\NullLogger; |
12
|
|
|
|
13
|
|
|
/** |
14
|
|
|
* Handle error in following middlewares/app actions |
15
|
|
|
*/ |
16
|
|
|
class ErrorHandler implements LoggerAwareInterface |
17
|
|
|
{ |
18
|
|
|
/** |
19
|
|
|
* @var LoggerInterface |
20
|
|
|
*/ |
21
|
|
|
protected $logger; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @var \Exception|\Error |
25
|
|
|
*/ |
26
|
|
|
protected $error; |
27
|
|
|
|
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Set the logger for logging errors |
31
|
|
|
* |
32
|
|
|
* @param LoggerInterface $logger |
33
|
|
|
*/ |
34
|
|
|
public function setLogger(LoggerInterface $logger) |
35
|
|
|
{ |
36
|
|
|
$this->logger = $logger; |
37
|
|
|
} |
38
|
|
|
|
39
|
|
|
/** |
40
|
|
|
* Set the logger for logging errors |
41
|
|
|
* |
42
|
|
|
* @return LoggerInterface |
43
|
|
|
*/ |
44
|
|
|
public function getLogger() |
45
|
|
|
{ |
46
|
|
|
if (!isset($this->logger)) { |
47
|
|
|
$this->logger = new NullLogger(); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
return $this->logger; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Log an error or exception |
55
|
|
|
* |
56
|
|
|
* @param \Exception|\Error $error |
57
|
|
|
*/ |
58
|
|
|
public function log($error) |
59
|
|
|
{ |
60
|
|
|
if ($error instanceof \Error || $error instanceof \ErrorException) { |
|
|
|
|
61
|
|
|
return $this->logError($error); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
if ($error instanceof \Exception) { |
65
|
|
|
return $this->logException($error); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
$message = "Unable to log a " . (is_object($error) ? get_class($error) . ' ' : '') . gettype($error); |
69
|
|
|
$this->getLogger()->log(LogLevel::WARNING, $message); |
70
|
|
|
} |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* Log an error |
74
|
|
|
* |
75
|
|
|
* @param \Error|\ErrorException $error |
76
|
|
|
*/ |
77
|
|
|
protected function logError($error) |
78
|
|
|
{ |
79
|
|
|
$code = $error instanceof \ErrorException ? $error->getSeverity() : E_ERROR; |
|
|
|
|
80
|
|
|
$level = $this->getLogLevel($code); |
81
|
|
|
|
82
|
|
|
$message = sprintf('%s: %s at %s line %s', $this->codeToString($code), $error->getMessage(), |
83
|
|
|
$error->getFile(), $error->getLine()); |
84
|
|
|
|
85
|
|
|
$context = [ |
86
|
|
|
'error' => $error, |
87
|
|
|
'code' => $code, |
88
|
|
|
'message' => $error->getMessage(), |
89
|
|
|
'file' => $error->getFile(), |
90
|
|
|
'line' => $error->getLine() |
91
|
|
|
]; |
92
|
|
|
|
93
|
|
|
$this->getLogger()->log($level, $message, $context); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
/** |
97
|
|
|
* Log an exception |
98
|
|
|
* |
99
|
|
|
* @param \Exception $error |
100
|
|
|
*/ |
101
|
|
|
protected function logException(\Exception $error) |
102
|
|
|
{ |
103
|
|
|
$level = $this->getLogLevel(); |
104
|
|
|
|
105
|
|
|
$message = sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($error), $error->getMessage(), |
106
|
|
|
$error->getFile(), $error->getLine()); |
107
|
|
|
|
108
|
|
|
$context = ['exception' => $error]; |
109
|
|
|
|
110
|
|
|
$this->getLogger()->log($level, $message, $context); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
|
114
|
|
|
/** |
115
|
|
|
* Get the caught error |
116
|
|
|
* |
117
|
|
|
* @return \Throwable|\Exception|\Error |
118
|
|
|
*/ |
119
|
|
|
public function getError() |
120
|
|
|
{ |
121
|
|
|
return $this->error; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
|
125
|
|
|
/** |
126
|
|
|
* Run middleware action |
127
|
|
|
* |
128
|
|
|
* @param ServerRequestInterface $request |
129
|
|
|
* @param ResponseInterface $response |
130
|
|
|
* @param callback $next |
131
|
|
|
* @return ResponseInterface |
132
|
|
|
*/ |
133
|
|
|
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next) |
134
|
|
|
{ |
135
|
|
|
if (!is_callable($next)) { |
136
|
|
|
throw new \InvalidArgumentException("'next' should be a callback"); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
try { |
140
|
|
|
$this->error = null; |
141
|
|
|
$nextResponse = $next($request, $response); |
142
|
|
|
} catch(\Error $e) { |
143
|
|
|
$this->error = $e; |
144
|
|
|
} catch(\Exception $e) { |
145
|
|
|
$this->error = $e; |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
if ($this->error) { |
149
|
|
|
$this->log($this->error); |
150
|
|
|
$nextResponse = $this->handleError($response); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
return $nextResponse; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* Handle caught error |
158
|
|
|
* |
159
|
|
|
* @param ResponseInterface $response |
160
|
|
|
* @return ResponseInterface |
161
|
|
|
*/ |
162
|
|
|
protected function handleError($response) |
163
|
|
|
{ |
164
|
|
|
$errorResponse = $response->withStatus(500); |
165
|
|
|
$errorResponse->getBody()->write('Unexpected error'); |
166
|
|
|
|
167
|
|
|
return $errorResponse; |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
|
171
|
|
|
/** |
172
|
|
|
* Get the log level for an error code |
173
|
|
|
* |
174
|
|
|
* @param int $code E_* error code |
175
|
|
|
* @return string |
176
|
|
|
*/ |
177
|
|
|
protected function getLogLevel($code = null) |
178
|
|
|
{ |
179
|
|
|
switch ($code) { |
180
|
|
|
case E_STRICT: |
181
|
|
|
case E_DEPRECATED: |
182
|
|
|
case E_USER_DEPRECATED: |
183
|
|
|
return LogLevel::INFO; |
184
|
|
|
|
185
|
|
|
case E_NOTICE: |
186
|
|
|
case E_USER_NOTICE: |
187
|
|
|
return LogLevel::NOTICE; |
188
|
|
|
|
189
|
|
|
case E_WARNING: |
190
|
|
|
case E_CORE_WARNING: |
191
|
|
|
case E_COMPILE_WARNING: |
192
|
|
|
case E_USER_WARNING: |
193
|
|
|
return LogLevel::WARNING; |
194
|
|
|
|
195
|
|
|
case E_PARSE: |
196
|
|
|
case E_CORE_ERROR: |
197
|
|
|
case E_COMPILE_ERROR: |
198
|
|
|
return LogLevel::CRITICAL; |
199
|
|
|
|
200
|
|
|
default: |
201
|
|
|
return LogLevel::ERROR; |
202
|
|
|
} |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* Turn an error code into a string |
207
|
|
|
* |
208
|
|
|
* @param int $code |
209
|
|
|
* @return string |
210
|
|
|
*/ |
211
|
|
|
protected function codeToString($code) |
212
|
|
|
{ |
213
|
|
|
switch ($code) { |
214
|
|
|
case E_ERROR: |
215
|
|
|
case E_USER_ERROR: |
216
|
|
|
case E_RECOVERABLE_ERROR: |
217
|
|
|
return 'Fatal error'; |
218
|
|
|
case E_WARNING: |
219
|
|
|
case E_USER_WARNING: |
220
|
|
|
return 'Warning'; |
221
|
|
|
case E_PARSE: |
222
|
|
|
return 'Parse error'; |
223
|
|
|
case E_NOTICE: |
224
|
|
|
case E_USER_NOTICE: |
225
|
|
|
return 'Notice'; |
226
|
|
|
case E_CORE_ERROR: |
227
|
|
|
return 'Core error'; |
228
|
|
|
case E_CORE_WARNING: |
229
|
|
|
return 'Core warning'; |
230
|
|
|
case E_COMPILE_ERROR: |
231
|
|
|
return 'Compile error'; |
232
|
|
|
case E_COMPILE_WARNING: |
233
|
|
|
return 'Compile warning'; |
234
|
|
|
case E_STRICT: |
235
|
|
|
return 'Strict standards'; |
236
|
|
|
case E_DEPRECATED: |
237
|
|
|
case E_USER_DEPRECATED: |
238
|
|
|
return 'Deprecated'; |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
return 'Unknown error'; |
242
|
|
|
} |
243
|
|
|
} |
244
|
|
|
|
This error could be the result of:
1. Missing dependencies
PHP Analyzer uses your
composer.json
file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects thecomposer.json
to be in the root folder of your repository.Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the
require
orrequire-dev
section?2. Missing use statement
PHP does not complain about undefined classes in
ìnstanceof
checks. For example, the following PHP code will work perfectly fine:If you have not tested against this specific condition, such errors might go unnoticed.