ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Run.php
Go to the documentation of this file.
1<?php
7namespace Whoops;
8
9use InvalidArgumentException;
17
18final class Run implements RunInterface
19{
21 private $allowQuit = true;
22 private $sendOutput = true;
23
27 private $sendHttpCode = 500;
28
32 private $handlerStack = [];
33
34 private $silencedPatterns = [];
35
36 private $system;
37
38 public function __construct(SystemFacade $system = null)
39 {
40 $this->system = $system ?: new SystemFacade;
41 }
42
50 public function pushHandler($handler)
51 {
52 if (is_callable($handler)) {
54 }
55
56 if (!$handler instanceof HandlerInterface) {
57 throw new InvalidArgumentException(
58 "Argument to " . __METHOD__ . " must be a callable, or instance of "
59 . "Whoops\\Handler\\HandlerInterface"
60 );
61 }
62
63 $this->handlerStack[] = $handler;
64 return $this;
65 }
66
72 public function popHandler()
73 {
74 return array_pop($this->handlerStack);
75 }
76
82 public function getHandlers()
83 {
84 return $this->handlerStack;
85 }
86
92 public function clearHandlers()
93 {
94 $this->handlerStack = [];
95 return $this;
96 }
97
102 private function getInspector($exception)
103 {
104 return new Inspector($exception);
105 }
106
111 public function register()
112 {
113 if (!$this->isRegistered) {
114 // Workaround PHP bug 42098
115 // https://bugs.php.net/bug.php?id=42098
116 class_exists("\\Whoops\\Exception\\ErrorException");
117 class_exists("\\Whoops\\Exception\\FrameCollection");
118 class_exists("\\Whoops\\Exception\\Frame");
119 class_exists("\\Whoops\\Exception\\Inspector");
120
121 $this->system->setErrorHandler([$this, self::ERROR_HANDLER]);
122 $this->system->setExceptionHandler([$this, self::EXCEPTION_HANDLER]);
123 $this->system->registerShutdownFunction([$this, self::SHUTDOWN_HANDLER]);
124
125 $this->isRegistered = true;
126 }
127
128 return $this;
129 }
130
135 public function unregister()
136 {
137 if ($this->isRegistered) {
138 $this->system->restoreExceptionHandler();
139 $this->system->restoreErrorHandler();
140
141 $this->isRegistered = false;
142 }
143
144 return $this;
145 }
146
152 public function allowQuit($exit = null)
153 {
154 if (func_num_args() == 0) {
155 return $this->allowQuit;
156 }
157
158 return $this->allowQuit = (bool) $exit;
159 }
160
167 public function silenceErrorsInPaths($patterns, $levels = 10240)
168 {
169 $this->silencedPatterns = array_merge(
170 $this->silencedPatterns,
171 array_map(
172 function ($pattern) use ($levels) {
173 return [
174 "pattern" => $pattern,
175 "levels" => $levels,
176 ];
177 },
178 (array) $patterns
179 )
180 );
181 return $this;
182 }
183
184
190 public function getSilenceErrorsInPaths()
191 {
192 return $this->silencedPatterns;
193 }
194
195 /*
196 * Should Whoops send HTTP error code to the browser if possible?
197 * Whoops will by default send HTTP code 500, but you may wish to
198 * use 502, 503, or another 5xx family code.
199 *
200 * @param bool|int $code
201 * @return int|false
202 */
203 public function sendHttpCode($code = null)
204 {
205 if (func_num_args() == 0) {
206 return $this->sendHttpCode;
207 }
208
209 if (!$code) {
210 return $this->sendHttpCode = false;
211 }
212
213 if ($code === true) {
214 $code = 500;
215 }
216
217 if ($code < 400 || 600 <= $code) {
218 throw new InvalidArgumentException(
219 "Invalid status code '$code', must be 4xx or 5xx"
220 );
221 }
222
223 return $this->sendHttpCode = $code;
224 }
225
232 public function writeToOutput($send = null)
233 {
234 if (func_num_args() == 0) {
235 return $this->sendOutput;
236 }
237
238 return $this->sendOutput = (bool) $send;
239 }
240
248 public function handleException($exception)
249 {
250 // Walk the registered handlers in the reverse order
251 // they were registered, and pass off the exception
252 $inspector = $this->getInspector($exception);
253
254 // Capture output produced while handling the exception,
255 // we might want to send it straight away to the client,
256 // or return it silently.
257 $this->system->startOutputBuffering();
258
259 // Just in case there are no handlers:
260 $handlerResponse = null;
261 $handlerContentType = null;
262
263 foreach (array_reverse($this->handlerStack) as $handler) {
264 $handler->setRun($this);
265 $handler->setInspector($inspector);
266 $handler->setException($exception);
267
268 // The HandlerInterface does not require an Exception passed to handle()
269 // and neither of our bundled handlers use it.
270 // However, 3rd party handlers may have already relied on this parameter,
271 // and removing it would be possibly breaking for users.
272 $handlerResponse = $handler->handle($exception);
273
274 // Collect the content type for possible sending in the headers.
275 $handlerContentType = method_exists($handler, 'contentType') ? $handler->contentType() : null;
276
277 if (in_array($handlerResponse, [Handler::LAST_HANDLER, Handler::QUIT])) {
278 // The Handler has handled the exception in some way, and
279 // wishes to quit execution (Handler::QUIT), or skip any
280 // other handlers (Handler::LAST_HANDLER). If $this->allowQuit
281 // is false, Handler::QUIT behaves like Handler::LAST_HANDLER
282 break;
283 }
284 }
285
286 $willQuit = $handlerResponse == Handler::QUIT && $this->allowQuit();
287
288 $output = $this->system->cleanOutputBuffer();
289
290 // If we're allowed to, send output generated by handlers directly
291 // to the output, otherwise, and if the script doesn't quit, return
292 // it so that it may be used by the caller
293 if ($this->writeToOutput()) {
294 // @todo Might be able to clean this up a bit better
295 if ($willQuit) {
296 // Cleanup all other output buffers before sending our output:
297 while ($this->system->getOutputBufferLevel() > 0) {
298 $this->system->endOutputBuffering();
299 }
300
301 // Send any headers if needed:
302 if (Misc::canSendHeaders() && $handlerContentType) {
303 header("Content-Type: {$handlerContentType}");
304 }
305 }
306
307 $this->writeToOutputNow($output);
308 }
309
310 if ($willQuit) {
311 // HHVM fix for https://github.com/facebook/hhvm/issues/4055
312 $this->system->flushOutputBuffer();
313
314 $this->system->stopExecution(1);
315 }
316
317 return $output;
318 }
319
334 public function handleError($level, $message, $file = null, $line = null)
335 {
336 if ($level & $this->system->getErrorReportingLevel()) {
337 foreach ($this->silencedPatterns as $entry) {
338 $pathMatches = (bool) preg_match($entry["pattern"], $file);
339 $levelMatches = $level & $entry["levels"];
340 if ($pathMatches && $levelMatches) {
341 // Ignore the error, abort handling
342 // See https://github.com/filp/whoops/issues/418
343 return true;
344 }
345 }
346
347 // XXX we pass $level for the "code" param only for BC reasons.
348 // see https://github.com/filp/whoops/issues/267
349 $exception = new ErrorException($message, /*code*/ $level, /*severity*/ $level, $file, $line);
350 if ($this->canThrowExceptions) {
351 throw $exception;
352 } else {
353 $this->handleException($exception);
354 }
355 // Do not propagate errors which were already handled by Whoops.
356 return true;
357 }
358
359 // Propagate error to the next handler, allows error_get_last() to
360 // work on silenced errors.
361 return false;
362 }
363
367 public function handleShutdown()
368 {
369 // If we reached this step, we are in shutdown handler.
370 // An exception thrown in a shutdown handler will not be propagated
371 // to the exception handler. Pass that information along.
372 $this->canThrowExceptions = false;
373
374 $error = $this->system->getLastError();
375 if ($error && Misc::isLevelFatal($error['type'])) {
376 // If there was a fatal error,
377 // it was not handled in handleError yet.
378 $this->handleError(
379 $error['type'],
380 $error['message'],
381 $error['file'],
382 $error['line']
383 );
384 }
385 }
386
391 private $canThrowExceptions = true;
392
398 private function writeToOutputNow($output)
399 {
400 if ($this->sendHttpCode() && \Whoops\Util\Misc::canSendHeaders()) {
401 $this->system->setHttpResponseCode(
402 $this->sendHttpCode()
403 );
404 }
405
406 echo $output;
407
408 return $this;
409 }
410}
An exception for terminatinating execution or to throw for unit testing.
Wraps ErrorException; mostly used for typing (at least now) to easily cleanup the stack trace of redu...
Wrapper for Closures passed as handlers.
Abstract implementation of a Handler.
Definition: Handler.php:16
writeToOutputNow($output)
Echo something to the browser.
Definition: Run.php:398
writeToOutput($send=null)
Should Whoops push output directly to the client? If this is false, output will be returned by handle...
Definition: Run.php:232
unregister()
Unregisters all handlers registered by this Whoops\Run instance.
Definition: Run.php:135
clearHandlers()
Clears all handlers in the handlerStack, including the default PrettyPage handler.
Definition: Run.php:92
__construct(SystemFacade $system=null)
Definition: Run.php:38
silenceErrorsInPaths($patterns, $levels=10240)
Silence particular errors in particular files.
Definition: Run.php:167
getInspector($exception)
Definition: Run.php:102
allowQuit($exit=null)
Should Whoops allow Handlers to force the script to quit?
Definition: Run.php:152
handleShutdown()
Special case to deal with Fatal errors and the like.
Definition: Run.php:367
$system
Definition: Run.php:36
getHandlers()
Returns an array with all handlers, in the order they were added to the stack.
Definition: Run.php:82
handleException($exception)
Handles an exception, ultimately generating a Whoops error page.
Definition: Run.php:248
getSilenceErrorsInPaths()
Returns an array with silent errors in path configuration.
Definition: Run.php:190
$isRegistered
Definition: Run.php:20
pushHandler($handler)
Pushes a handler to the end of the stack.
Definition: Run.php:50
handleError($level, $message, $file=null, $line=null)
Converts generic PHP errors to \ErrorException instances, before passing them off to be handled.
Definition: Run.php:334
popHandler()
Removes the last handler in the stack and returns it.
Definition: Run.php:72
sendHttpCode($code=null)
Should Whoops send HTTP error code to the browser if possible? Whoops will by default send HTTP code ...
Definition: Run.php:203
$code
Definition: example_050.php:99
catch(Exception $e) $message
Whoops - php errors for cool kids.
$handler