PKZ' LICENSE.mdnuW+A# The MIT License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PKZ / CHANGELOG.mdnuW+A# CHANGELOG ## v2.18.0 * Line numbers are now clickable. ## v2.17.0 * Support cursor IDE. ## v2.16.0 * Support PHP `8.4`. * Drop support for PHP older than `7.1`. ## v2.15.4 * Improve link color in comments. ## v2.15.3 * Improve performance of the syntax highlighting (#758). ## v2.15.2 * Fixed missing code highlight, which additionally led to issue with switching tabs, between application and all frames ([#747](https://github.com/filp/whoops/issues/747)). ## v2.15.1 * Fixed bug with PrettyPageHandler "*Calling `getFrameFilters` method on null*" ([#751](https://github.com/filp/whoops/pull/751)). ## v2.15.0 * Add addFrameFilter ([#749](https://github.com/filp/whoops/pull/749)) ## v2.14.6 * Upgraded prismJS to version `1.29.0` due to security issue ([#741][i741]). [i741]: https://github.com/filp/whoops/pull/741 ## v2.14.5 * Allow `ArrayAccess` on super globals. ## v2.14.4 * Fix PHP `5.5` support. * Allow to use psr/log `2` or `3`. ## v2.14.3 * Support PHP `8.1`. ## v2.14.1 * Fix syntax highlighting scrolling too far. * Improve the way we detect xdebug linkformat. ## v2.14.0 * Switched syntax highlighting to Prism.js. Avoids licensing issues with prettify, and uses a maintained, modern project. ## v2.13.0 * Add Netbeans editor. ## v2.12.1 * Avoid redirecting away from an error. ## v2.12.0 * Hide non-string values in super globals when requested. ## v2.11.0 * Customize exit code. ## v2.10.0 * Better chaining on handler classes. ## v2.9.2 * Fix copy button styles. ## v2.9.1 * Fix xdebug function crash on PHP `8`. ## v2.9.0 * `JsonResponseHandler` includes the exception code. ## v2.8.0 * Support PHP 8. ## v2.7.3 * `PrettyPageHandler` functionality to hide superglobal keys has a clearer name (`hideSuperglobalKey`). ## v2.7.2 * `PrettyPageHandler` now accepts custom js files. * `PrettyPageHandler` and `templateHelper` is now accessible through inheritance. ## v2.7.1 * Fix a PHP warning in some cases with anonymous classes. ## v2.7.0 * Added `removeFirstHandler` and `removeLastHandler`. ## v2.6.0 * Fix 2.4.0 `pushHandler` changing the order of handlers. ## v2.5.1 * Fix error messaging in a rare case. ## v2.5.0 * Automatically configure xdebug if available. ## v2.4.1 * Try harder to close all output buffers. ## v2.4.0 * Allow to prepend and append handlers. ## v2.3.2 * Various fixes from the community. ## v2.3.1 * Prevent exception in Whoops when caught exception frame is not related to real file. ## v2.3.0 * Show previous exception messages. ## v2.2.0 * Support PHP `7.2`. ## v2.1.0 * Add a `SystemFacade` to allow clients to override Whoops behavior. * Show frame arguments in `PrettyPageHandler`. * Highlight the line with the error. * Add icons to search on Google and Stack Overflow. ## v2.0.0 Backwards compatibility breaking changes: * `Run` class is now `final`. If you inherited from `Run`, please now instead use a custom `SystemFacade` injected into the `Run` constructor, or contribute your changes to our core. * PHP < 5.5 support dropped. PKZ ))(src/Whoops/Exception/FrameCollection.phpnuW+A */ namespace Whoops\Exception; use ArrayAccess; use ArrayIterator; use Countable; use IteratorAggregate; use ReturnTypeWillChange; use Serializable; use UnexpectedValueException; /** * Exposes a fluent interface for dealing with an ordered list * of stack-trace frames. */ class FrameCollection implements ArrayAccess, IteratorAggregate, Serializable, Countable { /** * @var array[] */ private $frames; public function __construct(array $frames) { $this->frames = array_map(function ($frame) { return new Frame($frame); }, $frames); } /** * Filters frames using a callable, returns the same FrameCollection * * @param callable $callable * @return FrameCollection */ public function filter($callable) { $this->frames = array_values(array_filter($this->frames, $callable)); return $this; } /** * Map the collection of frames * * @param callable $callable * @return FrameCollection */ public function map($callable) { // Contain the map within a higher-order callable // that enforces type-correctness for the $callable $this->frames = array_map(function ($frame) use ($callable) { $frame = call_user_func($callable, $frame); if (!$frame instanceof Frame) { throw new UnexpectedValueException( "Callable to " . __CLASS__ . "::map must return a Frame object" ); } return $frame; }, $this->frames); return $this; } /** * Returns an array with all frames, does not affect * the internal array. * * @todo If this gets any more complex than this, * have getIterator use this method. * @see FrameCollection::getIterator * @return array */ public function getArray() { return $this->frames; } /** * @see IteratorAggregate::getIterator * @return ArrayIterator */ #[ReturnTypeWillChange] public function getIterator() { return new ArrayIterator($this->frames); } /** * @see ArrayAccess::offsetExists * @param int $offset */ #[ReturnTypeWillChange] public function offsetExists($offset) { return isset($this->frames[$offset]); } /** * @see ArrayAccess::offsetGet * @param int $offset */ #[ReturnTypeWillChange] public function offsetGet($offset) { return $this->frames[$offset]; } /** * @see ArrayAccess::offsetSet * @param int $offset */ #[ReturnTypeWillChange] public function offsetSet($offset, $value) { throw new \Exception(__CLASS__ . ' is read only'); } /** * @see ArrayAccess::offsetUnset * @param int $offset */ #[ReturnTypeWillChange] public function offsetUnset($offset) { throw new \Exception(__CLASS__ . ' is read only'); } /** * @see Countable::count * @return int */ #[ReturnTypeWillChange] public function count() { return count($this->frames); } /** * Count the frames that belongs to the application. * * @return int */ public function countIsApplication() { return count(array_filter($this->frames, function (Frame $f) { return $f->isApplication(); })); } /** * @see Serializable::serialize * @return string */ #[ReturnTypeWillChange] public function serialize() { return serialize($this->frames); } /** * @see Serializable::unserialize * @param string $serializedFrames */ #[ReturnTypeWillChange] public function unserialize($serializedFrames) { $this->frames = unserialize($serializedFrames); } public function __serialize() { return $this->frames; } public function __unserialize(array $serializedFrames) { $this->frames = $serializedFrames; } /** * @param Frame[] $frames Array of Frame instances, usually from $e->getPrevious() */ public function prependFrames(array $frames) { $this->frames = array_merge($frames, $this->frames); } /** * Gets the innermost part of stack trace that is not the same as that of outer exception * * @param FrameCollection $parentFrames Outer exception frames to compare tail against * @return Frame[] */ public function topDiff(FrameCollection $parentFrames) { $diff = $this->frames; $parentFrames = $parentFrames->getArray(); $p = count($parentFrames)-1; for ($i = count($diff)-1; $i >= 0 && $p >= 0; $i--) { /** @var Frame $tailFrame */ $tailFrame = $diff[$i]; if ($tailFrame->equals($parentFrames[$p])) { unset($diff[$i]); } $p--; } return $diff; } } PKZ.%%"src/Whoops/Exception/Inspector.phpnuW+A */ namespace Whoops\Exception; use Whoops\Inspector\InspectorFactory; use Whoops\Inspector\InspectorInterface; use Whoops\Util\Misc; class Inspector implements InspectorInterface { /** * @var \Throwable */ private $exception; /** * @var \Whoops\Exception\FrameCollection */ private $frames; /** * @var \Whoops\Exception\Inspector */ private $previousExceptionInspector; /** * @var \Throwable[] */ private $previousExceptions; /** * @var \Whoops\Inspector\InspectorFactoryInterface|null */ protected $inspectorFactory; /** * @param \Throwable $exception The exception to inspect * @param \Whoops\Inspector\InspectorFactoryInterface $factory */ public function __construct($exception, $factory = null) { $this->exception = $exception; $this->inspectorFactory = $factory ?: new InspectorFactory(); } /** * @return \Throwable */ public function getException() { return $this->exception; } /** * @return string */ public function getExceptionName() { return get_class($this->exception); } /** * @return string */ public function getExceptionMessage() { return $this->extractDocrefUrl($this->exception->getMessage())['message']; } /** * @return string[] */ public function getPreviousExceptionMessages() { return array_map(function ($prev) { /** @var \Throwable $prev */ return $this->extractDocrefUrl($prev->getMessage())['message']; }, $this->getPreviousExceptions()); } /** * @return int[] */ public function getPreviousExceptionCodes() { return array_map(function ($prev) { /** @var \Throwable $prev */ return $prev->getCode(); }, $this->getPreviousExceptions()); } /** * Returns a url to the php-manual related to the underlying error - when available. * * @return string|null */ public function getExceptionDocrefUrl() { return $this->extractDocrefUrl($this->exception->getMessage())['url']; } private function extractDocrefUrl($message) { $docref = [ 'message' => $message, 'url' => null, ]; // php embbeds urls to the manual into the Exception message with the following ini-settings defined // http://php.net/manual/en/errorfunc.configuration.php#ini.docref-root if (!ini_get('html_errors') || !ini_get('docref_root')) { return $docref; } $pattern = "/\[(?:[^<]+)<\/a>\]/"; if (preg_match($pattern, $message, $matches)) { // -> strip those automatically generated links from the exception message $docref['message'] = preg_replace($pattern, '', $message, 1); $docref['url'] = $matches[1]; } return $docref; } /** * Does the wrapped Exception has a previous Exception? * @return bool */ public function hasPreviousException() { return $this->previousExceptionInspector || $this->exception->getPrevious(); } /** * Returns an Inspector for a previous Exception, if any. * @todo Clean this up a bit, cache stuff a bit better. * @return Inspector */ public function getPreviousExceptionInspector() { if ($this->previousExceptionInspector === null) { $previousException = $this->exception->getPrevious(); if ($previousException) { $this->previousExceptionInspector = $this->inspectorFactory->create($previousException); } } return $this->previousExceptionInspector; } /** * Returns an array of all previous exceptions for this inspector's exception * @return \Throwable[] */ public function getPreviousExceptions() { if ($this->previousExceptions === null) { $this->previousExceptions = []; $prev = $this->exception->getPrevious(); while ($prev !== null) { $this->previousExceptions[] = $prev; $prev = $prev->getPrevious(); } } return $this->previousExceptions; } /** * Returns an iterator for the inspected exception's * frames. * * @param array $frameFilters * * @return \Whoops\Exception\FrameCollection */ public function getFrames(array $frameFilters = []) { if ($this->frames === null) { $frames = $this->getTrace($this->exception); // Fill empty line/file info for call_user_func_array usages (PHP Bug #44428) foreach ($frames as $k => $frame) { if (empty($frame['file'])) { // Default values when file and line are missing $file = '[internal]'; $line = 0; $next_frame = !empty($frames[$k + 1]) ? $frames[$k + 1] : []; if ($this->isValidNextFrame($next_frame)) { $file = $next_frame['file']; $line = $next_frame['line']; } $frames[$k]['file'] = $file; $frames[$k]['line'] = $line; } } // Find latest non-error handling frame index ($i) used to remove error handling frames $i = 0; foreach ($frames as $k => $frame) { if ($frame['file'] == $this->exception->getFile() && $frame['line'] == $this->exception->getLine()) { $i = $k; } } // Remove error handling frames if ($i > 0) { array_splice($frames, 0, $i); } $firstFrame = $this->getFrameFromException($this->exception); array_unshift($frames, $firstFrame); $this->frames = new FrameCollection($frames); if ($previousInspector = $this->getPreviousExceptionInspector()) { // Keep outer frame on top of the inner one $outerFrames = $this->frames; $newFrames = clone $previousInspector->getFrames(); // I assume it will always be set, but let's be safe if (isset($newFrames[0])) { $newFrames[0]->addComment( $previousInspector->getExceptionMessage(), 'Exception message:' ); } $newFrames->prependFrames($outerFrames->topDiff($newFrames)); $this->frames = $newFrames; } // Apply frame filters callbacks on the frames stack if (!empty($frameFilters)) { foreach ($frameFilters as $filterCallback) { $this->frames->filter($filterCallback); } } } return $this->frames; } /** * Gets the backtrace from an exception. * * If xdebug is installed * * @param \Throwable $e * @return array */ protected function getTrace($e) { $traces = $e->getTrace(); // Get trace from xdebug if enabled, failure exceptions only trace to the shutdown handler by default if (!$e instanceof \ErrorException) { return $traces; } if (!Misc::isLevelFatal($e->getSeverity())) { return $traces; } if (!extension_loaded('xdebug') || !function_exists('xdebug_is_enabled') || !xdebug_is_enabled()) { return $traces; } // Use xdebug to get the full stack trace and remove the shutdown handler stack trace $stack = array_reverse(xdebug_get_function_stack()); $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $traces = array_diff_key($stack, $trace); return $traces; } /** * Given an exception, generates an array in the format * generated by Exception::getTrace() * @param \Throwable $exception * @return array */ protected function getFrameFromException($exception) { return [ 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'class' => get_class($exception), 'args' => [ $exception->getMessage(), ], ]; } /** * Given an error, generates an array in the format * generated by ErrorException * @param ErrorException $exception * @return array */ protected function getFrameFromError(ErrorException $exception) { return [ 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'class' => null, 'args' => [], ]; } /** * Determine if the frame can be used to fill in previous frame's missing info * happens for call_user_func and call_user_func_array usages (PHP Bug #44428) * * @return bool */ protected function isValidNextFrame(array $frame) { if (empty($frame['file'])) { return false; } if (empty($frame['line'])) { return false; } if (empty($frame['function']) || !stristr($frame['function'], 'call_user_func')) { return false; } return true; } } PKZ9Un "src/Whoops/Exception/Formatter.phpnuW+A */ namespace Whoops\Exception; use Whoops\Inspector\InspectorInterface; class Formatter { /** * Returns all basic information about the exception in a simple array * for further convertion to other languages * @param InspectorInterface $inspector * @param bool $shouldAddTrace * @param array $frameFilters * @return array */ public static function formatExceptionAsDataArray(InspectorInterface $inspector, $shouldAddTrace, array $frameFilters = []) { $exception = $inspector->getException(); $response = [ 'type' => get_class($exception), 'message' => $exception->getMessage(), 'code' => $exception->getCode(), 'file' => $exception->getFile(), 'line' => $exception->getLine(), ]; if ($shouldAddTrace) { $frames = $inspector->getFrames($frameFilters); $frameData = []; foreach ($frames as $frame) { /** @var Frame $frame */ $frameData[] = [ 'file' => $frame->getFile(), 'line' => $frame->getLine(), 'function' => $frame->getFunction(), 'class' => $frame->getClass(), 'args' => $frame->getArgs(), ]; } $response['trace'] = $frameData; } return $response; } public static function formatExceptionPlain(InspectorInterface $inspector) { $message = $inspector->getException()->getMessage(); $frames = $inspector->getFrames(); $plain = $inspector->getExceptionName(); $plain .= ' thrown with message "'; $plain .= $message; $plain .= '"'."\n\n"; $plain .= "Stacktrace:\n"; foreach ($frames as $i => $frame) { $plain .= "#". (count($frames) - $i - 1). " "; $plain .= $frame->getClass() ?: ''; $plain .= $frame->getClass() && $frame->getFunction() ? ":" : ""; $plain .= $frame->getFunction() ?: ''; $plain .= ' in '; $plain .= ($frame->getFile() ?: '<#unknown>'); $plain .= ':'; $plain .= (int) $frame->getLine(). "\n"; } return $plain; } } PKZ"sCcc'src/Whoops/Exception/ErrorException.phpnuW+A */ namespace Whoops\Exception; use ErrorException as BaseErrorException; /** * Wraps ErrorException; mostly used for typing (at least now) * to easily cleanup the stack trace of redundant info. */ class ErrorException extends BaseErrorException { } PKZŢsrc/Whoops/Exception/Frame.phpnuW+A */ namespace Whoops\Exception; use InvalidArgumentException; use Serializable; class Frame implements Serializable { /** * @var array */ protected $frame; /** * @var string */ protected $fileContentsCache; /** * @var array[] */ protected $comments = []; /** * @var bool */ protected $application; public function __construct(array $frame) { $this->frame = $frame; } /** * @param bool $shortened * @return string|null */ public function getFile($shortened = false) { if (empty($this->frame['file'])) { return null; } $file = $this->frame['file']; // Check if this frame occurred within an eval(). // @todo: This can be made more reliable by checking if we've entered // eval() in a previous trace, but will need some more work on the upper // trace collector(s). if (preg_match('/^(.*)\((\d+)\) : (?:eval\(\)\'d|assert) code$/', $file, $matches)) { $file = $this->frame['file'] = $matches[1]; $this->frame['line'] = (int) $matches[2]; } if ($shortened && is_string($file)) { // Replace the part of the path that all frames have in common, and add 'soft hyphens' for smoother line-breaks. $dirname = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))); if ($dirname !== '/') { $file = str_replace($dirname, "…", $file); } $file = str_replace("/", "/­", $file); } return $file; } /** * @return int|null */ public function getLine() { return isset($this->frame['line']) ? $this->frame['line'] : null; } /** * @return string|null */ public function getClass() { return isset($this->frame['class']) ? $this->frame['class'] : null; } /** * @return string|null */ public function getFunction() { return isset($this->frame['function']) ? $this->frame['function'] : null; } /** * @return array */ public function getArgs() { return isset($this->frame['args']) ? (array) $this->frame['args'] : []; } /** * Returns the full contents of the file for this frame, * if it's known. * @return string|null */ public function getFileContents() { if ($this->fileContentsCache === null && $filePath = $this->getFile()) { // Leave the stage early when 'Unknown' or '[internal]' is passed // this would otherwise raise an exception when // open_basedir is enabled. if ($filePath === "Unknown" || $filePath === '[internal]') { return null; } try { $this->fileContentsCache = file_get_contents($filePath); } catch (ErrorException $exception) { // Internal file paths of PHP extensions cannot be opened } } return $this->fileContentsCache; } /** * Adds a comment to this frame, that can be received and * used by other handlers. For example, the PrettyPage handler * can attach these comments under the code for each frame. * * An interesting use for this would be, for example, code analysis * & annotations. * * @param string $comment * @param string $context Optional string identifying the origin of the comment */ public function addComment($comment, $context = 'global') { $this->comments[] = [ 'comment' => $comment, 'context' => $context, ]; } /** * Returns all comments for this frame. Optionally allows * a filter to only retrieve comments from a specific * context. * * @param string $filter * @return array[] */ public function getComments($filter = null) { $comments = $this->comments; if ($filter !== null) { $comments = array_filter($comments, function ($c) use ($filter) { return $c['context'] == $filter; }); } return $comments; } /** * Returns the array containing the raw frame data from which * this Frame object was built * * @return array */ public function getRawFrame() { return $this->frame; } /** * Returns the contents of the file for this frame as an * array of lines, and optionally as a clamped range of lines. * * NOTE: lines are 0-indexed * * @example * Get all lines for this file * $frame->getFileLines(); // => array( 0 => ' '...', ...) * @example * Get one line for this file, starting at line 10 (zero-indexed, remember!) * $frame->getFileLines(9, 1); // array( 9 => '...' ) * * @throws InvalidArgumentException if $length is less than or equal to 0 * @param int $start * @param int $length * @return string[]|null */ public function getFileLines($start = 0, $length = null) { if (null !== ($contents = $this->getFileContents())) { $lines = explode("\n", $contents); // Get a subset of lines from $start to $end if ($length !== null) { $start = (int) $start; $length = (int) $length; if ($start < 0) { $start = 0; } if ($length <= 0) { throw new InvalidArgumentException( "\$length($length) cannot be lower or equal to 0" ); } $lines = array_slice($lines, $start, $length, true); } return $lines; } } /** * Implements the Serializable interface, with special * steps to also save the existing comments. * * @see Serializable::serialize * @return string */ public function serialize() { $frame = $this->frame; if (!empty($this->comments)) { $frame['_comments'] = $this->comments; } return serialize($frame); } public function __serialize() { $frame = $this->frame; if (!empty($this->comments)) { $frame['_comments'] = $this->comments; } return $frame; } /** * Unserializes the frame data, while also preserving * any existing comment data. * * @see Serializable::unserialize * @param string $serializedFrame */ public function unserialize($serializedFrame) { $frame = unserialize($serializedFrame); if (!empty($frame['_comments'])) { $this->comments = $frame['_comments']; unset($frame['_comments']); } $this->frame = $frame; } public function __unserialize($frame) { if (!empty($frame['_comments'])) { $this->comments = $frame['_comments']; unset($frame['_comments']); } $this->frame = $frame; } /** * Compares Frame against one another * @param Frame $frame * @return bool */ public function equals(Frame $frame) { if (!$this->getFile() || $this->getFile() === 'Unknown' || !$this->getLine()) { return false; } return $frame->getFile() === $this->getFile() && $frame->getLine() === $this->getLine(); } /** * Returns whether this frame belongs to the application or not. * * @return boolean */ public function isApplication() { return $this->application; } /** * Mark as an frame belonging to the application. * * @param boolean $application */ public function setApplication($application) { $this->application = $application; } } PKZىsrc/Whoops/RunInterface.phpnuW+A */ namespace Whoops; use InvalidArgumentException; use Whoops\Exception\ErrorException; use Whoops\Handler\HandlerInterface; interface RunInterface { const EXCEPTION_HANDLER = "handleException"; const ERROR_HANDLER = "handleError"; const SHUTDOWN_HANDLER = "handleShutdown"; /** * Pushes a handler to the end of the stack * * @throws InvalidArgumentException If argument is not callable or instance of HandlerInterface * @param Callable|HandlerInterface $handler * @return Run */ public function pushHandler($handler); /** * Removes the last handler in the stack and returns it. * Returns null if there"s nothing else to pop. * * @return null|HandlerInterface */ public function popHandler(); /** * Returns an array with all handlers, in the * order they were added to the stack. * * @return array */ public function getHandlers(); /** * Clears all handlers in the handlerStack, including * the default PrettyPage handler. * * @return Run */ public function clearHandlers(); /** * @return array */ public function getFrameFilters(); /** * @return Run */ public function clearFrameFilters(); /** * Registers this instance as an error handler. * * @return Run */ public function register(); /** * Unregisters all handlers registered by this Whoops\Run instance * * @return Run */ public function unregister(); /** * Should Whoops allow Handlers to force the script to quit? * * @param bool|int $exit * @return bool */ public function allowQuit($exit = null); /** * Silence particular errors in particular files * * @param array|string $patterns List or a single regex pattern to match * @param int $levels Defaults to E_STRICT | E_DEPRECATED * @return \Whoops\Run */ public function silenceErrorsInPaths($patterns, $levels = 10240); /** * Should Whoops send HTTP error code to the browser if possible? * Whoops will by default send HTTP code 500, but you may wish to * use 502, 503, or another 5xx family code. * * @param bool|int $code * @return int|false */ public function sendHttpCode($code = null); /** * Should Whoops exit with a specific code on the CLI if possible? * Whoops will exit with 1 by default, but you can specify something else. * * @param int $code * @return int */ public function sendExitCode($code = null); /** * Should Whoops push output directly to the client? * If this is false, output will be returned by handleException * * @param bool|int $send * @return bool */ public function writeToOutput($send = null); /** * Handles an exception, ultimately generating a Whoops error * page. * * @param \Throwable $exception * @return string Output generated by handlers */ public function handleException($exception); /** * Converts generic PHP errors to \ErrorException * instances, before passing them off to be handled. * * This method MUST be compatible with set_error_handler. * * @param int $level * @param string $message * @param string $file * @param int $line * * @return bool * @throws ErrorException */ public function handleError($level, $message, $file = null, $line = null); /** * Special case to deal with Fatal errors and the like. */ public function handleShutdown(); /** * Registers a filter callback in the frame filters stack. * * @param callable $filterCallback * @return \Whoops\Run */ public function addFrameFilter($filterCallback); } PKZe5++2src/Whoops/Inspector/InspectorFactoryInterface.phpnuW+A */ namespace Whoops\Inspector; interface InspectorFactoryInterface { /** * @param \Throwable $exception * @return InspectorInterface */ public function create($exception); } PKZ^>+src/Whoops/Inspector/InspectorInterface.phpnuW+A */ namespace Whoops\Inspector; interface InspectorInterface { /** * @return \Throwable */ public function getException(); /** * @return string */ public function getExceptionName(); /** * @return string */ public function getExceptionMessage(); /** * @return string[] */ public function getPreviousExceptionMessages(); /** * @return int[] */ public function getPreviousExceptionCodes(); /** * Returns a url to the php-manual related to the underlying error - when available. * * @return string|null */ public function getExceptionDocrefUrl(); /** * Does the wrapped Exception has a previous Exception? * @return bool */ public function hasPreviousException(); /** * Returns an Inspector for a previous Exception, if any. * @todo Clean this up a bit, cache stuff a bit better. * @return InspectorInterface */ public function getPreviousExceptionInspector(); /** * Returns an array of all previous exceptions for this inspector's exception * @return \Throwable[] */ public function getPreviousExceptions(); /** * Returns an iterator for the inspected exception's * frames. * * @param array $frameFilters * * @return \Whoops\Exception\FrameCollection */ public function getFrames(array $frameFilters = []); } PKZeY)src/Whoops/Inspector/InspectorFactory.phpnuW+A */ namespace Whoops\Inspector; use Whoops\Exception\Inspector; class InspectorFactory implements InspectorFactoryInterface { /** * @param \Throwable $exception * @return InspectorInterface */ public function create($exception) { return new Inspector($exception, $this); } } PKZBU$HH&src/Whoops/Handler/CallbackHandler.phpnuW+A */ namespace Whoops\Handler; use InvalidArgumentException; /** * Wrapper for Closures passed as handlers. Can be used * directly, or will be instantiated automagically by Whoops\Run * if passed to Run::pushHandler */ class CallbackHandler extends Handler { /** * @var callable */ protected $callable; /** * @throws InvalidArgumentException If argument is not callable * @param callable $callable */ public function __construct($callable) { if (!is_callable($callable)) { throw new InvalidArgumentException( 'Argument to ' . __METHOD__ . ' must be valid callable' ); } $this->callable = $callable; } /** * @return int|null */ public function handle() { $exception = $this->getException(); $inspector = $this->getInspector(); $run = $this->getRun(); $callable = $this->callable; // invoke the callable directly, to get simpler stacktraces (in comparison to call_user_func). // this assumes that $callable is a properly typed php-callable, which we check in __construct(). return $callable($exception, $inspector, $run); } } PKZzzsrc/Whoops/Handler/Handler.phpnuW+A */ namespace Whoops\Handler; use Whoops\Inspector\InspectorInterface; use Whoops\RunInterface; /** * Abstract implementation of a Handler. */ abstract class Handler implements HandlerInterface { /* Return constants that can be returned from Handler::handle to message the handler walker. */ const DONE = 0x10; // returning this is optional, only exists for // semantic purposes /** * The Handler has handled the Throwable in some way, and wishes to skip any other Handler. * Execution will continue. */ const LAST_HANDLER = 0x20; /** * The Handler has handled the Throwable in some way, and wishes to quit/stop execution */ const QUIT = 0x30; /** * @var RunInterface */ private $run; /** * @var InspectorInterface $inspector */ private $inspector; /** * @var \Throwable $exception */ private $exception; /** * @param RunInterface $run */ public function setRun(RunInterface $run) { $this->run = $run; } /** * @return RunInterface */ protected function getRun() { return $this->run; } /** * @param InspectorInterface $inspector */ public function setInspector(InspectorInterface $inspector) { $this->inspector = $inspector; } /** * @return InspectorInterface */ protected function getInspector() { return $this->inspector; } /** * @param \Throwable $exception */ public function setException($exception) { $this->exception = $exception; } /** * @return \Throwable */ protected function getException() { return $this->exception; } } PKZ A )src/Whoops/Handler/XmlResponseHandler.phpnuW+A */ namespace Whoops\Handler; use SimpleXMLElement; use Whoops\Exception\Formatter; /** * Catches an exception and converts it to an XML * response. Additionally can also return exception * frames for consumption by an API. */ class XmlResponseHandler extends Handler { /** * @var bool */ private $returnFrames = false; /** * @param bool|null $returnFrames * @return bool|static */ public function addTraceToOutput($returnFrames = null) { if (func_num_args() == 0) { return $this->returnFrames; } $this->returnFrames = (bool) $returnFrames; return $this; } /** * @return int */ public function handle() { $response = [ 'error' => Formatter::formatExceptionAsDataArray( $this->getInspector(), $this->addTraceToOutput(), $this->getRun()->getFrameFilters() ), ]; echo self::toXml($response); return Handler::QUIT; } /** * @return string */ public function contentType() { return 'application/xml'; } /** * @param SimpleXMLElement $node Node to append data to, will be modified in place * @param array|\Traversable $data * @return SimpleXMLElement The modified node, for chaining */ private static function addDataToNode(\SimpleXMLElement $node, $data) { assert(is_array($data) || $data instanceof Traversable); foreach ($data as $key => $value) { if (is_numeric($key)) { // Convert the key to a valid string $key = "unknownNode_". (string) $key; } // Delete any char not allowed in XML element names $key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key); if (is_array($value)) { $child = $node->addChild($key); self::addDataToNode($child, $value); } else { $value = str_replace('&', '&', print_r($value, true)); $node->addChild($key, $value); } } return $node; } /** * The main function for converting to an XML document. * * @param array|\Traversable $data * @return string XML */ private static function toXml($data) { assert(is_array($data) || $data instanceof Traversable); $node = simplexml_load_string(""); return self::addDataToNode($node, $data)->asXML(); } } PKZt7dd(src/Whoops/Handler/PrettyPageHandler.phpnuW+A */ namespace Whoops\Handler; use InvalidArgumentException; use RuntimeException; use Symfony\Component\VarDumper\Cloner\AbstractCloner; use Symfony\Component\VarDumper\Cloner\VarCloner; use UnexpectedValueException; use Whoops\Exception\Formatter; use Whoops\Util\Misc; use Whoops\Util\TemplateHelper; class PrettyPageHandler extends Handler { const EDITOR_SUBLIME = "sublime"; const EDITOR_TEXTMATE = "textmate"; const EDITOR_EMACS = "emacs"; const EDITOR_MACVIM = "macvim"; const EDITOR_PHPSTORM = "phpstorm"; const EDITOR_IDEA = "idea"; const EDITOR_VSCODE = "vscode"; const EDITOR_ATOM = "atom"; const EDITOR_ESPRESSO = "espresso"; const EDITOR_XDEBUG = "xdebug"; const EDITOR_NETBEANS = "netbeans"; const EDITOR_CURSOR = "cursor"; /** * Search paths to be scanned for resources. * * Stored in the reverse order they're declared. * * @var array */ private $searchPaths = []; /** * Fast lookup cache for known resource locations. * * @var array */ private $resourceCache = []; /** * The name of the custom css file. * * @var string|null */ private $customCss = null; /** * The name of the custom js file. * * @var string|null */ private $customJs = null; /** * @var array[] */ private $extraTables = []; /** * @var bool */ private $handleUnconditionally = false; /** * @var string */ private $pageTitle = "Whoops! There was an error."; /** * @var array[] */ private $applicationPaths; /** * @var array[] */ private $blacklist = [ '_GET' => [], '_POST' => [], '_FILES' => [], '_COOKIE' => [], '_SESSION' => [], '_SERVER' => [], '_ENV' => [], ]; /** * An identifier for a known IDE/text editor. * * Either a string, or a calalble that resolves a string, that can be used * to open a given file in an editor. If the string contains the special * substrings %file or %line, they will be replaced with the correct data. * * @example * "txmt://open?url=%file&line=%line" * * @var callable|string $editor */ protected $editor; /** * A list of known editor strings. * * @var array */ protected $editors = [ "sublime" => "subl://open?url=file://%file&line=%line", "textmate" => "txmt://open?url=file://%file&line=%line", "emacs" => "emacs://open?url=file://%file&line=%line", "macvim" => "mvim://open/?url=file://%file&line=%line", "phpstorm" => "phpstorm://open?file=%file&line=%line", "idea" => "idea://open?file=%file&line=%line", "vscode" => "vscode://file/%file:%line", "atom" => "atom://core/open/file?filename=%file&line=%line", "espresso" => "x-espresso://open?filepath=%file&lines=%line", "netbeans" => "netbeans://open/?f=%file:%line", "cursor" => "cursor://file/%file:%line", ]; /** * @var TemplateHelper */ protected $templateHelper; /** * Constructor. * * @return void */ public function __construct() { if (ini_get('xdebug.file_link_format') || get_cfg_var('xdebug.file_link_format')) { // Register editor using xdebug's file_link_format option. $this->editors['xdebug'] = function ($file, $line) { return str_replace(['%f', '%l'], [$file, $line], ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format')); }; // If xdebug is available, use it as default editor. $this->setEditor('xdebug'); } // Add the default, local resource search path: $this->searchPaths[] = __DIR__ . "/../Resources"; // blacklist php provided auth based values $this->blacklist('_SERVER', 'PHP_AUTH_PW'); $this->templateHelper = new TemplateHelper(); if (class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) { $cloner = new VarCloner(); // Only dump object internals if a custom caster exists for performance reasons // https://github.com/filp/whoops/pull/404 $cloner->addCasters(['*' => function ($obj, $a, $stub, $isNested, $filter = 0) { $class = $stub->class; $classes = [$class => $class] + class_parents($obj) + class_implements($obj); foreach ($classes as $class) { if (isset(AbstractCloner::$defaultCasters[$class])) { return $a; } } // Remove all internals return []; }]); $this->templateHelper->setCloner($cloner); } } /** * @return int|null * * @throws \Exception */ public function handle() { if (!$this->handleUnconditionally()) { // Check conditions for outputting HTML: // @todo: Make this more robust if (PHP_SAPI === 'cli') { // Help users who have been relying on an internal test value // fix their code to the proper method if (isset($_ENV['whoops-test'])) { throw new \Exception( 'Use handleUnconditionally instead of whoops-test' .' environment variable' ); } return Handler::DONE; } } $templateFile = $this->getResource("views/layout.html.php"); $cssFile = $this->getResource("css/whoops.base.css"); $zeptoFile = $this->getResource("js/zepto.min.js"); $prismJs = $this->getResource("js/prism.js"); $prismCss = $this->getResource("css/prism.css"); $clipboard = $this->getResource("js/clipboard.min.js"); $jsFile = $this->getResource("js/whoops.base.js"); if ($this->customCss) { $customCssFile = $this->getResource($this->customCss); } if ($this->customJs) { $customJsFile = $this->getResource($this->customJs); } $inspector = $this->getInspector(); $frames = $this->getExceptionFrames(); $code = $this->getExceptionCode(); // List of variables that will be passed to the layout template. $vars = [ "page_title" => $this->getPageTitle(), // @todo: Asset compiler "stylesheet" => file_get_contents($cssFile), "zepto" => file_get_contents($zeptoFile), "prismJs" => file_get_contents($prismJs), "prismCss" => file_get_contents($prismCss), "clipboard" => file_get_contents($clipboard), "javascript" => file_get_contents($jsFile), // Template paths: "header" => $this->getResource("views/header.html.php"), "header_outer" => $this->getResource("views/header_outer.html.php"), "frame_list" => $this->getResource("views/frame_list.html.php"), "frames_description" => $this->getResource("views/frames_description.html.php"), "frames_container" => $this->getResource("views/frames_container.html.php"), "panel_details" => $this->getResource("views/panel_details.html.php"), "panel_details_outer" => $this->getResource("views/panel_details_outer.html.php"), "panel_left" => $this->getResource("views/panel_left.html.php"), "panel_left_outer" => $this->getResource("views/panel_left_outer.html.php"), "frame_code" => $this->getResource("views/frame_code.html.php"), "env_details" => $this->getResource("views/env_details.html.php"), "title" => $this->getPageTitle(), "name" => explode("\\", $inspector->getExceptionName()), "message" => $inspector->getExceptionMessage(), "previousMessages" => $inspector->getPreviousExceptionMessages(), "docref_url" => $inspector->getExceptionDocrefUrl(), "code" => $code, "previousCodes" => $inspector->getPreviousExceptionCodes(), "plain_exception" => Formatter::formatExceptionPlain($inspector), "frames" => $frames, "has_frames" => !!count($frames), "handler" => $this, "handlers" => $this->getRun()->getHandlers(), "active_frames_tab" => count($frames) && $frames->offsetGet(0)->isApplication() ? 'application' : 'all', "has_frames_tabs" => $this->getApplicationPaths(), "tables" => [ "GET Data" => $this->masked($_GET, '_GET'), "POST Data" => $this->masked($_POST, '_POST'), "Files" => isset($_FILES) ? $this->masked($_FILES, '_FILES') : [], "Cookies" => $this->masked($_COOKIE, '_COOKIE'), "Session" => isset($_SESSION) ? $this->masked($_SESSION, '_SESSION') : [], "Server/Request Data" => $this->masked($_SERVER, '_SERVER'), "Environment Variables" => $this->masked($_ENV, '_ENV'), ], ]; if (isset($customCssFile)) { $vars["stylesheet"] .= file_get_contents($customCssFile); } if (isset($customJsFile)) { $vars["javascript"] .= file_get_contents($customJsFile); } // Add extra entries list of data tables: // @todo: Consolidate addDataTable and addDataTableCallback $extraTables = array_map(function ($table) use ($inspector) { return $table instanceof \Closure ? $table($inspector) : $table; }, $this->getDataTables()); $vars["tables"] = array_merge($extraTables, $vars["tables"]); $plainTextHandler = new PlainTextHandler(); $plainTextHandler->setRun($this->getRun()); $plainTextHandler->setException($this->getException()); $plainTextHandler->setInspector($this->getInspector()); $vars["preface"] = ""; $this->templateHelper->setVariables($vars); $this->templateHelper->render($templateFile); return Handler::QUIT; } /** * Get the stack trace frames of the exception currently being handled. * * @return \Whoops\Exception\FrameCollection */ protected function getExceptionFrames() { $frames = $this->getInspector()->getFrames($this->getRun()->getFrameFilters()); if ($this->getApplicationPaths()) { foreach ($frames as $frame) { foreach ($this->getApplicationPaths() as $path) { if (strpos($frame->getFile(), $path) === 0) { $frame->setApplication(true); break; } } } } return $frames; } /** * Get the code of the exception currently being handled. * * @return string */ protected function getExceptionCode() { $exception = $this->getException(); $code = $exception->getCode(); if ($exception instanceof \ErrorException) { // ErrorExceptions wrap the php-error types within the 'severity' property $code = Misc::translateErrorCode($exception->getSeverity()); } return (string) $code; } /** * @return string */ public function contentType() { return 'text/html'; } /** * Adds an entry to the list of tables displayed in the template. * * The expected data is a simple associative array. Any nested arrays * will be flattened with `print_r`. * * @param string $label * * @return static */ public function addDataTable($label, array $data) { $this->extraTables[$label] = $data; return $this; } /** * Lazily adds an entry to the list of tables displayed in the table. * * The supplied callback argument will be called when the error is * rendered, it should produce a simple associative array. Any nested * arrays will be flattened with `print_r`. * * @param string $label * @param callable $callback Callable returning an associative array * * @throws InvalidArgumentException If $callback is not callable * * @return static */ public function addDataTableCallback($label, /* callable */ $callback) { if (!is_callable($callback)) { throw new InvalidArgumentException('Expecting callback argument to be callable'); } $this->extraTables[$label] = function (?\Whoops\Inspector\InspectorInterface $inspector = null) use ($callback) { try { $result = call_user_func($callback, $inspector); // Only return the result if it can be iterated over by foreach(). return is_array($result) || $result instanceof \Traversable ? $result : []; } catch (\Exception $e) { // Don't allow failure to break the rendering of the original exception. return []; } }; return $this; } /** * Returns all the extra data tables registered with this handler. * * Optionally accepts a 'label' parameter, to only return the data table * under that label. * * @param string|null $label * * @return array[]|callable */ public function getDataTables($label = null) { if ($label !== null) { return isset($this->extraTables[$label]) ? $this->extraTables[$label] : []; } return $this->extraTables; } /** * Set whether to handle unconditionally. * * Allows to disable all attempts to dynamically decide whether to handle * or return prematurely. Set this to ensure that the handler will perform, * no matter what. * * @param bool|null $value * * @return bool|static */ public function handleUnconditionally($value = null) { if (func_num_args() == 0) { return $this->handleUnconditionally; } $this->handleUnconditionally = (bool) $value; return $this; } /** * Adds an editor resolver. * * Either a string, or a closure that resolves a string, that can be used * to open a given file in an editor. If the string contains the special * substrings %file or %line, they will be replaced with the correct data. * * @example * $run->addEditor('macvim', "mvim://open?url=file://%file&line=%line") * @example * $run->addEditor('remove-it', function($file, $line) { * unlink($file); * return "http://stackoverflow.com"; * }); * * @param string $identifier * @param string|callable $resolver * * @return static */ public function addEditor($identifier, $resolver) { $this->editors[$identifier] = $resolver; return $this; } /** * Set the editor to use to open referenced files. * * Pass either the name of a configured editor, or a closure that directly * resolves an editor string. * * @example * $run->setEditor(function($file, $line) { return "file:///{$file}"; }); * @example * $run->setEditor('sublime'); * * @param string|callable $editor * * @throws InvalidArgumentException If invalid argument identifier provided * * @return static */ public function setEditor($editor) { if (!is_callable($editor) && !isset($this->editors[$editor])) { throw new InvalidArgumentException( "Unknown editor identifier: $editor. Known editors:" . implode(",", array_keys($this->editors)) ); } $this->editor = $editor; return $this; } /** * Get the editor href for a given file and line, if available. * * @param string $filePath * @param int $line * * @throws InvalidArgumentException If editor resolver does not return a string * * @return string|bool */ public function getEditorHref($filePath, $line) { $editor = $this->getEditor($filePath, $line); if (empty($editor)) { return false; } // Check that the editor is a string, and replace the // %line and %file placeholders: if (!isset($editor['url']) || !is_string($editor['url'])) { throw new UnexpectedValueException( __METHOD__ . " should always resolve to a string or a valid editor array; got something else instead." ); } $editor['url'] = str_replace("%line", rawurlencode($line), $editor['url']); $editor['url'] = str_replace("%file", rawurlencode($filePath), $editor['url']); return $editor['url']; } /** * Determine if the editor link should act as an Ajax request. * * @param string $filePath * @param int $line * * @throws UnexpectedValueException If editor resolver does not return a boolean * * @return bool */ public function getEditorAjax($filePath, $line) { $editor = $this->getEditor($filePath, $line); // Check that the ajax is a bool if (!isset($editor['ajax']) || !is_bool($editor['ajax'])) { throw new UnexpectedValueException( __METHOD__ . " should always resolve to a bool; got something else instead." ); } return $editor['ajax']; } /** * Determines both the editor and if ajax should be used. * * @param string $filePath * @param int $line * * @return array */ protected function getEditor($filePath, $line) { if (!$this->editor || (!is_string($this->editor) && !is_callable($this->editor))) { return []; } if (is_string($this->editor) && isset($this->editors[$this->editor]) && !is_callable($this->editors[$this->editor])) { return [ 'ajax' => false, 'url' => $this->editors[$this->editor], ]; } if (is_callable($this->editor) || (isset($this->editors[$this->editor]) && is_callable($this->editors[$this->editor]))) { if (is_callable($this->editor)) { $callback = call_user_func($this->editor, $filePath, $line); } else { $callback = call_user_func($this->editors[$this->editor], $filePath, $line); } if (empty($callback)) { return []; } if (is_string($callback)) { return [ 'ajax' => false, 'url' => $callback, ]; } return [ 'ajax' => isset($callback['ajax']) ? $callback['ajax'] : false, 'url' => isset($callback['url']) ? $callback['url'] : $callback, ]; } return []; } /** * Set the page title. * * @param string $title * * @return static */ public function setPageTitle($title) { $this->pageTitle = (string) $title; return $this; } /** * Get the page title. * * @return string */ public function getPageTitle() { return $this->pageTitle; } /** * Adds a path to the list of paths to be searched for resources. * * @param string $path * * @throws InvalidArgumentException If $path is not a valid directory * * @return static */ public function addResourcePath($path) { if (!is_dir($path)) { throw new InvalidArgumentException( "'$path' is not a valid directory" ); } array_unshift($this->searchPaths, $path); return $this; } /** * Adds a custom css file to be loaded. * * @param string|null $name * * @return static */ public function addCustomCss($name) { $this->customCss = $name; return $this; } /** * Adds a custom js file to be loaded. * * @param string|null $name * * @return static */ public function addCustomJs($name) { $this->customJs = $name; return $this; } /** * @return array */ public function getResourcePaths() { return $this->searchPaths; } /** * Finds a resource, by its relative path, in all available search paths. * * The search is performed starting at the last search path, and all the * way back to the first, enabling a cascading-type system of overrides for * all resources. * * @param string $resource * * @throws RuntimeException If resource cannot be found in any of the available paths * * @return string */ protected function getResource($resource) { // If the resource was found before, we can speed things up // by caching its absolute, resolved path: if (isset($this->resourceCache[$resource])) { return $this->resourceCache[$resource]; } // Search through available search paths, until we find the // resource we're after: foreach ($this->searchPaths as $path) { $fullPath = $path . "/$resource"; if (is_file($fullPath)) { // Cache the result: $this->resourceCache[$resource] = $fullPath; return $fullPath; } } // If we got this far, nothing was found. throw new RuntimeException( "Could not find resource '$resource' in any resource paths." . "(searched: " . join(", ", $this->searchPaths). ")" ); } /** * @deprecated * * @return string */ public function getResourcesPath() { $allPaths = $this->getResourcePaths(); // Compat: return only the first path added return end($allPaths) ?: null; } /** * @deprecated * * @param string $resourcesPath * * @return static */ public function setResourcesPath($resourcesPath) { $this->addResourcePath($resourcesPath); return $this; } /** * Return the application paths. * * @return array */ public function getApplicationPaths() { return $this->applicationPaths; } /** * Set the application paths. * * @return void */ public function setApplicationPaths(array $applicationPaths) { $this->applicationPaths = $applicationPaths; } /** * Set the application root path. * * @param string $applicationRootPath * * @return void */ public function setApplicationRootPath($applicationRootPath) { $this->templateHelper->setApplicationRootPath($applicationRootPath); } /** * blacklist a sensitive value within one of the superglobal arrays. * Alias for the hideSuperglobalKey method. * * @param string $superGlobalName The name of the superglobal array, e.g. '_GET' * @param string $key The key within the superglobal * @see hideSuperglobalKey * * @return static */ public function blacklist($superGlobalName, $key) { $this->blacklist[$superGlobalName][] = $key; return $this; } /** * Hide a sensitive value within one of the superglobal arrays. * * @param string $superGlobalName The name of the superglobal array, e.g. '_GET' * @param string $key The key within the superglobal * @return static */ public function hideSuperglobalKey($superGlobalName, $key) { return $this->blacklist($superGlobalName, $key); } /** * Checks all values within the given superGlobal array. * * Blacklisted values will be replaced by a equal length string containing * only '*' characters for string values. * Non-string values will be replaced with a fixed asterisk count. * We intentionally dont rely on $GLOBALS as it depends on the 'auto_globals_jit' php.ini setting. * * @param array|\ArrayAccess $superGlobal One of the superglobal arrays * @param string $superGlobalName The name of the superglobal array, e.g. '_GET' * * @return array $values without sensitive data */ private function masked($superGlobal, $superGlobalName) { $blacklisted = $this->blacklist[$superGlobalName]; $values = $superGlobal; foreach ($blacklisted as $key) { if (isset($superGlobal[$key])) { $values[$key] = str_repeat('*', is_string($superGlobal[$key]) ? strlen($superGlobal[$key]) : 3); } } return $values; } } PKZԷ'src/Whoops/Handler/HandlerInterface.phpnuW+A */ namespace Whoops\Handler; use Whoops\Inspector\InspectorInterface; use Whoops\RunInterface; interface HandlerInterface { /** * @return int|null A handler may return nothing, or a Handler::HANDLE_* constant */ public function handle(); /** * @param RunInterface $run * @return void */ public function setRun(RunInterface $run); /** * @param \Throwable $exception * @return void */ public function setException($exception); /** * @param InspectorInterface $inspector * @return void */ public function setInspector(InspectorInterface $inspector); } PKZU # #'src/Whoops/Handler/PlainTextHandler.phpnuW+A * Plaintext handler for command line and logs. * @author Pierre-Yves Landuré */ namespace Whoops\Handler; use InvalidArgumentException; use Psr\Log\LoggerInterface; use Whoops\Exception\Frame; /** * Handler outputing plaintext error messages. Can be used * directly, or will be instantiated automagically by Whoops\Run * if passed to Run::pushHandler */ class PlainTextHandler extends Handler { const VAR_DUMP_PREFIX = ' | '; /** * @var \Psr\Log\LoggerInterface */ protected $logger; /** * @var callable */ protected $dumper; /** * @var bool */ private $addTraceToOutput = true; /** * @var bool|integer */ private $addTraceFunctionArgsToOutput = false; /** * @var integer */ private $traceFunctionArgsOutputLimit = 1024; /** * @var bool */ private $addPreviousToOutput = true; /** * @var bool */ private $loggerOnly = false; /** * Constructor. * @throws InvalidArgumentException If argument is not null or a LoggerInterface * @param \Psr\Log\LoggerInterface|null $logger */ public function __construct($logger = null) { $this->setLogger($logger); } /** * Set the output logger interface. * @throws InvalidArgumentException If argument is not null or a LoggerInterface * @param \Psr\Log\LoggerInterface|null $logger */ public function setLogger($logger = null) { if (! (is_null($logger) || $logger instanceof LoggerInterface)) { throw new InvalidArgumentException( 'Argument to ' . __METHOD__ . " must be a valid Logger Interface (aka. Monolog), " . get_class($logger) . ' given.' ); } $this->logger = $logger; } /** * @return \Psr\Log\LoggerInterface|null */ public function getLogger() { return $this->logger; } /** * Set var dumper callback function. * * @param callable $dumper * @return static */ public function setDumper(callable $dumper) { $this->dumper = $dumper; return $this; } /** * Add error trace to output. * @param bool|null $addTraceToOutput * @return bool|static */ public function addTraceToOutput($addTraceToOutput = null) { if (func_num_args() == 0) { return $this->addTraceToOutput; } $this->addTraceToOutput = (bool) $addTraceToOutput; return $this; } /** * Add previous exceptions to output. * @param bool|null $addPreviousToOutput * @return bool|static */ public function addPreviousToOutput($addPreviousToOutput = null) { if (func_num_args() == 0) { return $this->addPreviousToOutput; } $this->addPreviousToOutput = (bool) $addPreviousToOutput; return $this; } /** * Add error trace function arguments to output. * Set to True for all frame args, or integer for the n first frame args. * @param bool|integer|null $addTraceFunctionArgsToOutput * @return static|bool|integer */ public function addTraceFunctionArgsToOutput($addTraceFunctionArgsToOutput = null) { if (func_num_args() == 0) { return $this->addTraceFunctionArgsToOutput; } if (! is_integer($addTraceFunctionArgsToOutput)) { $this->addTraceFunctionArgsToOutput = (bool) $addTraceFunctionArgsToOutput; } else { $this->addTraceFunctionArgsToOutput = $addTraceFunctionArgsToOutput; } return $this; } /** * Set the size limit in bytes of frame arguments var_dump output. * If the limit is reached, the var_dump output is discarded. * Prevent memory limit errors. * @var integer * @return static */ public function setTraceFunctionArgsOutputLimit($traceFunctionArgsOutputLimit) { $this->traceFunctionArgsOutputLimit = (integer) $traceFunctionArgsOutputLimit; return $this; } /** * Create plain text response and return it as a string * @return string */ public function generateResponse() { $exception = $this->getException(); $message = $this->getExceptionOutput($exception); if ($this->addPreviousToOutput) { $previous = $exception->getPrevious(); while ($previous) { $message .= "\n\nCaused by\n" . $this->getExceptionOutput($previous); $previous = $previous->getPrevious(); } } return $message . $this->getTraceOutput() . "\n"; } /** * Get the size limit in bytes of frame arguments var_dump output. * If the limit is reached, the var_dump output is discarded. * Prevent memory limit errors. * @return integer */ public function getTraceFunctionArgsOutputLimit() { return $this->traceFunctionArgsOutputLimit; } /** * Only output to logger. * @param bool|null $loggerOnly * @return static|bool */ public function loggerOnly($loggerOnly = null) { if (func_num_args() == 0) { return $this->loggerOnly; } $this->loggerOnly = (bool) $loggerOnly; return $this; } /** * Test if handler can output to stdout. * @return bool */ private function canOutput() { return !$this->loggerOnly(); } /** * Get the frame args var_dump. * @param \Whoops\Exception\Frame $frame [description] * @param integer $line [description] * @return string */ private function getFrameArgsOutput(Frame $frame, $line) { if ($this->addTraceFunctionArgsToOutput() === false || $this->addTraceFunctionArgsToOutput() < $line) { return ''; } // Dump the arguments: ob_start(); $this->dump($frame->getArgs()); if (ob_get_length() > $this->getTraceFunctionArgsOutputLimit()) { // The argument var_dump is to big. // Discarded to limit memory usage. ob_clean(); return sprintf( "\n%sArguments dump length greater than %d Bytes. Discarded.", self::VAR_DUMP_PREFIX, $this->getTraceFunctionArgsOutputLimit() ); } return sprintf( "\n%s", preg_replace('/^/m', self::VAR_DUMP_PREFIX, ob_get_clean()) ); } /** * Dump variable. * * @param mixed $var * @return void */ protected function dump($var) { if ($this->dumper) { call_user_func($this->dumper, $var); } else { var_dump($var); } } /** * Get the exception trace as plain text. * @return string */ private function getTraceOutput() { if (! $this->addTraceToOutput()) { return ''; } $inspector = $this->getInspector(); $frames = $inspector->getFrames($this->getRun()->getFrameFilters()); $response = "\nStack trace:"; $line = 1; foreach ($frames as $frame) { /** @var Frame $frame */ $class = $frame->getClass(); $template = "\n%3d. %s->%s() %s:%d%s"; if (! $class) { // Remove method arrow (->) from output. $template = "\n%3d. %s%s() %s:%d%s"; } $response .= sprintf( $template, $line, $class, $frame->getFunction(), $frame->getFile(), $frame->getLine(), $this->getFrameArgsOutput($frame, $line) ); $line++; } return $response; } /** * Get the exception as plain text. * @param \Throwable $exception * @return string */ private function getExceptionOutput($exception) { return sprintf( "%s: %s in file %s on line %d", get_class($exception), $exception->getMessage(), $exception->getFile(), $exception->getLine() ); } /** * @return int */ public function handle() { $response = $this->generateResponse(); if ($this->getLogger()) { $this->getLogger()->error($response); } if (! $this->canOutput()) { return Handler::DONE; } echo $response; return Handler::QUIT; } /** * @return string */ public function contentType() { return 'text/plain'; } } PKZkZ==*src/Whoops/Handler/JsonResponseHandler.phpnuW+A */ namespace Whoops\Handler; use Whoops\Exception\Formatter; /** * Catches an exception and converts it to a JSON * response. Additionally can also return exception * frames for consumption by an API. */ class JsonResponseHandler extends Handler { /** * @var bool */ private $returnFrames = false; /** * @var bool */ private $jsonApi = false; /** * Returns errors[[]] instead of error[] to be in compliance with the json:api spec * @param bool $jsonApi Default is false * @return static */ public function setJsonApi($jsonApi = false) { $this->jsonApi = (bool) $jsonApi; return $this; } /** * @param bool|null $returnFrames * @return bool|static */ public function addTraceToOutput($returnFrames = null) { if (func_num_args() == 0) { return $this->returnFrames; } $this->returnFrames = (bool) $returnFrames; return $this; } /** * @return int */ public function handle() { if ($this->jsonApi === true) { $response = [ 'errors' => [ Formatter::formatExceptionAsDataArray( $this->getInspector(), $this->addTraceToOutput(), $this->getRun()->getFrameFilters() ), ] ]; } else { $response = [ 'error' => Formatter::formatExceptionAsDataArray( $this->getInspector(), $this->addTraceToOutput(), $this->getRun()->getFrameFilters() ), ]; } echo json_encode($response, defined('JSON_PARTIAL_OUTPUT_ON_ERROR') ? JSON_PARTIAL_OUTPUT_ON_ERROR : 0); return Handler::QUIT; } /** * @return string */ public function contentType() { return 'application/json'; } } PKZL"L"(src/Whoops/Resources/js/clipboard.min.jsnuW+A/*! * clipboard.js v1.5.3 * https://zenorocha.github.io/clipboard.js * * Licensed MIT © Zeno Rocha */ !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var e;e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,e.Clipboard=t()}}(function(){var t,e,n;return function t(e,n,r){function o(a,c){if(!n[a]){if(!e[a]){var s="function"==typeof require&&require;if(!c&&s)return s(a,!0);if(i)return i(a,!0);var u=new Error("Cannot find module '"+a+"'");throw u.code="MODULE_NOT_FOUND",u}var l=n[a]={exports:{}};e[a][0].call(l.exports,function(t){var n=e[a][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[a].exports}for(var i="function"==typeof require&&require,a=0;ar;r++)n[r].fn.apply(n[r].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),r=n[t],o=[];if(r&&e)for(var i=0,a=r.length;a>i;i++)r[i].fn!==e&&r[i].fn._!==e&&o.push(r[i]);return o.length?n[t]=o:delete n[t],this}},e.exports=r},{}],8:[function(t,e,n){"use strict";function r(t){return t&&t.__esModule?t:{"default":t}}function o(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}n.__esModule=!0;var i=function(){function t(t,e){for(var n=0;n0?n.fn.concat.apply([],t):t}function F(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function q(t){return t in f?f[t]:f[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function H(t,e){return"number"!=typeof e||c[F(t)]?e:e+"px"}function I(t){var e,n;return u[t]||(e=a.createElement(t),a.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),u[t]=n),u[t]}function V(t){return"children"in t?o.call(t.children):n.map(t.childNodes,function(t){return 1==t.nodeType?t:void 0})}function U(n,i,r){for(e in i)r&&(R(i[e])||A(i[e]))?(R(i[e])&&!R(n[e])&&(n[e]={}),A(i[e])&&!A(n[e])&&(n[e]=[]),U(n[e],i[e],r)):i[e]!==t&&(n[e]=i[e])}function B(t,e){return null==e?n(t):n(t).filter(e)}function J(t,e,n,i){return Z(e)?e.call(t,n,i):e}function X(t,e,n){null==n?t.removeAttribute(e):t.setAttribute(e,n)}function W(e,n){var i=e.className,r=i&&i.baseVal!==t;return n===t?r?i.baseVal:i:void(r?i.baseVal=n:e.className=n)}function Y(t){var e;try{return t?"true"==t||("false"==t?!1:"null"==t?null:/^0/.test(t)||isNaN(e=Number(t))?/^[\[\{]/.test(t)?n.parseJSON(t):t:e):t}catch(i){return t}}function G(t,e){e(t);for(var n in t.childNodes)G(t.childNodes[n],e)}var t,e,n,i,C,N,r=[],o=r.slice,s=r.filter,a=window.document,u={},f={},c={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},l=/^\s*<(\w+|!)[^>]*>/,h=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,p=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,d=/^(?:body|html)$/i,m=/([A-Z])/g,g=["val","css","html","text","data","width","height","offset"],v=["after","prepend","before","append"],y=a.createElement("table"),x=a.createElement("tr"),b={tr:a.createElement("tbody"),tbody:y,thead:y,tfoot:y,td:x,th:x,"*":a.createElement("div")},w=/complete|loaded|interactive/,E=/^[\w-]*$/,j={},T=j.toString,S={},O=a.createElement("div"),P={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},A=Array.isArray||function(t){return t instanceof Array};return S.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var i,r=t.parentNode,o=!r;return o&&(r=O).appendChild(t),i=~S.qsa(r,e).indexOf(t),o&&O.removeChild(t),i},C=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},N=function(t){return s.call(t,function(e,n){return t.indexOf(e)==n})},S.fragment=function(e,i,r){var s,u,f;return h.test(e)&&(s=n(a.createElement(RegExp.$1))),s||(e.replace&&(e=e.replace(p,"<$1>")),i===t&&(i=l.test(e)&&RegExp.$1),i in b||(i="*"),f=b[i],f.innerHTML=""+e,s=n.each(o.call(f.childNodes),function(){f.removeChild(this)})),R(r)&&(u=n(s),n.each(r,function(t,e){g.indexOf(t)>-1?u[t](e):u.attr(t,e)})),s},S.Z=function(t,e){return t=t||[],t.__proto__=n.fn,t.selector=e||"",t},S.isZ=function(t){return t instanceof S.Z},S.init=function(e,i){var r;if(!e)return S.Z();if("string"==typeof e)if(e=e.trim(),"<"==e[0]&&l.test(e))r=S.fragment(e,RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=S.qsa(a,e)}else{if(Z(e))return n(a).ready(e);if(S.isZ(e))return e;if(A(e))r=k(e);else if(D(e))r=[e],e=null;else if(l.test(e))r=S.fragment(e.trim(),RegExp.$1,i),e=null;else{if(i!==t)return n(i).find(e);r=S.qsa(a,e)}}return S.Z(r,e)},n=function(t,e){return S.init(t,e)},n.extend=function(t){var e,n=o.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){U(t,n,e)}),t},S.qsa=function(t,e){var n,i="#"==e[0],r=!i&&"."==e[0],s=i||r?e.slice(1):e,a=E.test(s);return _(t)&&a&&i?(n=t.getElementById(s))?[n]:[]:1!==t.nodeType&&9!==t.nodeType?[]:o.call(a&&!i?r?t.getElementsByClassName(s):t.getElementsByTagName(e):t.querySelectorAll(e))},n.contains=function(t,e){return t!==e&&t.contains(e)},n.type=L,n.isFunction=Z,n.isWindow=$,n.isArray=A,n.isPlainObject=R,n.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},n.inArray=function(t,e,n){return r.indexOf.call(e,t,n)},n.camelCase=C,n.trim=function(t){return null==t?"":String.prototype.trim.call(t)},n.uuid=0,n.support={},n.expr={},n.map=function(t,e){var n,r,o,i=[];if(M(t))for(r=0;r=0?e:e+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return r.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return Z(t)?this.not(this.not(t)):n(s.call(this,function(e){return S.matches(e,t)}))},add:function(t,e){return n(N(this.concat(n(t,e))))},is:function(t){return this.length>0&&S.matches(this[0],t)},not:function(e){var i=[];if(Z(e)&&e.call!==t)this.each(function(t){e.call(this,t)||i.push(this)});else{var r="string"==typeof e?this.filter(e):M(e)&&Z(e.item)?o.call(e):n(e);this.forEach(function(t){r.indexOf(t)<0&&i.push(t)})}return n(i)},has:function(t){return this.filter(function(){return D(t)?n.contains(this,t):n(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!D(t)?t:n(t)},last:function(){var t=this[this.length-1];return t&&!D(t)?t:n(t)},find:function(t){var e,i=this;return e="object"==typeof t?n(t).filter(function(){var t=this;return r.some.call(i,function(e){return n.contains(e,t)})}):1==this.length?n(S.qsa(this[0],t)):this.map(function(){return S.qsa(this,t)})},closest:function(t,e){var i=this[0],r=!1;for("object"==typeof t&&(r=n(t));i&&!(r?r.indexOf(i)>=0:S.matches(i,t));)i=i!==e&&!_(i)&&i.parentNode;return n(i)},parents:function(t){for(var e=[],i=this;i.length>0;)i=n.map(i,function(t){return(t=t.parentNode)&&!_(t)&&e.indexOf(t)<0?(e.push(t),t):void 0});return B(e,t)},parent:function(t){return B(N(this.pluck("parentNode")),t)},children:function(t){return B(this.map(function(){return V(this)}),t)},contents:function(){return this.map(function(){return o.call(this.childNodes)})},siblings:function(t){return B(this.map(function(t,e){return s.call(V(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(t){return n.map(this,function(e){return e[t]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=I(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var e=Z(t);if(this[0]&&!e)var i=n(t).get(0),r=i.parentNode||this.length>1;return this.each(function(o){n(this).wrapAll(e?t.call(this,o):r?i.cloneNode(!0):i)})},wrapAll:function(t){if(this[0]){n(this[0]).before(t=n(t));for(var e;(e=t.children()).length;)t=e.first();n(t).append(this)}return this},wrapInner:function(t){var e=Z(t);return this.each(function(i){var r=n(this),o=r.contents(),s=e?t.call(this,i):t;o.length?o.wrapAll(s):r.append(s)})},unwrap:function(){return this.parent().each(function(){n(this).replaceWith(n(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(e){return this.each(function(){var i=n(this);(e===t?"none"==i.css("display"):e)?i.show():i.hide()})},prev:function(t){return n(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return n(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0===arguments.length?this.length>0?this[0].innerHTML:null:this.each(function(e){var i=this.innerHTML;n(this).empty().append(J(this,t,e,i))})},text:function(e){return 0===arguments.length?this.length>0?this[0].textContent:null:this.each(function(){this.textContent=e===t?"":""+e})},attr:function(n,i){var r;return"string"==typeof n&&i===t?0==this.length||1!==this[0].nodeType?t:"value"==n&&"INPUT"==this[0].nodeName?this.val():!(r=this[0].getAttribute(n))&&n in this[0]?this[0][n]:r:this.each(function(t){if(1===this.nodeType)if(D(n))for(e in n)X(this,e,n[e]);else X(this,n,J(this,i,t,this.getAttribute(n)))})},removeAttr:function(t){return this.each(function(){1===this.nodeType&&X(this,t)})},prop:function(e,n){return e=P[e]||e,n===t?this[0]&&this[0][e]:this.each(function(t){this[e]=J(this,n,t,this[e])})},data:function(e,n){var i=this.attr("data-"+e.replace(m,"-$1").toLowerCase(),n);return null!==i?Y(i):t},val:function(t){return 0===arguments.length?this[0]&&(this[0].multiple?n(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value):this.each(function(e){this.value=J(this,t,e,this.value)})},offset:function(t){if(t)return this.each(function(e){var i=n(this),r=J(this,t,e,i.offset()),o=i.offsetParent().offset(),s={top:r.top-o.top,left:r.left-o.left};"static"==i.css("position")&&(s.position="relative"),i.css(s)});if(0==this.length)return null;var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(t,i){if(arguments.length<2){var r=this[0],o=getComputedStyle(r,"");if(!r)return;if("string"==typeof t)return r.style[C(t)]||o.getPropertyValue(t);if(A(t)){var s={};return n.each(A(t)?t:[t],function(t,e){s[e]=r.style[C(e)]||o.getPropertyValue(e)}),s}}var a="";if("string"==L(t))i||0===i?a=F(t)+":"+H(t,i):this.each(function(){this.style.removeProperty(F(t))});else for(e in t)t[e]||0===t[e]?a+=F(e)+":"+H(e,t[e])+";":this.each(function(){this.style.removeProperty(F(e))});return this.each(function(){this.style.cssText+=";"+a})},index:function(t){return t?this.indexOf(n(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return t?r.some.call(this,function(t){return this.test(W(t))},q(t)):!1},addClass:function(t){return t?this.each(function(e){i=[];var r=W(this),o=J(this,t,e,r);o.split(/\s+/g).forEach(function(t){n(this).hasClass(t)||i.push(t)},this),i.length&&W(this,r+(r?" ":"")+i.join(" "))}):this},removeClass:function(e){return this.each(function(n){return e===t?W(this,""):(i=W(this),J(this,e,n,i).split(/\s+/g).forEach(function(t){i=i.replace(q(t)," ")}),void W(this,i.trim()))})},toggleClass:function(e,i){return e?this.each(function(r){var o=n(this),s=J(this,e,r,W(this));s.split(/\s+/g).forEach(function(e){(i===t?!o.hasClass(e):i)?o.addClass(e):o.removeClass(e)})}):this},scrollTop:function(e){if(this.length){var n="scrollTop"in this[0];return e===t?n?this[0].scrollTop:this[0].pageYOffset:this.each(n?function(){this.scrollTop=e}:function(){this.scrollTo(this.scrollX,e)})}},scrollLeft:function(e){if(this.length){var n="scrollLeft"in this[0];return e===t?n?this[0].scrollLeft:this[0].pageXOffset:this.each(n?function(){this.scrollLeft=e}:function(){this.scrollTo(e,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),i=this.offset(),r=d.test(e[0].nodeName)?{top:0,left:0}:e.offset();return i.top-=parseFloat(n(t).css("margin-top"))||0,i.left-=parseFloat(n(t).css("margin-left"))||0,r.top+=parseFloat(n(e[0]).css("border-top-width"))||0,r.left+=parseFloat(n(e[0]).css("border-left-width"))||0,{top:i.top-r.top,left:i.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||a.body;t&&!d.test(t.nodeName)&&"static"==n(t).css("position");)t=t.offsetParent;return t})}},n.fn.detach=n.fn.remove,["width","height"].forEach(function(e){var i=e.replace(/./,function(t){return t[0].toUpperCase()});n.fn[e]=function(r){var o,s=this[0];return r===t?$(s)?s["inner"+i]:_(s)?s.documentElement["scroll"+i]:(o=this.offset())&&o[e]:this.each(function(t){s=n(this),s.css(e,J(this,r,t,s[e]()))})}}),v.forEach(function(t,e){var i=e%2;n.fn[t]=function(){var t,o,r=n.map(arguments,function(e){return t=L(e),"object"==t||"array"==t||null==e?e:S.fragment(e)}),s=this.length>1;return r.length<1?this:this.each(function(t,a){o=i?a:a.parentNode,a=0==e?a.nextSibling:1==e?a.firstChild:2==e?a:null,r.forEach(function(t){if(s)t=t.cloneNode(!0);else if(!o)return n(t).remove();G(o.insertBefore(t,a),function(t){null==t.nodeName||"SCRIPT"!==t.nodeName.toUpperCase()||t.type&&"text/javascript"!==t.type||t.src||window.eval.call(window,t.innerHTML)})})})},n.fn[i?t+"To":"insert"+(e?"Before":"After")]=function(e){return n(e)[t](this),this}}),S.Z.prototype=n.fn,S.uniq=N,S.deserializeValue=Y,n.zepto=S,n}();window.Zepto=Zepto,void 0===window.$&&(window.$=Zepto),function(t){function l(t){return t._zid||(t._zid=e++)}function h(t,e,n,i){if(e=p(e),e.ns)var r=d(e.ns);return(s[l(t)]||[]).filter(function(t){return!(!t||e.e&&t.e!=e.e||e.ns&&!r.test(t.ns)||n&&l(t.fn)!==l(n)||i&&t.sel!=i)})}function p(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function d(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function m(t,e){return t.del&&!u&&t.e in f||!!e}function g(t){return c[t]||u&&f[t]||t}function v(e,i,r,o,a,u,f){var h=l(e),d=s[h]||(s[h]=[]);i.split(/\s/).forEach(function(i){if("ready"==i)return t(document).ready(r);var s=p(i);s.fn=r,s.sel=a,s.e in c&&(r=function(e){var n=e.relatedTarget;return!n||n!==this&&!t.contains(this,n)?s.fn.apply(this,arguments):void 0}),s.del=u;var l=u||r;s.proxy=function(t){if(t=j(t),!t.isImmediatePropagationStopped()){t.data=o;var i=l.apply(e,t._args==n?[t]:[t].concat(t._args));return i===!1&&(t.preventDefault(),t.stopPropagation()),i}},s.i=d.length,d.push(s),"addEventListener"in e&&e.addEventListener(g(s.e),s.proxy,m(s,f))})}function y(t,e,n,i,r){var o=l(t);(e||"").split(/\s/).forEach(function(e){h(t,e,n,i).forEach(function(e){delete s[o][e.i],"removeEventListener"in t&&t.removeEventListener(g(e.e),e.proxy,m(e,r))})})}function j(e,i){return(i||!e.isDefaultPrevented)&&(i||(i=e),t.each(E,function(t,n){var r=i[t];e[t]=function(){return this[n]=x,r&&r.apply(i,arguments)},e[n]=b}),(i.defaultPrevented!==n?i.defaultPrevented:"returnValue"in i?i.returnValue===!1:i.getPreventDefault&&i.getPreventDefault())&&(e.isDefaultPrevented=x)),e}function T(t){var e,i={originalEvent:t};for(e in t)w.test(e)||t[e]===n||(i[e]=t[e]);return j(i,t)}var n,e=1,i=Array.prototype.slice,r=t.isFunction,o=function(t){return"string"==typeof t},s={},a={},u="onfocusin"in window,f={focus:"focusin",blur:"focusout"},c={mouseenter:"mouseover",mouseleave:"mouseout"};a.click=a.mousedown=a.mouseup=a.mousemove="MouseEvents",t.event={add:v,remove:y},t.proxy=function(e,n){if(r(e)){var i=function(){return e.apply(n,arguments)};return i._zid=l(e),i}if(o(n))return t.proxy(e[n],e);throw new TypeError("expected function")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,i){return this.on(t,e,n,i,1)};var x=function(){return!0},b=function(){return!1},w=/^([A-Z]|returnValue$|layer[XY]$)/,E={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,s,a,u,f){var c,l,h=this;return e&&!o(e)?(t.each(e,function(t,e){h.on(t,s,a,e,f)}),h):(o(s)||r(u)||u===!1||(u=a,a=s,s=n),(r(a)||a===!1)&&(u=a,a=n),u===!1&&(u=b),h.each(function(n,r){f&&(c=function(t){return y(r,t.type,u),u.apply(this,arguments)}),s&&(l=function(e){var n,o=t(e.target).closest(s,r).get(0);return o&&o!==r?(n=t.extend(T(e),{currentTarget:o,liveFired:r}),(c||u).apply(o,[n].concat(i.call(arguments,1)))):void 0}),v(r,e,u,a,s,l||c)}))},t.fn.off=function(e,i,s){var a=this;return e&&!o(e)?(t.each(e,function(t,e){a.off(t,i,e)}),a):(o(i)||r(s)||s===!1||(s=i,i=n),s===!1&&(s=b),a.each(function(){y(this,e,s,i)}))},t.fn.trigger=function(e,n){return e=o(e)||t.isPlainObject(e)?t.Event(e):j(e),e._args=n,this.each(function(){"dispatchEvent"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,n){var i,r;return this.each(function(s,a){i=T(o(e)?t.Event(e):e),i._args=n,i.target=a,t.each(h(a,e.type||e),function(t,e){return r=e.proxy(i),i.isImmediatePropagationStopped()?!1:void 0})}),r},"focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(e){t.fn[e]=function(t){return t?this.bind(e,t):this.trigger(e)}}),["focus","blur"].forEach(function(e){t.fn[e]=function(t){return t?this.bind(e,t):this.each(function(){try{this[e]()}catch(t){}}),this}}),t.Event=function(t,e){o(t)||(e=t,t=e.type);var n=document.createEvent(a[t]||"Events"),i=!0;if(e)for(var r in e)"bubbles"==r?i=!!e[r]:n[r]=e[r];return n.initEvent(t,i,!0),j(n)}}(Zepto),function(t){function l(e,n,i){var r=t.Event(n);return t(e).trigger(r,i),!r.isDefaultPrevented()}function h(t,e,i,r){return t.global?l(e||n,i,r):void 0}function p(e){e.global&&0===t.active++&&h(e,null,"ajaxStart")}function d(e){e.global&&!--t.active&&h(e,null,"ajaxStop")}function m(t,e){var n=e.context;return e.beforeSend.call(n,t,e)===!1||h(e,n,"ajaxBeforeSend",[t,e])===!1?!1:void h(e,n,"ajaxSend",[t,e])}function g(t,e,n,i){var r=n.context,o="success";n.success.call(r,t,o,e),i&&i.resolveWith(r,[t,o,e]),h(n,r,"ajaxSuccess",[e,n,t]),y(o,e,n)}function v(t,e,n,i,r){var o=i.context;i.error.call(o,n,e,t),r&&r.rejectWith(o,[n,e,t]),h(i,o,"ajaxError",[n,i,t||e]),y(e,n,i)}function y(t,e,n){var i=n.context;n.complete.call(i,e,t),h(n,i,"ajaxComplete",[e,n]),d(n)}function x(){}function b(t){return t&&(t=t.split(";",2)[0]),t&&(t==f?"html":t==u?"json":s.test(t)?"script":a.test(t)&&"xml")||"text"}function w(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function E(e){e.processData&&e.data&&"string"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&"GET"!=e.type.toUpperCase()||(e.url=w(e.url,e.data),e.data=void 0)}function j(e,n,i,r){return t.isFunction(n)&&(r=i,i=n,n=void 0),t.isFunction(i)||(r=i,i=void 0),{url:e,data:n,success:i,dataType:r}}function S(e,n,i,r){var o,s=t.isArray(n),a=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),r&&(n=i?r:r+"["+(a||"object"==o||"array"==o?n:"")+"]"),!r&&s?e.add(u.name,u.value):"array"==o||!i&&"object"==o?S(e,u,i,n):e.add(n,u)})}var i,r,e=0,n=window.document,o=/)<[^<]*)*<\/script>/gi,s=/^(?:text|application)\/javascript/i,a=/^(?:text|application)\/xml/i,u="application/json",f="text/html",c=/^\s*$/;t.active=0,t.ajaxJSONP=function(i,r){if(!("type"in i))return t.ajax(i);var f,h,o=i.jsonpCallback,s=(t.isFunction(o)?o():o)||"jsonp"+ ++e,a=n.createElement("script"),u=window[s],c=function(e){t(a).triggerHandler("error",e||"abort")},l={abort:c};return r&&r.promise(l),t(a).on("load error",function(e,n){clearTimeout(h),t(a).off().remove(),"error"!=e.type&&f?g(f[0],l,i,r):v(null,n||"error",l,i,r),window[s]=u,f&&t.isFunction(u)&&u(f[0]),u=f=void 0}),m(l,i)===!1?(c("abort"),l):(window[s]=function(){f=arguments},a.src=i.url.replace(/\?(.+)=\?/,"?$1="+s),n.head.appendChild(a),i.timeout>0&&(h=setTimeout(function(){c("timeout")},i.timeout)),l)},t.ajaxSettings={type:"GET",beforeSend:x,success:x,error:x,complete:x,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:u,xml:"application/xml, text/xml",html:f,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0},t.ajax=function(e){var n=t.extend({},e||{}),o=t.Deferred&&t.Deferred();for(i in t.ajaxSettings)void 0===n[i]&&(n[i]=t.ajaxSettings[i]);p(n),n.crossDomain||(n.crossDomain=/^([\w-]+:)?\/\/([^\/]+)/.test(n.url)&&RegExp.$2!=window.location.host),n.url||(n.url=window.location.toString()),E(n),n.cache===!1&&(n.url=w(n.url,"_="+Date.now()));var s=n.dataType,a=/\?.+=\?/.test(n.url);if("jsonp"==s||a)return a||(n.url=w(n.url,n.jsonp?n.jsonp+"=?":n.jsonp===!1?"":"callback=?")),t.ajaxJSONP(n,o);var j,u=n.accepts[s],f={},l=function(t,e){f[t.toLowerCase()]=[t,e]},h=/^([\w-]+:)\/\//.test(n.url)?RegExp.$1:window.location.protocol,d=n.xhr(),y=d.setRequestHeader;if(o&&o.promise(d),n.crossDomain||l("X-Requested-With","XMLHttpRequest"),l("Accept",u||"*/*"),(u=n.mimeType||u)&&(u.indexOf(",")>-1&&(u=u.split(",",2)[0]),d.overrideMimeType&&d.overrideMimeType(u)),(n.contentType||n.contentType!==!1&&n.data&&"GET"!=n.type.toUpperCase())&&l("Content-Type",n.contentType||"application/x-www-form-urlencoded"),n.headers)for(r in n.headers)l(r,n.headers[r]);if(d.setRequestHeader=l,d.onreadystatechange=function(){if(4==d.readyState){d.onreadystatechange=x,clearTimeout(j);var e,i=!1;if(d.status>=200&&d.status<300||304==d.status||0==d.status&&"file:"==h){s=s||b(n.mimeType||d.getResponseHeader("content-type")),e=d.responseText;try{"script"==s?(1,eval)(e):"xml"==s?e=d.responseXML:"json"==s&&(e=c.test(e)?null:t.parseJSON(e))}catch(r){i=r}i?v(i,"parsererror",d,n,o):g(e,d,n,o)}else v(d.statusText||null,d.status?"error":"abort",d,n,o)}},m(d,n)===!1)return d.abort(),v(null,"abort",d,n,o),d;if(n.xhrFields)for(r in n.xhrFields)d[r]=n.xhrFields[r];var T="async"in n?n.async:!0;d.open(n.type,n.url,T,n.username,n.password);for(r in f)y.apply(d,f[r]);return n.timeout>0&&(j=setTimeout(function(){d.onreadystatechange=x,d.abort(),v(null,"timeout",d,n,o)},n.timeout)),d.send(n.data?n.data:null),d},t.get=function(){return t.ajax(j.apply(null,arguments))},t.post=function(){var e=j.apply(null,arguments);return e.type="POST",t.ajax(e)},t.getJSON=function(){var e=j.apply(null,arguments);return e.dataType="json",t.ajax(e)},t.fn.load=function(e,n,i){if(!this.length)return this;var a,r=this,s=e.split(/\s/),u=j(e,n,i),f=u.success;return s.length>1&&(u.url=s[0],a=s[1]),u.success=function(e){r.html(a?t("
").html(e.replace(o,"")).find(a):e),f&&f.apply(r,arguments)},t.ajax(u),this};var T=encodeURIComponent;t.param=function(t,e){var n=[];return n.add=function(t,e){this.push(T(t)+"="+T(e))},S(n,t,e),n.join("&").replace(/%20/g,"+")}}(Zepto),function(t){t.fn.serializeArray=function(){var n,e=[];return t([].slice.call(this.get(0).elements)).each(function(){n=t(this);var i=n.attr("type");"fieldset"!=this.nodeName.toLowerCase()&&!this.disabled&&"submit"!=i&&"reset"!=i&&"button"!=i&&("radio"!=i&&"checkbox"!=i||this.checked)&&e.push({name:n.attr("name"),value:n.val()})}),e},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+"="+encodeURIComponent(e.value))}),t.join("&")},t.fn.submit=function(e){if(e)this.bind("submit",e);else if(this.length){var n=t.Event("submit");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(Zepto),function(t){"__proto__"in{}||t.extend(t.zepto,{Z:function(e,n){return e=e||[],t.extend(e,t.fn),e.selector=n||"",e.__Z=!0,e},isZ:function(e){return"array"===t.type(e)&&"__Z"in e}});try{getComputedStyle(void 0)}catch(e){var n=getComputedStyle;window.getComputedStyle=function(t){try{return n(t)}catch(e){return null}}}}(Zepto); PKZ~_<&src/Whoops/Resources/js/whoops.base.jsnuW+AZepto(function($) { var $leftPanel = $('.left-panel'); var $frameContainer = $('.frames-container'); var $appFramesTab = $('#application-frames-tab'); var $allFramesTab = $('#all-frames-tab'); var $container = $('.details-container'); var $activeLine = $frameContainer.find('.frame.active'); var $activeFrame = $container.find('.frame-code.active'); var $ajaxEditors = $('.editor-link[data-ajax]'); var $header = $('header'); $header.on('mouseenter', function () { if ($header.find('.exception').height() >= 145) { $header.addClass('header-expand'); } }); $header.on('mouseleave', function () { $header.removeClass('header-expand'); }); /* * add prettyprint classes to our current active codeblock * run prettyPrint() to highlight the active code * scroll to the line when prettyprint is done * highlight the current line */ var renderCurrentCodeblock = function(id) { Prism.highlightAllUnder(document.querySelector('.frame-code-container .frame-code.active')); highlightCurrentLine(); } /* * Highlight the active and neighboring lines for the current frame * Adjust the offset to make sure that line is veritcally centered */ var highlightCurrentLine = function() { // We show more code than needed, purely for proper syntax highlighting // Let’s hide a big chunk of that code and then scroll the remaining block $activeFrame.find('.code-block').first().css({ maxHeight: 345, overflow: 'hidden', }); var line = $activeFrame.find('.code-block .line-highlight').first()[0]; line.scrollIntoView(); line.parentElement.scrollTop -= 180; $container.scrollTop(0); } /* * click handler for loading codeblocks */ $frameContainer.on('click', '.frame', function() { var $this = $(this); var id = /frame\-line\-([\d]*)/.exec($this.attr('id'))[1]; var $codeFrame = $('#frame-code-' + id); if ($codeFrame) { $activeLine.removeClass('active'); $activeFrame.removeClass('active'); $this.addClass('active'); $codeFrame.addClass('active'); $activeLine = $this; $activeFrame = $codeFrame; renderCurrentCodeblock(id); } }); var clipboard = new Clipboard('.clipboard'); var showTooltip = function(elem, msg) { elem.classList.add('tooltipped', 'tooltipped-s'); elem.setAttribute('aria-label', msg); }; clipboard.on('success', function(e) { e.clearSelection(); showTooltip(e.trigger, 'Copied!'); }); clipboard.on('error', function(e) { showTooltip(e.trigger, fallbackMessage(e.action)); }); var btn = document.querySelector('.clipboard'); btn.addEventListener('mouseleave', function(e) { e.currentTarget.classList.remove('tooltipped', 'tooltipped-s'); e.currentTarget.removeAttribute('aria-label'); }); function fallbackMessage(action) { var actionMsg = ''; var actionKey = (action === 'cut' ? 'X' : 'C'); if (/Mac/i.test(navigator.userAgent)) { actionMsg = 'Press ⌘-' + actionKey + ' to ' + action; } else { actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action; } return actionMsg; } function scrollIntoView($node, $parent) { var nodeOffset = $node.offset(); var nodeTop = nodeOffset.top; var nodeBottom = nodeTop + nodeOffset.height; var parentScrollTop = $parent.scrollTop(); var parentHeight = $parent.height(); if (nodeTop < 0) { $parent.scrollTop(parentScrollTop + nodeTop); } else if (nodeBottom > parentHeight) { $parent.scrollTop(parentScrollTop + nodeBottom - parentHeight); } } $(document).on('keydown', function(e) { var applicationFrames = $frameContainer.hasClass('frames-container-application'), frameClass = applicationFrames ? '.frame.frame-application' : '.frame'; if(e.ctrlKey || e.which === 74 || e.which === 75) { // CTRL+Arrow-UP/k and Arrow-Down/j support: // 1) select the next/prev element // 2) make sure the newly selected element is within the view-scope // 3) focus the (right) container, so arrow-up/down (without ctrl) scroll the details if (e.which === 38 /* arrow up */ || e.which === 75 /* k */) { $activeLine.prev(frameClass).click(); scrollIntoView($activeLine, $leftPanel); $container.focus(); e.preventDefault(); } else if (e.which === 40 /* arrow down */ || e.which === 74 /* j */) { $activeLine.next(frameClass).click(); scrollIntoView($activeLine, $leftPanel); $container.focus(); e.preventDefault(); } } else if (e.which == 78 /* n */) { if ($appFramesTab.length) { setActiveFramesTab($('.frames-tab:not(.frames-tab-active)')); } } }); // Avoid to quit the page with some protocol (e.g. IntelliJ Platform REST API) $ajaxEditors.on('click', function(e){ e.preventDefault(); $.get(this.href); }); // Symfony VarDumper: Close the by default expanded objects $('.sf-dump-expanded') .removeClass('sf-dump-expanded') .addClass('sf-dump-compact'); $('.sf-dump-toggle span').html('▶'); // Make the given frames-tab active function setActiveFramesTab($tab) { $tab.addClass('frames-tab-active'); if ($tab.attr('id') == 'application-frames-tab') { $frameContainer.addClass('frames-container-application'); $allFramesTab.removeClass('frames-tab-active'); } else { $frameContainer.removeClass('frames-container-application'); $appFramesTab.removeClass('frames-tab-active'); } } $('a.frames-tab').on('click', function(e) { e.preventDefault(); setActiveFramesTab($(this)); }); // Open editor from code block rows number $(document).delegate('.line-numbers-rows > span', 'click', function(e) { var linkTag = $(this).closest('.frame-code').find('.editor-link'); if (!linkTag) return; var editorUrl = linkTag.attr('href'); var requiresAjax = linkTag.data('ajax'); var lineOffset = $(this).closest('[data-line-offset]').data('line-offset'); var lineNumber = lineOffset + $(this).index(); var realLine = $(this).closest('[data-line]').data('line'); if (!realLine) return; var fileUrl = editorUrl.replace( new RegExp('([:=])' + realLine), '$1' + lineNumber ); if (requiresAjax) { $.get(fileUrl); } else { $('').attr('href', fileUrl).trigger('click'); } }); // Render late enough for highlightCurrentLine to be ready renderCurrentCodeblock(); }); PKZ>^>^ src/Whoops/Resources/js/prism.jsnuW+A/* PrismJS 1.29.0 https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */ var _self="undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=g.reach);A+=w.value.length,w=w.next){var E=w.value;if(n.length>e.length)return;if(!(E instanceof i)){var P,L=1;if(y){if(!(P=l(b,A,e,m))||P.index>=e.length)break;var S=P.index,O=P.index+P[0].length,j=A;for(j+=w.value.length;S>=j;)j+=(w=w.next).value.length;if(A=j-=w.value.length,w.value instanceof i)continue;for(var C=w;C!==n.tail&&(jg.reach&&(g.reach=W);var z=w.prev;if(_&&(z=u(n,z,_),A+=_.length),c(n,z,L),w=u(n,z,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),L>1){var I={cause:f+","+d,reach:W};o(e,n,t,w.prev,A,I),g&&I.reach>g.reach&&(g.reach=I.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a"+i.content+""},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener("message",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute("data-manual")&&(a.manual=!0)),!a.manual){var h=document.readyState;"loading"===h||"interactive"===h&&g&&g.defer?document.addEventListener("DOMContentLoaded",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);"undefined"!=typeof module&&module.exports&&(module.exports=Prism),"undefined"!=typeof global&&(global.Prism=Prism); Prism.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},Prism.languages.markup.tag.inside["attr-value"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside["internal-subset"].inside=Prism.languages.markup,Prism.hooks.add("wrap",(function(a){"entity"===a.type&&(a.attributes.title=a.content.replace(/&/,"&"))})),Object.defineProperty(Prism.languages.markup.tag,"addInlined",{value:function(a,e){var s={};s["language-"+e]={pattern:/(^$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^$/i;var t={"included-cdata":{pattern://i,inside:s}};t["language-"+e]={pattern:/[\s\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp("(<__[^>]*>)(?:))*\\]\\]>|(?!)".replace(/__/g,(function(){return a})),"i"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(Prism.languages.markup.tag,"addAttribute",{value:function(a,e){Prism.languages.markup.tag.inside["special-attr"].push({pattern:RegExp("(^|[\"'\\s])(?:"+a+")\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))","i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[e,"language-"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend("markup",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml; !function(e){function n(e,n){return"___"+e.toUpperCase()+n+"___"}Object.defineProperties(e.languages["markup-templating"]={},{buildPlaceholders:{value:function(t,a,r,o){if(t.language===a){var c=t.tokenStack=[];t.code=t.code.replace(r,(function(e){if("function"==typeof o&&!o(e))return e;for(var r,i=c.length;-1!==t.code.indexOf(r=n(a,i));)++i;return c[i]=e,r})),t.grammar=e.languages.markup}}},tokenizePlaceholders:{value:function(t,a){if(t.language===a&&t.tokenStack){t.grammar=e.languages[a];var r=0,o=Object.keys(t.tokenStack);!function c(i){for(var u=0;u=o.length);u++){var g=i[u];if("string"==typeof g||g.content&&"string"==typeof g.content){var l=o[r],s=t.tokenStack[l],f="string"==typeof g?g:g.content,p=n(a,l),k=f.indexOf(p);if(k>-1){++r;var m=f.substring(0,k),d=new e.Token(a,e.tokenize(s,t.grammar),"language-"+a,s),h=f.substring(k+p.length),v=[];m&&v.push.apply(v,c([m])),v.push(d),h&&v.push.apply(v,c([h])),"string"==typeof g?i.splice.apply(i,[u,1].concat(v)):g.content=v}}else g.content&&c(g.content)}return i}(t.tokens)}}}})}(Prism); !function(e){var a=/\/\*[\s\S]*?\*\/|\/\/.*|#(?!\[).*/,t=[{pattern:/\b(?:false|true)\b/i,alias:"boolean"},{pattern:/(::\s*)\b[a-z_]\w*\b(?!\s*\()/i,greedy:!0,lookbehind:!0},{pattern:/(\b(?:case|const)\s+)\b[a-z_]\w*(?=\s*[;=])/i,greedy:!0,lookbehind:!0},/\b(?:null)\b/i,/\b[A-Z_][A-Z0-9_]*\b(?!\s*\()/],i=/\b0b[01]+(?:_[01]+)*\b|\b0o[0-7]+(?:_[0-7]+)*\b|\b0x[\da-f]+(?:_[\da-f]+)*\b|(?:\b\d+(?:_\d+)*\.?(?:\d+(?:_\d+)*)?|\B\.\d+)(?:e[+-]?\d+)?/i,n=/|\?\?=?|\.{3}|\??->|[!=]=?=?|::|\*\*=?|--|\+\+|&&|\|\||<<|>>|[?~]|[/^|%*&<>.+-]=?/,s=/[{}\[\](),:;]/;e.languages.php={delimiter:{pattern:/\?>$|^<\?(?:php(?=\s)|=)?/i,alias:"important"},comment:a,variable:/\$+(?:\w+\b|(?=\{))/,package:{pattern:/(namespace\s+|use\s+(?:function\s+)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,lookbehind:!0,inside:{punctuation:/\\/}},"class-name-definition":{pattern:/(\b(?:class|enum|interface|trait)\s+)\b[a-z_]\w*(?!\\)\b/i,lookbehind:!0,alias:"class-name"},"function-definition":{pattern:/(\bfunction\s+)[a-z_]\w*(?=\s*\()/i,lookbehind:!0,alias:"function"},keyword:[{pattern:/(\(\s*)\b(?:array|bool|boolean|float|int|integer|object|string)\b(?=\s*\))/i,alias:"type-casting",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|object|self|static|string)\b(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b(?:array(?!\s*\()|bool|callable|(?:false|null)(?=\s*\|)|float|int|iterable|mixed|never|object|self|static|string|void)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/\b(?:array(?!\s*\()|bool|float|int|iterable|mixed|object|string|void)\b/i,alias:"type-declaration",greedy:!0},{pattern:/(\|\s*)(?:false|null)\b|\b(?:false|null)(?=\s*\|)/i,alias:"type-declaration",greedy:!0,lookbehind:!0},{pattern:/\b(?:parent|self|static)(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(\byield\s+)from\b/i,lookbehind:!0},/\bclass\b/i,{pattern:/((?:^|[^\s>:]|(?:^|[^-])>|(?:^|[^:]):)\s*)\b(?:abstract|and|array|as|break|callable|case|catch|clone|const|continue|declare|default|die|do|echo|else|elseif|empty|enddeclare|endfor|endforeach|endif|endswitch|endwhile|enum|eval|exit|extends|final|finally|fn|for|foreach|function|global|goto|if|implements|include|include_once|instanceof|insteadof|interface|isset|list|match|namespace|never|new|or|parent|print|private|protected|public|readonly|require|require_once|return|self|static|switch|throw|trait|try|unset|use|var|while|xor|yield|__halt_compiler)\b/i,lookbehind:!0}],"argument-name":{pattern:/([(,]\s*)\b[a-z_]\w*(?=\s*:(?!:))/i,lookbehind:!0},"class-name":[{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self|\s+static))\s+|\bcatch\s*\()\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/(\|\s*)\b[a-z_]\w*(?!\\)\b/i,greedy:!0,lookbehind:!0},{pattern:/\b[a-z_]\w*(?!\\)\b(?=\s*\|)/i,greedy:!0},{pattern:/(\|\s*)(?:\\?\b[a-z_]\w*)+\b/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(?:\\?\b[a-z_]\w*)+\b(?=\s*\|)/i,alias:"class-name-fully-qualified",greedy:!0,inside:{punctuation:/\\/}},{pattern:/(\b(?:extends|implements|instanceof|new(?!\s+self\b|\s+static\b))\s+|\bcatch\s*\()(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:"class-name-fully-qualified",greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*\$)/i,alias:"type-declaration",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-declaration"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/\b[a-z_]\w*(?=\s*::)/i,alias:"static-context",greedy:!0},{pattern:/(?:\\?\b[a-z_]\w*)+(?=\s*::)/i,alias:["class-name-fully-qualified","static-context"],greedy:!0,inside:{punctuation:/\\/}},{pattern:/([(,?]\s*)[a-z_]\w*(?=\s*\$)/i,alias:"type-hint",greedy:!0,lookbehind:!0},{pattern:/([(,?]\s*)(?:\\?\b[a-z_]\w*)+(?=\s*\$)/i,alias:["class-name-fully-qualified","type-hint"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}},{pattern:/(\)\s*:\s*(?:\?\s*)?)\b[a-z_]\w*(?!\\)\b/i,alias:"return-type",greedy:!0,lookbehind:!0},{pattern:/(\)\s*:\s*(?:\?\s*)?)(?:\\?\b[a-z_]\w*)+\b(?!\\)/i,alias:["class-name-fully-qualified","return-type"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:t,function:{pattern:/(^|[^\\\w])\\?[a-z_](?:[\w\\]*\w)?(?=\s*\()/i,lookbehind:!0,inside:{punctuation:/\\/}},property:{pattern:/(->\s*)\w+/,lookbehind:!0},number:i,operator:n,punctuation:s};var l={pattern:/\{\$(?:\{(?:\{[^{}]+\}|[^{}]+)\}|[^{}])+\}|(^|[^\\{])\$+(?:\w+(?:\[[^\r\n\[\]]+\]|->\w+)?)/,lookbehind:!0,inside:e.languages.php},r=[{pattern:/<<<'([^']+)'[\r\n](?:.*[\r\n])*?\1;/,alias:"nowdoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<'[^']+'|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<'?|[';]$/}}}},{pattern:/<<<(?:"([^"]+)"[\r\n](?:.*[\r\n])*?\1;|([a-z_]\w*)[\r\n](?:.*[\r\n])*?\2;)/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<<(?:"[^"]+"|[a-z_]\w*)|[a-z_]\w*;$/i,alias:"symbol",inside:{punctuation:/^<<<"?|[";]$/}},interpolation:l}},{pattern:/`(?:\\[\s\S]|[^\\`])*`/,alias:"backtick-quoted-string",greedy:!0},{pattern:/'(?:\\[\s\S]|[^\\'])*'/,alias:"single-quoted-string",greedy:!0},{pattern:/"(?:\\[\s\S]|[^\\"])*"/,alias:"double-quoted-string",greedy:!0,inside:{interpolation:l}}];e.languages.insertBefore("php","variable",{string:r,attribute:{pattern:/#\[(?:[^"'\/#]|\/(?![*/])|\/\/.*$|#(?!\[).*$|\/\*(?:[^*]|\*(?!\/))*\*\/|"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*')+\](?=\s*[a-z$#])/im,greedy:!0,inside:{"attribute-content":{pattern:/^(#\[)[\s\S]+(?=\]$)/,lookbehind:!0,inside:{comment:a,string:r,"attribute-class-name":[{pattern:/([^:]|^)\b[a-z_]\w*(?!\\)\b/i,alias:"class-name",greedy:!0,lookbehind:!0},{pattern:/([^:]|^)(?:\\?\b[a-z_]\w*)+/i,alias:["class-name","class-name-fully-qualified"],greedy:!0,lookbehind:!0,inside:{punctuation:/\\/}}],constant:t,number:i,operator:n,punctuation:s}},delimiter:{pattern:/^#\[|\]$/,alias:"punctuation"}}}}),e.hooks.add("before-tokenize",(function(a){/<\?/.test(a.code)&&e.languages["markup-templating"].buildPlaceholders(a,"php",/<\?(?:[^"'/#]|\/(?![*/])|("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|(?:\/\/|#(?!\[))(?:[^?\n\r]|\?(?!>))*(?=$|\?>|[\r\n])|#\[|\/\*(?:[^*]|\*(?!\/))*(?:\*\/|$))*?(?:\?>|$)/g)})),e.hooks.add("after-tokenize",(function(a){e.languages["markup-templating"].tokenizePlaceholders(a,"php")}))}(Prism); !function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document&&document.querySelector){var e,t="line-numbers",i="linkable-line-numbers",n=/\n(?!$)/g,r=!0;Prism.plugins.lineHighlight={highlightLines:function(o,u,c){var h=(u="string"==typeof u?u:o.getAttribute("data-line")||"").replace(/\s+/g,"").split(",").filter(Boolean),d=+o.getAttribute("data-line-offset")||0,f=(function(){if(void 0===e){var t=document.createElement("div");t.style.fontSize="13px",t.style.lineHeight="1.5",t.style.padding="0",t.style.border="0",t.innerHTML=" 
 ",document.body.appendChild(t),e=38===t.offsetHeight,document.body.removeChild(t)}return e}()?parseInt:parseFloat)(getComputedStyle(o).lineHeight),p=Prism.util.isActive(o,t),g=o.querySelector("code"),m=p?o:g||o,v=[],y=g.textContent.match(n),b=y?y.length+1:1,A=g&&m!=g?function(e,t){var i=getComputedStyle(e),n=getComputedStyle(t);function r(e){return+e.substr(0,e.length-2)}return t.offsetTop+r(n.borderTopWidth)+r(n.paddingTop)-r(i.paddingTop)}(o,g):0;h.forEach((function(e){var t=e.split("-"),i=+t[0],n=+t[1]||i;if(!((n=Math.min(b+d,n))i&&r.setAttribute("data-end",String(n)),r.style.top=(i-d-1)*f+A+"px",r.textContent=new Array(n-i+2).join(" \n")}));v.push((function(){r.style.width=o.scrollWidth+"px"})),v.push((function(){m.appendChild(r)}))}}));var P=o.id;if(p&&Prism.util.isActive(o,i)&&P){l(o,i)||v.push((function(){o.classList.add(i)}));var E=parseInt(o.getAttribute("data-start")||"1");s(".line-numbers-rows > span",o).forEach((function(e,t){var i=t+E;e.onclick=function(){var e=P+"."+i;r=!1,location.hash=e,setTimeout((function(){r=!0}),1)}}))}return function(){v.forEach(a)}}};var o=0;Prism.hooks.add("before-sanity-check",(function(e){var t=e.element.parentElement;if(u(t)){var i=0;s(".line-highlight",t).forEach((function(e){i+=e.textContent.length,e.parentNode.removeChild(e)})),i&&/^(?: \n)+$/.test(e.code.slice(-i))&&(e.code=e.code.slice(0,-i))}})),Prism.hooks.add("complete",(function e(i){var n=i.element.parentElement;if(u(n)){clearTimeout(o);var r=Prism.plugins.lineNumbers,s=i.plugins&&i.plugins.lineNumbers;l(n,t)&&r&&!s?Prism.hooks.add("line-numbers",e):(Prism.plugins.lineHighlight.highlightLines(n)(),o=setTimeout(c,1))}})),window.addEventListener("hashchange",c),window.addEventListener("resize",(function(){s("pre").filter(u).map((function(e){return Prism.plugins.lineHighlight.highlightLines(e)})).forEach(a)}))}function s(e,t){return Array.prototype.slice.call((t||document).querySelectorAll(e))}function l(e,t){return e.classList.contains(t)}function a(e){e()}function u(e){return!!(e&&/pre/i.test(e.nodeName)&&(e.hasAttribute("data-line")||e.id&&Prism.util.isActive(e,i)))}function c(){var e=location.hash.slice(1);s(".temporary.line-highlight").forEach((function(e){e.parentNode.removeChild(e)}));var t=(e.match(/\.([\d,-]+)$/)||[,""])[1];if(t&&!document.getElementById(e)){var i=e.slice(0,e.lastIndexOf(".")),n=document.getElementById(i);n&&(n.hasAttribute("data-line")||n.setAttribute("data-line",""),Prism.plugins.lineHighlight.highlightLines(n,t,"temporary ")(),r&&document.querySelector(".temporary.line-highlight").scrollIntoView())}}}(); !function(){if("undefined"!=typeof Prism&&"undefined"!=typeof document){var e="line-numbers",n=/\n(?!$)/g,t=Prism.plugins.lineNumbers={getLine:function(n,t){if("PRE"===n.tagName&&n.classList.contains(e)){var i=n.querySelector(".line-numbers-rows");if(i){var r=parseInt(n.getAttribute("data-start"),10)||1,s=r+(i.children.length-1);ts&&(t=s);var l=t-r;return i.children[l]}}},resize:function(e){r([e])},assumeViewportIndependence:!0},i=void 0;window.addEventListener("resize",(function(){t.assumeViewportIndependence&&i===window.innerWidth||(i=window.innerWidth,r(Array.prototype.slice.call(document.querySelectorAll("pre.line-numbers"))))})),Prism.hooks.add("complete",(function(t){if(t.code){var i=t.element,s=i.parentNode;if(s&&/pre/i.test(s.nodeName)&&!i.querySelector(".line-numbers-rows")&&Prism.util.isActive(i,e)){i.classList.remove(e),s.classList.add(e);var l,o=t.code.match(n),a=o?o.length+1:1,u=new Array(a+1).join("");(l=document.createElement("span")).setAttribute("aria-hidden","true"),l.className="line-numbers-rows",l.innerHTML=u,s.hasAttribute("data-start")&&(s.style.counterReset="linenumber "+(parseInt(s.getAttribute("data-start"),10)-1)),t.element.appendChild(l),r([s]),Prism.hooks.run("line-numbers",t)}}})),Prism.hooks.add("line-numbers",(function(e){e.plugins=e.plugins||{},e.plugins.lineNumbers=!0}))}function r(e){if(0!=(e=e.filter((function(e){var n,t=(n=e,n?window.getComputedStyle?getComputedStyle(n):n.currentStyle||null:null)["white-space"];return"pre-wrap"===t||"pre-line"===t}))).length){var t=e.map((function(e){var t=e.querySelector("code"),i=e.querySelector(".line-numbers-rows");if(t&&i){var r=e.querySelector(".line-numbers-sizer"),s=t.textContent.split(n);r||((r=document.createElement("span")).className="line-numbers-sizer",t.appendChild(r)),r.innerHTML="0",r.style.display="block";var l=r.getBoundingClientRect().height;return r.innerHTML="",{element:e,lines:s,lineHeights:[],oneLinerHeight:l,sizer:r}}})).filter(Boolean);t.forEach((function(e){var n=e.sizer,t=e.lines,i=e.lineHeights,r=e.oneLinerHeight;i[t.length-1]=void 0,t.forEach((function(e,t){if(e&&e.length>1){var s=n.appendChild(document.createElement("span"));s.style.display="block",s.textContent=e}else i[t]=r}))})),t.forEach((function(e){for(var n=e.sizer,t=e.lineHeights,i=0,r=0;r render($header) ?> PKZ-_/src/Whoops/Resources/views/env_details.html.phpnuW+A

Environment & details:

$data): ?>
$value): ?>
Key Value
escape($k) ?> dump($value) ?>
empty
$h): ?>
. escape(get_class($h)) ?>
PKZ*ro o .src/Whoops/Resources/views/frame_code.html.phpnuW+A
$frame): ?> getLine(); ?>
getFileLines($line - 20, 40); // getFileLines can return null if there is no source code if ($range): $range = array_map(function ($line) { return empty($line) ? ' ' : $line;}, $range); $start = key($range) + 1; $code = join("\n", $range); ?>
escape($code) ?>
dumpArgs($frame); ?>
Arguments
getComments(); ?>
$comment): ?>
escape($context) ?> escapeButPreserveUris($comment) ?>
PKZ.src/Whoops/Resources/views/frame_list.html.phpnuW+A $frame): ?>
breakOnDelimiter('\\', $tpl->escape($frame->getClass() ?: '')) ?> breakOnDelimiter('\\', $tpl->escape($frame->getFunction() ?: '')) ?>
getFile() ? $tpl->breakOnDelimiter('/', $tpl->shorten($tpl->escape($frame->getFile()))) : '<#unknown>' ?>getLine() ?>
render($header_outer); $tpl->render($frames_description); $tpl->render($frames_container); PKZYyy4src/Whoops/Resources/views/panel_left_outer.html.phpnuW+A
render($panel_left) ?>
PKZGw"WW7src/Whoops/Resources/views/panel_details_outer.html.phpnuW+A
render($panel_details) ?>
PKZ޲!mm*src/Whoops/Resources/views/layout.html.phpnuW+A <?php echo $tpl->escape($page_title) ?>
render($panel_left_outer) ?> render($panel_details_outer) ?>
PKZ\ FF1src/Whoops/Resources/views/panel_details.html.phpnuW+Arender($frame_code) ?> render($env_details) ?>PKZkg%$$*src/Whoops/Resources/views/header.html.phpnuW+A
$nameSection): ?> escape($nameSection) ?> escape($nameSection) . ' \\' ?> (escape($code) ?>)
escape($message) ?>
Previous exceptions
    $previousMessage): ?>
  • escape($previousMessage) ?> ()
No message escape($plain_exception) ?>
PKZ W4src/Whoops/Resources/views/frames_container.html.phpnuW+A
render($frame_list) ?>
PKZ6src/Whoops/Resources/views/frames_description.html.phpnuW+A
Application frames (countIsApplication() ?>) All frames () Stack frames ()
PKZ$ȁ4 "src/Whoops/Resources/css/prism.cssnuW+A/* PrismJS 1.29.0 https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */ code[class*=language-],pre[class*=language-]{color:#ccc;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green} pre[data-line]{position:relative;padding:1em 0 1em 3em}.line-highlight{position:absolute;left:0;right:0;padding:inherit 0;margin-top:1em;background:hsla(24,20%,50%,.08);background:linear-gradient(to right,hsla(24,20%,50%,.1) 70%,hsla(24,20%,50%,0));pointer-events:none;line-height:inherit;white-space:pre}@media print{.line-highlight{-webkit-print-color-adjust:exact;color-adjust:exact}}.line-highlight:before,.line-highlight[data-end]:after{content:attr(data-start);position:absolute;top:.4em;left:.6em;min-width:1em;padding:0 .5em;background-color:hsla(24,20%,50%,.4);color:#f4f1ef;font:bold 65%/1.5 sans-serif;text-align:center;vertical-align:.3em;border-radius:999px;text-shadow:none;box-shadow:0 1px #fff}.line-highlight[data-end]:after{content:attr(data-end);top:auto;bottom:.4em}.line-numbers .line-highlight:after,.line-numbers .line-highlight:before{content:none}pre[id].linkable-line-numbers span.line-numbers-rows{pointer-events:all}pre[id].linkable-line-numbers span.line-numbers-rows>span:before{cursor:pointer}pre[id].linkable-line-numbers span.line-numbers-rows>span:hover:before{background-color:rgba(128,128,128,.2)} pre[class*=language-].line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre[class*=language-].line-numbers>code{position:relative;white-space:inherit}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right} PKZ4׌(((src/Whoops/Resources/css/whoops.base.cssnuW+Abody { font: 12px "Helvetica Neue", helvetica, arial, sans-serif; color: #131313; background: #eeeeee; padding:0; margin: 0; max-height: 100%; text-rendering: optimizeLegibility; } a { text-decoration: none; } .Whoops.container { position: relative; z-index: 9999999999; } .panel { overflow-y: scroll; height: 100%; position: fixed; margin: 0; left: 0; top: 0; } .branding { position: absolute; top: 10px; right: 20px; color: #777777; font-size: 10px; z-index: 100; } .branding a { color: #e95353; } header { color: white; box-sizing: border-box; background-color: #2a2a2a; padding: 35px 40px; max-height: 180px; overflow: hidden; transition: 0.5s; } header.header-expand { max-height: 1000px; } .exc-title { margin: 0; color: #bebebe; font-size: 14px; } .exc-title-primary, .exc-title-secondary { color: #e95353; } .exc-message { font-size: 20px; word-wrap: break-word; margin: 4px 0 0 0; color: white; } .exc-message span { display: block; } .exc-message-empty-notice { color: #a29d9d; font-weight: 300; } .prev-exc-title { margin: 10px 0; } .prev-exc-title + ul { margin: 0; padding: 0 0 0 20px; line-height: 12px; } .prev-exc-title + ul li { font: 12px "Helvetica Neue", helvetica, arial, sans-serif; } .prev-exc-title + ul li .prev-exc-code { display: inline-block; color: #bebebe; } .details-container { left: 30%; width: 70%; background: #fafafa; } .details { padding: 5px; } .details-heading { color: #4288CE; font-weight: 300; padding-bottom: 10px; margin-bottom: 10px; border-bottom: 1px solid rgba(0, 0, 0, .1); } .details pre.sf-dump { white-space: pre; word-wrap: inherit; } .details pre.sf-dump, .details pre.sf-dump .sf-dump-num, .details pre.sf-dump .sf-dump-const, .details pre.sf-dump .sf-dump-str, .details pre.sf-dump .sf-dump-note, .details pre.sf-dump .sf-dump-ref, .details pre.sf-dump .sf-dump-public, .details pre.sf-dump .sf-dump-protected, .details pre.sf-dump .sf-dump-private, .details pre.sf-dump .sf-dump-meta, .details pre.sf-dump .sf-dump-key, .details pre.sf-dump .sf-dump-index { color: #463C54; } .left-panel { width: 30%; background: #ded8d8; } .frames-description { background: rgba(0, 0, 0, .05); padding: 8px 15px; color: #a29d9d; font-size: 11px; } .frames-description.frames-description-application { text-align: center; font-size: 12px; } .frames-container.frames-container-application .frame:not(.frame-application) { display: none; } .frames-tab { color: #a29d9d; display: inline-block; padding: 4px 8px; margin: 0 2px; border-radius: 3px; } .frames-tab.frames-tab-active { background-color: #2a2a2a; color: #bebebe; } .frame { padding: 14px; cursor: pointer; transition: all 0.1s ease; background: #eeeeee; } .frame:not(:last-child) { border-bottom: 1px solid rgba(0, 0, 0, .05); } .frame.active { box-shadow: inset -5px 0 0 0 #4288CE; color: #4288CE; } .frame:not(.active):hover { background: #BEE9EA; } .frame-method-info { margin-bottom: 10px; } .frame-class, .frame-function, .frame-index { font-size: 14px; } .frame-index { float: left; } .frame-method-info { margin-left: 24px; } .frame-index { font-size: 11px; color: #a29d9d; background-color: rgba(0, 0, 0, .05); height: 18px; width: 18px; line-height: 18px; border-radius: 5px; padding: 0 1px 0 1px; text-align: center; display: inline-block; } .frame-application .frame-index { background-color: #2a2a2a; color: #bebebe; } .frame-file { font-family: "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace; color: #a29d9d; } .frame-file .editor-link { color: #a29d9d; } .frame-line { font-weight: bold; } .frame-line:before { content: ":"; } .frame-code { padding: 5px; background: #303030; display: none; } .frame-code.active { display: block; } .frame-code .frame-file { color: #a29d9d; padding: 12px 6px; border-bottom: none; } .code-block { padding: 10px; margin: 0; border-radius: 6px; box-shadow: 0 3px 0 rgba(0, 0, 0, .05), 0 10px 30px rgba(0, 0, 0, .05), inset 0 0 1px 0 rgba(255, 255, 255, .07); -moz-tab-size: 4; -o-tab-size: 4; tab-size: 4; } .linenums { margin: 0; margin-left: 10px; } .frame-comments { border-top: none; margin-top: 15px; font-size: 12px; } .frame-comments.empty { } .frame-comments.empty:before { content: "No comments for this stack frame."; font-weight: 300; color: #a29d9d; } .frame-comment { padding: 10px; color: #e3e3e3; border-radius: 6px; background-color: rgba(255, 255, 255, .05); } .frame-comment a { font-weight: bold; text-decoration: underline; color: #c6c6c6; } .frame-comment:not(:last-child) { border-bottom: 1px dotted rgba(0, 0, 0, .3); } .frame-comment-context { font-size: 10px; color: white; } .delimiter { display: inline-block; } .data-table-container label { font-size: 16px; color: #303030; font-weight: bold; margin: 10px 0; display: block; margin-bottom: 5px; padding-bottom: 5px; } .data-table { width: 100%; margin-bottom: 10px; } .data-table tbody { font: 13px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace; } .data-table thead { display: none; } .data-table tr { padding: 5px 0; } .data-table td:first-child { width: 20%; min-width: 130px; overflow: hidden; font-weight: bold; color: #463C54; padding-right: 5px; } .data-table td:last-child { width: 80%; -ms-word-break: break-all; word-break: break-all; word-break: break-word; -webkit-hyphens: auto; -moz-hyphens: auto; hyphens: auto; } .data-table span.empty { color: rgba(0, 0, 0, .3); font-weight: 300; } .data-table label.empty { display: inline; } .handler { padding: 4px 0; font: 14px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace; } #plain-exception { display: none; } .rightButton { cursor: pointer; border: 0; opacity: .8; background: none; color: rgba(255, 255, 255, 0.1); box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.1); border-radius: 3px; outline: none !important; } .rightButton:hover { box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.3); color: rgba(255, 255, 255, 0.3); } /* inspired by githubs kbd styles */ kbd { -moz-border-bottom-colors: none; -moz-border-left-colors: none; -moz-border-right-colors: none; -moz-border-top-colors: none; background-color: #fcfcfc; border-color: #ccc #ccc #bbb; border-image: none; border-style: solid; border-width: 1px; color: #555; display: inline-block; font-size: 11px; line-height: 10px; padding: 3px 5px; vertical-align: middle; } /* == Media queries */ /* Expand the spacing in the details section */ @media (min-width: 1000px) { .details, .frame-code { padding: 20px 40px; } .details-container { left: 32%; width: 68%; } .frames-container { margin: 5px; } .left-panel { width: 32%; } } /* Stack panels */ @media (max-width: 600px) { .panel { position: static; width: 100%; } } /* Stack details tables */ @media (max-width: 400px) { .data-table, .data-table tbody, .data-table tbody tr, .data-table tbody td { display: block; width: 100%; } .data-table tbody tr:first-child { padding-top: 0; } .data-table tbody td:first-child, .data-table tbody td:last-child { padding-left: 0; padding-right: 0; } .data-table tbody td:last-child { padding-top: 3px; } } .tooltipped { position: relative } .tooltipped:after { position: absolute; z-index: 1000000; display: none; padding: 5px 8px; color: #fff; text-align: center; text-decoration: none; text-shadow: none; text-transform: none; letter-spacing: normal; word-wrap: break-word; white-space: pre; pointer-events: none; content: attr(aria-label); background: rgba(0, 0, 0, 0.8); border-radius: 3px; -webkit-font-smoothing: subpixel-antialiased } .tooltipped:before { position: absolute; z-index: 1000001; display: none; width: 0; height: 0; color: rgba(0, 0, 0, 0.8); pointer-events: none; content: ""; border: 5px solid transparent } .tooltipped:hover:before, .tooltipped:hover:after, .tooltipped:active:before, .tooltipped:active:after, .tooltipped:focus:before, .tooltipped:focus:after { display: inline-block; text-decoration: none } .tooltipped-s:after { top: 100%; right: 50%; margin-top: 5px } .tooltipped-s:before { top: auto; right: 50%; bottom: -5px; margin-right: -5px; border-bottom-color: rgba(0, 0, 0, 0.8) } pre.sf-dump { padding: 0px !important; margin: 0px !important; } .search-for-help { width: 85%; padding: 0; margin: 10px 0; list-style-type: none; display: inline-block; } .search-for-help li { display: inline-block; margin-right: 5px; } .search-for-help li:last-child { margin-right: 0; } .search-for-help li a { } .search-for-help li a i { width: 16px; height: 16px; overflow: hidden; display: block; } .search-for-help li a svg { fill: #fff; } .search-for-help li a svg path { background-size: contain; } .line-numbers-rows span { pointer-events: auto; cursor: pointer; } .line-numbers-rows span:hover { text-decoration: underline; } PKZZ$src/Whoops/Util/HtmlDumperOutput.phpnuW+A */ namespace Whoops\Util; /** * Used as output callable for Symfony\Component\VarDumper\Dumper\HtmlDumper::dump() * * @see TemplateHelper::dump() */ class HtmlDumperOutput { private $output; public function __invoke($line, $depth) { // A negative depth means "end of dump" if ($depth >= 0) { // Adds a two spaces indentation to the line $this->output .= str_repeat(' ', $depth) . $line . "\n"; } } public function getOutput() { return $this->output; } public function clear() { $this->output = null; } } PKZ %%"src/Whoops/Util/TemplateHelper.phpnuW+A */ namespace Whoops\Util; use Symfony\Component\VarDumper\Caster\Caster; use Symfony\Component\VarDumper\Cloner\AbstractCloner; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Whoops\Exception\Frame; /** * Exposes useful tools for working with/in templates */ class TemplateHelper { /** * An array of variables to be passed to all templates * @var array */ private $variables = []; /** * @var HtmlDumper */ private $htmlDumper; /** * @var HtmlDumperOutput */ private $htmlDumperOutput; /** * @var AbstractCloner */ private $cloner; /** * @var string */ private $applicationRootPath; public function __construct() { // root path for ordinary composer projects $this->applicationRootPath = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))); } /** * Escapes a string for output in an HTML document * * @param string $raw * @return string */ public function escape($raw) { $flags = ENT_QUOTES; // HHVM has all constants defined, but only ENT_IGNORE // works at the moment if (defined("ENT_SUBSTITUTE") && !defined("HHVM_VERSION")) { $flags |= ENT_SUBSTITUTE; } else { // This is for 5.3. // The documentation warns of a potential security issue, // but it seems it does not apply in our case, because // we do not blacklist anything anywhere. $flags |= ENT_IGNORE; } $raw = str_replace(chr(9), ' ', $raw); return htmlspecialchars($raw, $flags, "UTF-8"); } /** * Escapes a string for output in an HTML document, but preserves * URIs within it, and converts them to clickable anchor elements. * * @param string $raw * @return string */ public function escapeButPreserveUris($raw) { $escaped = $this->escape($raw); return preg_replace( "@([A-z]+?://([-\w\.]+[-\w])+(:\d+)?(/([\w/_\.#-]*(\?\S+)?[^\.\s])?)?)@", "$1", $escaped ); } /** * Makes sure that the given string breaks on the delimiter. * * @param string $delimiter * @param string $s * @return string */ public function breakOnDelimiter($delimiter, $s) { $parts = explode($delimiter, $s); foreach ($parts as &$part) { $part = '' . $part . ''; } return implode($delimiter, $parts); } /** * Replace the part of the path that all files have in common. * * @param string $path * @return string */ public function shorten($path) { if ($this->applicationRootPath != "/") { $path = str_replace($this->applicationRootPath, '…', $path); } return $path; } private function getDumper() { if (!$this->htmlDumper && class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) { $this->htmlDumperOutput = new HtmlDumperOutput(); // re-use the same var-dumper instance, so it won't re-render the global styles/scripts on each dump. $this->htmlDumper = new HtmlDumper($this->htmlDumperOutput); $styles = [ 'default' => 'color:#FFFFFF; line-height:normal; font:12px "Inconsolata", "Fira Mono", "Source Code Pro", Monaco, Consolas, "Lucida Console", monospace !important; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:99999; word-break: normal', 'num' => 'color:#BCD42A', 'const' => 'color: #4bb1b1;', 'str' => 'color:#BCD42A', 'note' => 'color:#ef7c61', 'ref' => 'color:#A0A0A0', 'public' => 'color:#FFFFFF', 'protected' => 'color:#FFFFFF', 'private' => 'color:#FFFFFF', 'meta' => 'color:#FFFFFF', 'key' => 'color:#BCD42A', 'index' => 'color:#ef7c61', ]; $this->htmlDumper->setStyles($styles); } return $this->htmlDumper; } /** * Format the given value into a human readable string. * * @param mixed $value * @return string */ public function dump($value) { $dumper = $this->getDumper(); if ($dumper) { // re-use the same DumpOutput instance, so it won't re-render the global styles/scripts on each dump. // exclude verbose information (e.g. exception stack traces) if (class_exists('Symfony\Component\VarDumper\Caster\Caster')) { $cloneVar = $this->getCloner()->cloneVar($value, Caster::EXCLUDE_VERBOSE); // Symfony VarDumper 2.6 Caster class dont exist. } else { $cloneVar = $this->getCloner()->cloneVar($value); } $dumper->dump( $cloneVar, $this->htmlDumperOutput ); $output = $this->htmlDumperOutput->getOutput(); $this->htmlDumperOutput->clear(); return $output; } return htmlspecialchars(print_r($value, true)); } /** * Format the args of the given Frame as a human readable html string * * @param Frame $frame * @return string the rendered html */ public function dumpArgs(Frame $frame) { // we support frame args only when the optional dumper is available if (!$this->getDumper()) { return ''; } $html = ''; $numFrames = count($frame->getArgs()); if ($numFrames > 0) { $html = '
    '; foreach ($frame->getArgs() as $j => $frameArg) { $html .= '
  1. '. $this->dump($frameArg) .'
  2. '; } $html .= '
'; } return $html; } /** * Convert a string to a slug version of itself * * @param string $original * @return string */ public function slug($original) { $slug = str_replace(" ", "-", $original); $slug = preg_replace('/[^\w\d\-\_]/i', '', $slug); return strtolower($slug); } /** * Given a template path, render it within its own scope. This * method also accepts an array of additional variables to be * passed to the template. * * @param string $template */ public function render($template, ?array $additionalVariables = null) { $variables = $this->getVariables(); // Pass the helper to the template: $variables["tpl"] = $this; if ($additionalVariables !== null) { $variables = array_replace($variables, $additionalVariables); } call_user_func(function () { extract(func_get_arg(1)); require func_get_arg(0); }, $template, $variables); } /** * Sets the variables to be passed to all templates rendered * by this template helper. */ public function setVariables(array $variables) { $this->variables = $variables; } /** * Sets a single template variable, by its name: * * @param string $variableName * @param mixed $variableValue */ public function setVariable($variableName, $variableValue) { $this->variables[$variableName] = $variableValue; } /** * Gets a single template variable, by its name, or * $defaultValue if the variable does not exist * * @param string $variableName * @param mixed $defaultValue * @return mixed */ public function getVariable($variableName, $defaultValue = null) { return isset($this->variables[$variableName]) ? $this->variables[$variableName] : $defaultValue; } /** * Unsets a single template variable, by its name * * @param string $variableName */ public function delVariable($variableName) { unset($this->variables[$variableName]); } /** * Returns all variables for this helper * * @return array */ public function getVariables() { return $this->variables; } /** * Set the cloner used for dumping variables. * * @param AbstractCloner $cloner */ public function setCloner($cloner) { $this->cloner = $cloner; } /** * Get the cloner used for dumping variables. * * @return AbstractCloner */ public function getCloner() { if (!$this->cloner) { $this->cloner = new VarCloner(); } return $this->cloner; } /** * Set the application root path. * * @param string $applicationRootPath */ public function setApplicationRootPath($applicationRootPath) { $this->applicationRootPath = $applicationRootPath; } /** * Return the application root path. * * @return string */ public function getApplicationRootPath() { return $this->applicationRootPath; } } PKZsrc/Whoops/Util/Misc.phpnuW+A */ namespace Whoops\Util; class Misc { /** * Can we at this point in time send HTTP headers? * * Currently this checks if we are even serving an HTTP request, * as opposed to running from a command line. * * If we are serving an HTTP request, we check if it's not too late. * * @return bool */ public static function canSendHeaders() { return isset($_SERVER["REQUEST_URI"]) && !headers_sent(); } public static function isAjaxRequest() { return ( !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'); } /** * Check, if possible, that this execution was triggered by a command line. * @return bool */ public static function isCommandLine() { return PHP_SAPI == 'cli'; } /** * Translate ErrorException code into the represented constant. * * @param int $error_code * @return string */ public static function translateErrorCode($error_code) { $constants = get_defined_constants(true); if (array_key_exists('Core', $constants)) { foreach ($constants['Core'] as $constant => $value) { if (substr($constant, 0, 2) == 'E_' && $value == $error_code) { return $constant; } } } return "E_UNKNOWN"; } /** * Determine if an error level is fatal (halts execution) * * @param int $level * @return bool */ public static function isLevelFatal($level) { $errors = E_ERROR; $errors |= E_PARSE; $errors |= E_CORE_ERROR; $errors |= E_CORE_WARNING; $errors |= E_COMPILE_ERROR; $errors |= E_COMPILE_WARNING; return ($level & $errors) > 0; } } PKZJ src/Whoops/Util/SystemFacade.phpnuW+A */ namespace Whoops\Util; class SystemFacade { /** * Turns on output buffering. * * @return bool */ public function startOutputBuffering() { return ob_start(); } /** * @param callable $handler * @param int $types * * @return callable|null */ public function setErrorHandler(callable $handler, $types = 'use-php-defaults') { // Since PHP 5.4 the constant E_ALL contains all errors (even E_STRICT) if ($types === 'use-php-defaults') { $types = E_ALL; } return set_error_handler($handler, $types); } /** * @param callable $handler * * @return callable|null */ public function setExceptionHandler(callable $handler) { return set_exception_handler($handler); } /** * @return void */ public function restoreExceptionHandler() { restore_exception_handler(); } /** * @return void */ public function restoreErrorHandler() { restore_error_handler(); } /** * @param callable $function * * @return void */ public function registerShutdownFunction(callable $function) { register_shutdown_function($function); } /** * @return string|false */ public function cleanOutputBuffer() { return ob_get_clean(); } /** * @return int */ public function getOutputBufferLevel() { return ob_get_level(); } /** * @return bool */ public function endOutputBuffering() { return ob_end_clean(); } /** * @return void */ public function flushOutputBuffer() { flush(); } /** * @return int */ public function getErrorReportingLevel() { return error_reporting(); } /** * @return array|null */ public function getLastError() { return error_get_last(); } /** * @param int $httpCode * * @return int */ public function setHttpResponseCode($httpCode) { if (!headers_sent()) { // Ensure that no 'location' header is present as otherwise this // will override the HTTP code being set here, and mask the // expected error page. header_remove('location'); } return http_response_code($httpCode); } /** * @param int $exitStatus */ public function stopExecution($exitStatus) { exit($exitStatus); } } PKZr[Y??src/Whoops/Run.phpnuW+A */ namespace Whoops; use InvalidArgumentException; use Throwable; use Whoops\Exception\ErrorException; use Whoops\Handler\CallbackHandler; use Whoops\Handler\Handler; use Whoops\Handler\HandlerInterface; use Whoops\Inspector\CallableInspectorFactory; use Whoops\Inspector\InspectorFactory; use Whoops\Inspector\InspectorFactoryInterface; use Whoops\Inspector\InspectorInterface; use Whoops\Util\Misc; use Whoops\Util\SystemFacade; final class Run implements RunInterface { /** * @var bool */ private $isRegistered; /** * @var bool */ private $allowQuit = true; /** * @var bool */ private $sendOutput = true; /** * @var integer|false */ private $sendHttpCode = 500; /** * @var integer|false */ private $sendExitCode = 1; /** * @var HandlerInterface[] */ private $handlerStack = []; /** * @var array * @psalm-var list */ private $silencedPatterns = []; /** * @var SystemFacade */ private $system; /** * In certain scenarios, like in shutdown handler, we can not throw exceptions. * * @var bool */ private $canThrowExceptions = true; /** * The inspector factory to create inspectors. * * @var InspectorFactoryInterface */ private $inspectorFactory; /** * @var array */ private $frameFilters = []; public function __construct(?SystemFacade $system = null) { $this->system = $system ?: new SystemFacade; $this->inspectorFactory = new InspectorFactory(); } /** * Explicitly request your handler runs as the last of all currently registered handlers. * * @param callable|HandlerInterface $handler * * @return Run */ public function appendHandler($handler) { array_unshift($this->handlerStack, $this->resolveHandler($handler)); return $this; } /** * Explicitly request your handler runs as the first of all currently registered handlers. * * @param callable|HandlerInterface $handler * * @return Run */ public function prependHandler($handler) { return $this->pushHandler($handler); } /** * Register your handler as the last of all currently registered handlers (to be executed first). * Prefer using appendHandler and prependHandler for clarity. * * @param callable|HandlerInterface $handler * * @return Run * * @throws InvalidArgumentException If argument is not callable or instance of HandlerInterface. */ public function pushHandler($handler) { $this->handlerStack[] = $this->resolveHandler($handler); return $this; } /** * Removes and returns the last handler pushed to the handler stack. * * @see Run::removeFirstHandler(), Run::removeLastHandler() * * @return HandlerInterface|null */ public function popHandler() { return array_pop($this->handlerStack); } /** * Removes the first handler. * * @return void */ public function removeFirstHandler() { array_pop($this->handlerStack); } /** * Removes the last handler. * * @return void */ public function removeLastHandler() { array_shift($this->handlerStack); } /** * Returns an array with all handlers, in the order they were added to the stack. * * @return array */ public function getHandlers() { return $this->handlerStack; } /** * Clears all handlers in the handlerStack, including the default PrettyPage handler. * * @return Run */ public function clearHandlers() { $this->handlerStack = []; return $this; } public function getFrameFilters() { return $this->frameFilters; } public function clearFrameFilters() { $this->frameFilters = []; return $this; } /** * Registers this instance as an error handler. * * @return Run */ public function register() { if (!$this->isRegistered) { // Workaround PHP bug 42098 // https://bugs.php.net/bug.php?id=42098 class_exists("\\Whoops\\Exception\\ErrorException"); class_exists("\\Whoops\\Exception\\FrameCollection"); class_exists("\\Whoops\\Exception\\Frame"); class_exists("\\Whoops\\Exception\\Inspector"); class_exists("\\Whoops\\Inspector\\InspectorFactory"); $this->system->setErrorHandler([$this, self::ERROR_HANDLER]); $this->system->setExceptionHandler([$this, self::EXCEPTION_HANDLER]); $this->system->registerShutdownFunction([$this, self::SHUTDOWN_HANDLER]); $this->isRegistered = true; } return $this; } /** * Unregisters all handlers registered by this Whoops\Run instance. * * @return Run */ public function unregister() { if ($this->isRegistered) { $this->system->restoreExceptionHandler(); $this->system->restoreErrorHandler(); $this->isRegistered = false; } return $this; } /** * Should Whoops allow Handlers to force the script to quit? * * @param bool|int $exit * * @return bool */ public function allowQuit($exit = null) { if (func_num_args() == 0) { return $this->allowQuit; } return $this->allowQuit = (bool) $exit; } /** * Silence particular errors in particular files. * * @param array|string $patterns List or a single regex pattern to match. * @param int $levels Defaults to E_STRICT | E_DEPRECATED. * * @return Run */ public function silenceErrorsInPaths($patterns, $levels = 10240) { $this->silencedPatterns = array_merge( $this->silencedPatterns, array_map( function ($pattern) use ($levels) { return [ "pattern" => $pattern, "levels" => $levels, ]; }, (array) $patterns ) ); return $this; } /** * Returns an array with silent errors in path configuration. * * @return array */ public function getSilenceErrorsInPaths() { return $this->silencedPatterns; } /** * Should Whoops send HTTP error code to the browser if possible? * Whoops will by default send HTTP code 500, but you may wish to * use 502, 503, or another 5xx family code. * * @param bool|int $code * * @return int|false * * @throws InvalidArgumentException */ public function sendHttpCode($code = null) { if (func_num_args() == 0) { return $this->sendHttpCode; } if (!$code) { return $this->sendHttpCode = false; } if ($code === true) { $code = 500; } if ($code < 400 || 600 <= $code) { throw new InvalidArgumentException( "Invalid status code '$code', must be 4xx or 5xx" ); } return $this->sendHttpCode = $code; } /** * Should Whoops exit with a specific code on the CLI if possible? * Whoops will exit with 1 by default, but you can specify something else. * * @param int $code * * @return int * * @throws InvalidArgumentException */ public function sendExitCode($code = null) { if (func_num_args() == 0) { return $this->sendExitCode; } if ($code < 0 || 255 <= $code) { throw new InvalidArgumentException( "Invalid status code '$code', must be between 0 and 254" ); } return $this->sendExitCode = (int) $code; } /** * Should Whoops push output directly to the client? * If this is false, output will be returned by handleException. * * @param bool|int $send * * @return bool */ public function writeToOutput($send = null) { if (func_num_args() == 0) { return $this->sendOutput; } return $this->sendOutput = (bool) $send; } /** * Handles an exception, ultimately generating a Whoops error page. * * @param Throwable $exception * * @return string Output generated by handlers. */ public function handleException($exception) { // Walk the registered handlers in the reverse order // they were registered, and pass off the exception $inspector = $this->getInspector($exception); // Capture output produced while handling the exception, // we might want to send it straight away to the client, // or return it silently. $this->system->startOutputBuffering(); // Just in case there are no handlers: $handlerResponse = null; $handlerContentType = null; try { foreach (array_reverse($this->handlerStack) as $handler) { $handler->setRun($this); $handler->setInspector($inspector); $handler->setException($exception); // The HandlerInterface does not require an Exception passed to handle() // and neither of our bundled handlers use it. // However, 3rd party handlers may have already relied on this parameter, // and removing it would be possibly breaking for users. $handlerResponse = $handler->handle($exception); // Collect the content type for possible sending in the headers. $handlerContentType = method_exists($handler, 'contentType') ? $handler->contentType() : null; if (in_array($handlerResponse, [Handler::LAST_HANDLER, Handler::QUIT])) { // The Handler has handled the exception in some way, and // wishes to quit execution (Handler::QUIT), or skip any // other handlers (Handler::LAST_HANDLER). If $this->allowQuit // is false, Handler::QUIT behaves like Handler::LAST_HANDLER break; } } $willQuit = $handlerResponse == Handler::QUIT && $this->allowQuit(); } finally { $output = $this->system->cleanOutputBuffer(); } // If we're allowed to, send output generated by handlers directly // to the output, otherwise, and if the script doesn't quit, return // it so that it may be used by the caller if ($this->writeToOutput()) { // @todo Might be able to clean this up a bit better if ($willQuit) { // Cleanup all other output buffers before sending our output: while ($this->system->getOutputBufferLevel() > 0) { $this->system->endOutputBuffering(); } // Send any headers if needed: if (Misc::canSendHeaders() && $handlerContentType) { header("Content-Type: {$handlerContentType}"); } } $this->writeToOutputNow($output); } if ($willQuit) { // HHVM fix for https://github.com/facebook/hhvm/issues/4055 $this->system->flushOutputBuffer(); $this->system->stopExecution( $this->sendExitCode() ); } return $output; } /** * Converts generic PHP errors to \ErrorException instances, before passing them off to be handled. * * This method MUST be compatible with set_error_handler. * * @param int $level * @param string $message * @param string|null $file * @param int|null $line * * @return bool * * @throws ErrorException */ public function handleError($level, $message, $file = null, $line = null) { if ($level & $this->system->getErrorReportingLevel()) { foreach ($this->silencedPatterns as $entry) { $pathMatches = (bool) preg_match($entry["pattern"], $file); $levelMatches = $level & $entry["levels"]; if ($pathMatches && $levelMatches) { // Ignore the error, abort handling // See https://github.com/filp/whoops/issues/418 return true; } } // XXX we pass $level for the "code" param only for BC reasons. // see https://github.com/filp/whoops/issues/267 $exception = new ErrorException($message, /*code*/ $level, /*severity*/ $level, $file, $line); if ($this->canThrowExceptions) { throw $exception; } else { $this->handleException($exception); } // Do not propagate errors which were already handled by Whoops. return true; } // Propagate error to the next handler, allows error_get_last() to // work on silenced errors. return false; } /** * Special case to deal with Fatal errors and the like. * * @return void */ public function handleShutdown() { // If we reached this step, we are in shutdown handler. // An exception thrown in a shutdown handler will not be propagated // to the exception handler. Pass that information along. $this->canThrowExceptions = false; $error = $this->system->getLastError(); if ($error && Misc::isLevelFatal($error['type'])) { // If there was a fatal error, // it was not handled in handleError yet. $this->allowQuit = false; $this->handleError( $error['type'], $error['message'], $error['file'], $error['line'] ); } } /** * @param InspectorFactoryInterface $factory * * @return void */ public function setInspectorFactory(InspectorFactoryInterface $factory) { $this->inspectorFactory = $factory; } public function addFrameFilter($filterCallback) { if (!is_callable($filterCallback)) { throw new \InvalidArgumentException(sprintf( "A frame filter must be of type callable, %s type given.", gettype($filterCallback) )); } $this->frameFilters[] = $filterCallback; return $this; } /** * @param Throwable $exception * * @return InspectorInterface */ private function getInspector($exception) { return $this->inspectorFactory->create($exception); } /** * Resolves the giving handler. * * @param callable|HandlerInterface $handler * * @return HandlerInterface * * @throws InvalidArgumentException */ private function resolveHandler($handler) { if (is_callable($handler)) { $handler = new CallbackHandler($handler); } if (!$handler instanceof HandlerInterface) { throw new InvalidArgumentException( "Handler must be a callable, or instance of " . "Whoops\\Handler\\HandlerInterface" ); } return $handler; } /** * Echo something to the browser. * * @param string $output * * @return Run */ private function writeToOutputNow($output) { if ($this->sendHttpCode() && Misc::canSendHeaders()) { $this->system->setHttpResponseCode( $this->sendHttpCode() ); } echo $output; return $this; } } PKZFF.mailmapnuW+ADenis Sokolov Filipe Dobreira PKZ&|00 SECURITY.mdnuW+A# Security Policy ## Supported Versions Only the latest released version of Whoops is supported. To facilitate upgrades we almost never make backwards-incompatible changes. ## Reporting a Vulnerability Please report vulnerabilities over email, by sending an email to `denis` at `sokolov` dot `cc`. PKZ> composer.jsonnuW+A{ "name": "filp/whoops", "license": "MIT", "description": "php error handling for cool kids", "keywords": ["library", "error", "handling", "exception", "whoops", "throwable"], "homepage": "https://filp.github.io/whoops/", "authors": [ { "name": "Filipe Dobreira", "homepage": "https://github.com/filp", "role": "Developer" } ], "scripts": { "test": "phpunit --testdox tests" }, "require": { "php": "^7.1 || ^8.0", "psr/log": "^1.0.1 || ^2.0 || ^3.0" }, "require-dev": { "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", "mockery/mockery": "^1.0", "symfony/var-dumper": "^4.0 || ^5.0" }, "suggest": { "symfony/var-dumper": "Pretty print complex values better with var-dumper available", "whoops/soap": "Formats errors as SOAP responses" }, "autoload": { "psr-4": { "Whoops\\": "src/Whoops/" } }, "autoload-dev": { "psr-4": { "Whoops\\": "tests/Whoops/" } }, "extra": { "branch-alias": { "dev-master": "2.7-dev" } } } PKZ' LICENSE.mdnuW+APKZ / LCHANGELOG.mdnuW+APKZ ))(src/Whoops/Exception/FrameCollection.phpnuW+APKZ.%%"%src/Whoops/Exception/Inspector.phpnuW+APKZ9Un "2Ksrc/Whoops/Exception/Formatter.phpnuW+APKZ"sCcc'Usrc/Whoops/Exception/ErrorException.phpnuW+APKZŢVsrc/Whoops/Exception/Frame.phpnuW+APKZىwsrc/Whoops/RunInterface.phpnuW+APKZe5++2$src/Whoops/Inspector/InspectorFactoryInterface.phpnuW+APKZ^>+src/Whoops/Inspector/InspectorInterface.phpnuW+APKZeY)*src/Whoops/Inspector/InspectorFactory.phpnuW+APKZBU$HH&#src/Whoops/Handler/CallbackHandler.phpnuW+APKZzzsrc/Whoops/Handler/Handler.phpnuW+APKZ A )src/Whoops/Handler/XmlResponseHandler.phpnuW+APKZt7dd(src/Whoops/Handler/PrettyPageHandler.phpnuW+APKZԷ'src/Whoops/Handler/HandlerInterface.phpnuW+APKZU # #'src/Whoops/Handler/PlainTextHandler.phpnuW+APKZkZ==*|5src/Whoops/Handler/JsonResponseHandler.phpnuW+APKZL"L"(>src/Whoops/Resources/js/clipboard.min.jsnuW+APKZ/0<`<`$`src/Whoops/Resources/js/zepto.min.jsnuW+APKZ~_<&Gsrc/Whoops/Resources/js/whoops.base.jsnuW+APKZ>^>^ Psrc/Whoops/Resources/js/prism.jsnuW+APKZ.|w4409src/Whoops/Resources/views/header_outer.html.phpnuW+APKZ-_/r:src/Whoops/Resources/views/env_details.html.phpnuW+APKZ*ro o .@src/Whoops/Resources/views/frame_code.html.phpnuW+APKZ.Lsrc/Whoops/Resources/views/frame_list.html.phpnuW+APKZ"hh.$Qsrc/Whoops/Resources/views/panel_left.html.phpnuW+APKZYyy4Qsrc/Whoops/Resources/views/panel_left_outer.html.phpnuW+APKZGw"WW7Rsrc/Whoops/Resources/views/panel_details_outer.html.phpnuW+APKZ޲!mm*Ssrc/Whoops/Resources/views/layout.html.phpnuW+APKZ\ FF1LWsrc/Whoops/Resources/views/panel_details.html.phpnuW+APKZkg%$$*Wsrc/Whoops/Resources/views/header.html.phpnuW+APKZ W4}src/Whoops/Resources/views/frames_container.html.phpnuW+APKZ6~src/Whoops/Resources/views/frames_description.html.phpnuW+APKZ$ȁ4 "src/Whoops/Resources/css/prism.cssnuW+APKZ4׌(((src/Whoops/Resources/css/whoops.base.cssnuW+APKZZ$ֶsrc/Whoops/Util/HtmlDumperOutput.phpnuW+APKZ %%"src/Whoops/Util/TemplateHelper.phpnuW+APKZNsrc/Whoops/Util/Misc.phpnuW+APKZJ Ysrc/Whoops/Util/SystemFacade.phpnuW+APKZr[Y??8src/Whoops/Run.phpnuW+APKZFF#2.mailmapnuW+APKZ&|00 2SECURITY.mdnuW+APKZ>  4composer.jsonnuW+APK,,D8