Server IP : 213.176.29.180 / Your IP : 18.191.171.136 Web Server : Apache System : Linux 213.176.29.180.hostiran.name 4.18.0-553.22.1.el8_10.x86_64 #1 SMP Tue Sep 24 05:16:59 EDT 2024 x86_64 User : webtaragh ( 1001) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON Directory (0750) : /home/webtaragh/public_html/../www/wp-admin/../ |
[ Home ] | [ C0mmand ] | [ Upload File ] |
---|
whoops/CONTRIBUTING.md 0000644 00000001662 14736103200 0010315 0 ustar 00 If you want to give me some feedback or make a suggestion, create an [issue on GitHub](https://github.com/filp/whoops/issues/new). If you want to get your hands dirty, great! Here's a couple of steps/guidelines: - See [a list of possible features to add](https://github.com/filp/whoops/wiki/Possible-features-to-add) for ideas on what can be improved. - Add tests for your changes (in `tests/`). - Remember to stick to the existing code style as best as possible. When in doubt, follow `PSR-2`. - Before investing a lot of time coding, create an issue to get our opinion on your big changes. - Update the documentation, if applicable. - If you want to add an integration to a web framework, please [review our guidelines for that](docs/Framework%20Integration.md#contributing-an-integration-with-a-framework). In `PrettyPageHandler` we are using a Zepto library, but if you are only familiar with jQuery, note that it is pretty much identical. whoops/.mailmap 0000644 00000000106 14736103200 0007475 0 ustar 00 Denis Sokolov <denis@sokolov.cc> Filipe Dobreira <dobreira@gmail.com> whoops/src/Whoops/Util/Misc.php 0000644 00000003703 14736103200 0012451 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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; } } whoops/src/Whoops/Util/TemplateHelper.php 0000644 00000022523 14736103200 0014472 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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])?)?)@", "<a href=\"$1\" target=\"_blank\" rel=\"noreferrer noopener\">$1</a>", $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 = '<span class="delimiter">' . $part . '</span>'; } 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 = '<ol class="linenums">'; foreach ($frame->getArgs() as $j => $frameArg) { $html .= '<li>'. $this->dump($frameArg) .'</li>'; } $html .= '</ol>'; } 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 * @param array $additionalVariables */ 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. * * @param array $variables */ 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; } } whoops/src/Whoops/Util/HtmlDumperOutput.php 0000644 00000001316 14736103200 0015056 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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; } } whoops/src/Whoops/Util/SystemFacade.php 0000644 00000005217 14736103200 0014130 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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); } } whoops/src/Whoops/RunInterface.php 0000644 00000007120 14736103200 0013223 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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(); /** * 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(); } whoops/src/Whoops/Handler/CallbackHandler.php 0000644 00000002510 14736103200 0015203 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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); } } whoops/src/Whoops/Handler/Handler.php 0000644 00000003515 14736103200 0013574 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ namespace Whoops\Handler; use Whoops\Exception\Inspector; 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 Inspector $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 Inspector $inspector */ public function setInspector(Inspector $inspector) { $this->inspector = $inspector; } /** * @return Inspector */ protected function getInspector() { return $this->inspector; } /** * @param \Throwable $exception */ public function setException($exception) { $this->exception = $exception; } /** * @return \Throwable */ protected function getException() { return $this->exception; } } whoops/src/Whoops/Handler/PlainTextHandler.php 0000644 00000021351 14736103200 0015423 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> * Plaintext handler for command line and logs. * @author Pierre-Yves Landuré <https://howto.biapy.com/> */ 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(); $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'; } } whoops/src/Whoops/Handler/JsonResponseHandler.php 0000644 00000003711 14736103200 0016143 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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() ), ] ]; } else { $response = [ 'error' => Formatter::formatExceptionAsDataArray( $this->getInspector(), $this->addTraceToOutput() ), ]; } 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'; } } whoops/src/Whoops/Handler/HandlerInterface.php 0000644 00000001317 14736103200 0015413 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ namespace Whoops\Handler; use Whoops\Exception\Inspector; 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 Inspector $inspector * @return void */ public function setInspector(Inspector $inspector); } whoops/src/Whoops/Handler/XmlResponseHandler.php 0000644 00000005157 14736103200 0016000 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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() ), ]; 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("<?xml version='1.0' encoding='utf-8'?><root />"); return self::addDataToNode($node, $data)->asXML(); } } whoops/src/Whoops/Handler/PrettyPageHandler.php 0000644 00000062200 14736103200 0015575 0 ustar 00 <?php /** * Whoops - php errors for cool kids * @author Filipe Dobreira <http://github.com/filp> */ 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"; /** * 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", ]; /** * @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->setException($this->getException()); $plainTextHandler->setInspector($this->getInspector()); $vars["preface"] = "<!--\n\n\n" . $this->templateHelper->escape($plainTextHandler->generateResponse()) . "\n\n\n\n\n\n\n\n\n\n\n-->"; $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(); 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 * @param array $data * * @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\Exception\Inspector $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. * * @param array $applicationPaths * * @return void */ public function setApplicationPaths($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 $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(array $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; } } whoops/src/Whoops/Resources/css/whoops.base.css 0000644 00000024065 14736103200 0015640 0 ustar 00 body { 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: none; } .frame-comment a:hover { color: #4bb1b1; } .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; } whoops/src/Whoops/Resources/css/prism.css 0000644 00000010236 14736103200 0014535 0 ustar 00 /* PrismJS 1.24.1 https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+markup-templating+php&plugins=line-highlight+line-numbers */ /** * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML * Based on https://github.com/chriskempson/tomorrow-theme * @author Rose Pritchard */ code[class*="language-"], pre[class*="language-"] { color: #ccc; background: none; 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; } /* Code blocks */ pre[class*="language-"] { padding: 1em; margin: .5em 0; overflow: auto; } :not(pre) > code[class*="language-"], pre[class*="language-"] { background: #2d2d2d; } /* Inline code */ :not(pre) > code[class*="language-"] { padding: .1em; border-radius: .3em; white-space: normal; } .token.comment, .token.block-comment, .token.prolog, .token.doctype, .token.cdata { color: #999; } .token.punctuation { color: #ccc; } .token.tag, .token.attr-name, .token.namespace, .token.deleted { color: #e2777a; } .token.function-name { color: #6196cc; } .token.boolean, .token.number, .token.function { color: #f08d49; } .token.property, .token.class-name, .token.constant, .token.symbol { color: #f8c555; } .token.selector, .token.important, .token.atrule, .token.keyword, .token.builtin { color: #cc99cd; } .token.string, .token.char, .token.attr-value, .token.regex, .token.variable { color: #7ec699; } .token.operator, .token.entity, .token.url { color: #67cdcc; } .token.important, .token.bold { font-weight: bold; } .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; /* Same as .prism’s padding-top */ 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 { /* * This will prevent browsers from replacing the background color with white. * It's necessary because the element is layered on top of the displayed code. */ -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: hsl(24, 20%, 95%); font: bold 65%/1.5 sans-serif; text-align: center; vertical-align: .3em; border-radius: 999px; text-shadow: none; box-shadow: 0 1px white; } .line-highlight[data-end]:after { content: attr(data-end); top: auto; bottom: .4em; } .line-numbers .line-highlight:before, .line-numbers .line-highlight:after { 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; /* works for line-numbers below 1000 lines */ 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: 0.8em; text-align: right; } whoops/src/Whoops/Resources/views/frame_list.html.php 0000644 00000002017 14736103200 0017035 0 ustar 00 <?php /* List file names & line numbers for all stack frames; clicking these links/buttons will display the code view for that particular frame */ ?> <?php foreach ($frames as $i => $frame): ?> <div class="frame <?php echo ($i == 0 ? 'active' : '') ?> <?php echo ($frame->isApplication() ? 'frame-application' : '') ?>" id="frame-line-<?php echo $i ?>"> <span class="frame-index"><?php echo (count($frames) - $i - 1) ?></span> <div class="frame-method-info"> <span class="frame-class"><?php echo $tpl->breakOnDelimiter('\\', $tpl->escape($frame->getClass() ?: '')) ?></span> <span class="frame-function"><?php echo $tpl->breakOnDelimiter('\\', $tpl->escape($frame->getFunction() ?: '')) ?></span> </div> <div class="frame-file"> <?php echo $frame->getFile() ? $tpl->breakOnDelimiter('/', $tpl->shorten($tpl->escape($frame->getFile()))) : '<#unknown>' ?><!-- --><span class="frame-line"><?php echo (int) $frame->getLine() ?></span> </div> </div> <?php endforeach; whoops/src/Whoops/Resources/views/frames_container.html.php 0000644 00000000242 14736103200 0020225 0 ustar 00 <div class="frames-container <?php echo $active_frames_tab == 'application' ? 'frames-container-application' : '' ?>"> <?php $tpl->render($frame_list) ?> </div>