ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
Run.php
Go to the documentation of this file.
1 <?php
7 namespace Whoops;
8 
17 
18 final class Run implements RunInterface
19 {
20  private $isRegistered;
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)) {
53  $handler = new CallbackHandler($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 }
clearHandlers()
Clears all handlers in the handlerStack, including the default PrettyPage handler.
Definition: Run.php:92
$error
Definition: Error.php:17
$isRegistered
Definition: Run.php:20
handleException($exception)
Handles an exception, ultimately generating a Whoops error page.
Definition: Run.php:248
$code
Definition: example_050.php:99
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
handleError($level, $message, $file=null, $line=null)
Converts generic PHP errors to instances, before passing them off to be handled. ...
Definition: Run.php:334
getInspector($exception)
Definition: Run.php:102
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
writeToOutputNow($output)
Echo something to the browser.
Definition: Run.php:398
if(!is_dir( $entity_dir)) exit("Fatal Error ([A-Za-z0-9]+)\+" &#(? foreach( $entity_files as $file) $output
silenceErrorsInPaths($patterns, $levels=10240)
Silence particular errors in particular files.
Definition: Run.php:167
handleException(CrawlerException $ex)
allowQuit($exit=null)
Should Whoops allow Handlers to force the script to quit?
Definition: Run.php:152
getHandlers()
Returns an array with all handlers, in the order they were added to the stack.
Definition: Run.php:82
__construct(SystemFacade $system=null)
Definition: Run.php:38
Whoops - php errors for cool kids.
Add a drawing to the header
Definition: 04printing.php:69
Create styles array
The data for the language used.
unregister()
Unregisters all handlers registered by this Whoops instance.
Definition: Run.php:135
pushHandler($handler)
Pushes a handler to the end of the stack.
Definition: Run.php:50
handleShutdown()
Special case to deal with Fatal errors and the like.
Definition: Run.php:367
getSilenceErrorsInPaths()
Returns an array with silent errors in path configuration.
Definition: Run.php:190
popHandler()
Removes the last handler in the stack and returns it.
Definition: Run.php:72
Wrapper for Closures passed as handlers.
if(!file_exists("$old.txt")) if($old===$new) if(file_exists("$new.txt")) $file
Wraps ErrorException; mostly used for typing (at least now) to easily cleanup the stack trace of redu...
$system
Definition: Run.php:36