This commit is contained in:
Bastian Allgeier
2020-07-07 12:40:13 +02:00
parent 5f025ac2c2
commit f79d2e960c
176 changed files with 10532 additions and 5343 deletions

View File

@@ -46,6 +46,11 @@ class PlainTextHandler extends Handler
*/
private $traceFunctionArgsOutputLimit = 1024;
/**
* @var bool
*/
private $addPreviousToOutput = true;
/**
* @var bool
*/
@@ -114,6 +119,21 @@ class PlainTextHandler extends Handler
return $this;
}
/**
* Add previous exceptions to output.
* @param bool|null $addPreviousToOutput
* @return bool|$this
*/
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.
@@ -151,14 +171,18 @@ class PlainTextHandler extends Handler
public function generateResponse()
{
$exception = $this->getException();
return sprintf(
"%s: %s in file %s on line %d%s\n",
get_class($exception),
$exception->getMessage(),
$exception->getFile(),
$exception->getLine(),
$this->getTraceOutput()
);
$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";
}
/**
@@ -284,6 +308,22 @@ class PlainTextHandler extends Handler
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
*/

View File

@@ -17,9 +17,21 @@ 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";
/**
* Search paths to be scanned for resources, in the reverse
* order they're declared.
* Search paths to be scanned for resources.
*
* Stored in the reverse order they're declared.
*
* @var array
*/
@@ -39,6 +51,13 @@ class PrettyPageHandler extends Handler
*/
private $customCss = null;
/**
* The name of the custom js file.
*
* @var string
*/
private $customJs = null;
/**
* @var array[]
*/
@@ -73,19 +92,22 @@ class PrettyPageHandler extends Handler
];
/**
* A string identifier for a known IDE/text editor, 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.
* 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 mixed $editor
* "txmt://open?url=%file&line=%line"
*
* @var callable|string $editor
*/
protected $editor;
/**
* A list of known editor strings
* A list of known editor strings.
*
* @var array
*/
protected $editors = [
@@ -97,15 +119,18 @@ class PrettyPageHandler extends Handler
"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",
];
/**
* @var TemplateHelper
*/
private $templateHelper;
protected $templateHelper;
/**
* Constructor.
*
* @return void
*/
public function __construct()
{
@@ -114,6 +139,9 @@ class PrettyPageHandler extends Handler
$this->editors['xdebug'] = function ($file, $line) {
return str_replace(['%f', '%l'], [$file, $line], ini_get('xdebug.file_link_format'));
};
// If xdebug is available, use it as default editor.
$this->setEditor('xdebug');
}
// Add the default, local resource search path:
@@ -126,10 +154,11 @@ class PrettyPageHandler extends Handler
if (class_exists('Symfony\Component\VarDumper\Cloner\VarCloner')) {
$cloner = new VarCloner();
// Only dump object internals if a custom caster exists.
// 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($class) + class_implements($class);
$classes = [$class => $class] + class_parents($obj) + class_implements($obj);
foreach ($classes as $class) {
if (isset(AbstractCloner::$defaultCasters[$class])) {
@@ -177,6 +206,10 @@ class PrettyPageHandler extends Handler
$customCssFile = $this->getResource($this->customCss);
}
if ($this->customJs) {
$customJsFile = $this->getResource($this->customJs);
}
$inspector = $this->getInspector();
$frames = $this->getExceptionFrames();
$code = $this->getExceptionCode();
@@ -236,6 +269,10 @@ class PrettyPageHandler extends Handler
$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) {
@@ -255,9 +292,9 @@ class PrettyPageHandler extends Handler
}
/**
* Get the stack trace frames of the exception that is currently being handled.
* Get the stack trace frames of the exception currently being handled.
*
* @return \Whoops\Exception\FrameCollection;
* @return \Whoops\Exception\FrameCollection
*/
protected function getExceptionFrames()
{
@@ -278,7 +315,7 @@ class PrettyPageHandler extends Handler
}
/**
* Get the code of the exception that is currently being handled.
* Get the code of the exception currently being handled.
*
* @return string
*/
@@ -305,10 +342,14 @@ class PrettyPageHandler extends Handler
/**
* 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
* will be flattened with `print_r`.
*
* @param string $label
* @param array $data
*
* @return void
*/
public function addDataTable($label, array $data)
{
@@ -317,13 +358,17 @@ class PrettyPageHandler extends Handler
/**
* 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.
*
* 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
* @param string $label
* @param callable $callback Callable returning an associative array
*
* @return void
*/
public function addDataTableCallback($label, /* callable */ $callback)
{
@@ -346,9 +391,12 @@ class PrettyPageHandler extends Handler
/**
* 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
*
* 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)
@@ -362,10 +410,14 @@ class PrettyPageHandler extends Handler
}
/**
* 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
* 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|null
*/
public function handleUnconditionally($value = null)
@@ -378,10 +430,11 @@ class PrettyPageHandler extends Handler
}
/**
* Adds an editor resolver, identified by a string
* name, and that may be a string path, or a callable
* resolver. If the callable returns a string, it will
* be set as the file reference's href attribute.
* 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")
@@ -390,8 +443,11 @@ class PrettyPageHandler extends Handler
* unlink($file);
* return "http://stackoverflow.com";
* });
* @param string $identifier
* @param string $resolver
*
* @param string $identifier
* @param string|callable $resolver
*
* @return void
*/
public function addEditor($identifier, $resolver)
{
@@ -399,18 +455,21 @@ class PrettyPageHandler extends Handler
}
/**
* Set the editor to use to open referenced files, by a string
* identifier, or a callable that will be executed for every
* file reference, with a $file and $line argument, and should
* return a string.
* 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
* @param string|callable $editor
*
* @return void
*/
public function setEditor($editor)
{
@@ -425,14 +484,13 @@ class PrettyPageHandler extends Handler
}
/**
* Given a string file path, and an integer file line,
* executes the editor resolver and returns, if available,
* a string that may be used as the href property for that
* file reference.
* 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
* @param string $filePath
* @param int $line
*
* @return string|bool
*/
public function getEditorHref($filePath, $line)
@@ -458,13 +516,13 @@ class PrettyPageHandler extends Handler
}
/**
* Given a boolean if the editor link should
* act as an Ajax request. The editor must be a
* valid callable function/closure
* 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
*
* @throws UnexpectedValueException If editor resolver does not return a boolean
* @param string $filePath
* @param int $line
* @return bool
*/
public function getEditorAjax($filePath, $line)
@@ -481,12 +539,11 @@ class PrettyPageHandler extends Handler
}
/**
* Given a boolean if the editor link should
* act as an Ajax request. The editor must be a
* valid callable function/closure
* Determines both the editor and if ajax should be used.
*
* @param string $filePath
* @param int $line
*
* @param string $filePath
* @param int $line
* @return array
*/
protected function getEditor($filePath, $line)
@@ -530,7 +587,10 @@ class PrettyPageHandler extends Handler
}
/**
* @param string $title
* Set the page title.
*
* @param string $title
*
* @return void
*/
public function setPageTitle($title)
@@ -539,6 +599,8 @@ class PrettyPageHandler extends Handler
}
/**
* Get the page title.
*
* @return string
*/
public function getPageTitle()
@@ -547,12 +609,12 @@ class PrettyPageHandler extends Handler
}
/**
* Adds a path to the list of paths to be searched for
* resources.
* 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
*
* @param string $path
* @return void
*/
public function addResourcePath($path)
@@ -569,7 +631,8 @@ class PrettyPageHandler extends Handler
/**
* Adds a custom css file to be loaded.
*
* @param string $name
* @param string $name
*
* @return void
*/
public function addCustomCss($name)
@@ -577,6 +640,17 @@ class PrettyPageHandler extends Handler
$this->customCss = $name;
}
/**
* Adds a custom js file to be loaded.
*
* @param string $name
* @return void
*/
public function addCustomJs($name)
{
$this->customJs = $name;
}
/**
* @return array
*/
@@ -587,13 +661,15 @@ class PrettyPageHandler extends Handler
/**
* 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.
* 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
*
* @param string $resource
* @return string
*/
protected function getResource($resource)
@@ -639,7 +715,8 @@ class PrettyPageHandler extends Handler
/**
* @deprecated
*
* @param string $resourcesPath
* @param string $resourcesPath
*
* @return void
*/
public function setResourcesPath($resourcesPath)
@@ -661,6 +738,8 @@ class PrettyPageHandler extends Handler
* Set the application paths.
*
* @param array $applicationPaths
*
* @return void
*/
public function setApplicationPaths($applicationPaths)
{
@@ -671,6 +750,8 @@ class PrettyPageHandler extends Handler
* Set the application root path.
*
* @param string $applicationRootPath
*
* @return void
*/
public function setApplicationRootPath($applicationRootPath)
{
@@ -680,8 +761,10 @@ class PrettyPageHandler extends Handler
/**
* blacklist a sensitive value within one of the superglobal arrays.
*
* @param $superGlobalName string the name of the superglobal array, e.g. '_GET'
* @param $key string the key within the superglobal
* @param string $superGlobalName The name of the superglobal array, e.g. '_GET'
* @param string $key The key within the superglobal
*
* @return void
*/
public function blacklist($superGlobalName, $key)
{
@@ -690,12 +773,14 @@ class PrettyPageHandler extends Handler
/**
* Checks all values within the given superGlobal array.
* Blacklisted values will be replaced by a equal length string cointaining only '*' characters.
*
* We intentionally dont rely on $GLOBALS as it depends on 'auto_globals_jit' php.ini setting.
* Blacklisted values will be replaced by a equal length string cointaining
* only '*' characters. 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'
*
* @param $superGlobal array One of the superglobal arrays
* @param $superGlobalName string the name of the superglobal array, e.g. '_GET'
* @return array $values without sensitive data
*/
private function masked(array $superGlobal, $superGlobalName)
@@ -703,11 +788,13 @@ class PrettyPageHandler extends Handler
$blacklisted = $this->blacklist[$superGlobalName];
$values = $superGlobal;
foreach ($blacklisted as $key) {
if (isset($superGlobal[$key])) {
if (isset($superGlobal[$key]) && is_string($superGlobal[$key])) {
$values[$key] = str_repeat('*', strlen($superGlobal[$key]));
}
}
return $values;
}
}

View File

@@ -47,7 +47,7 @@ class XmlResponseHandler extends Handler
),
];
echo $this->toXml($response);
echo self::toXml($response);
return Handler::QUIT;
}