|
|
|
|
@@ -30,27 +30,37 @@ use Symfony\Component\Debug\Exception\OutOfMemoryException;
|
|
|
|
|
class ExceptionHandler
|
|
|
|
|
{
|
|
|
|
|
private $debug;
|
|
|
|
|
private $charset;
|
|
|
|
|
private $handler;
|
|
|
|
|
private $caughtBuffer;
|
|
|
|
|
private $caughtLength;
|
|
|
|
|
private $fileLinkFormat;
|
|
|
|
|
|
|
|
|
|
public function __construct($debug = true, $fileLinkFormat = null)
|
|
|
|
|
public function __construct($debug = true, $charset = null, $fileLinkFormat = null)
|
|
|
|
|
{
|
|
|
|
|
if (false !== strpos($charset, '%') xor false === strpos($fileLinkFormat, '%')) {
|
|
|
|
|
// Swap $charset and $fileLinkFormat for BC reasons
|
|
|
|
|
$pivot = $fileLinkFormat;
|
|
|
|
|
$fileLinkFormat = $charset;
|
|
|
|
|
$charset = $pivot;
|
|
|
|
|
}
|
|
|
|
|
$this->debug = $debug;
|
|
|
|
|
$this->charset = $charset ?: ini_get('default_charset') ?: 'UTF-8';
|
|
|
|
|
$this->fileLinkFormat = $fileLinkFormat ?: ini_get('xdebug.file_link_format') ?: get_cfg_var('xdebug.file_link_format');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Registers the exception handler.
|
|
|
|
|
*
|
|
|
|
|
* @param bool $debug
|
|
|
|
|
* @param bool $debug Enable/disable debug mode, where the stack trace is displayed
|
|
|
|
|
* @param string|null $charset The charset used by exception messages
|
|
|
|
|
* @param string|null $fileLinkFormat The IDE link template
|
|
|
|
|
*
|
|
|
|
|
* @return ExceptionHandler The registered exception handler
|
|
|
|
|
*/
|
|
|
|
|
public static function register($debug = true, $fileLinkFormat = null)
|
|
|
|
|
public static function register($debug = true, $charset = null, $fileLinkFormat = null)
|
|
|
|
|
{
|
|
|
|
|
$handler = new static($debug, $fileLinkFormat);
|
|
|
|
|
$handler = new static($debug, $charset, $fileLinkFormat);
|
|
|
|
|
|
|
|
|
|
$prev = set_exception_handler(array($handler, 'handle'));
|
|
|
|
|
if (is_array($prev) && $prev[0] instanceof ErrorHandler) {
|
|
|
|
|
@@ -177,6 +187,7 @@ class ExceptionHandler
|
|
|
|
|
foreach ($exception->getHeaders() as $name => $value) {
|
|
|
|
|
header($name.': '.$value, false);
|
|
|
|
|
}
|
|
|
|
|
header('Content-Type: text/html; charset='.$this->charset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo $this->decorate($this->getContent($exception), $this->getStylesheet($exception));
|
|
|
|
|
@@ -195,7 +206,7 @@ class ExceptionHandler
|
|
|
|
|
$exception = FlattenException::create($exception);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new Response($this->decorate($this->getContent($exception), $this->getStylesheet($exception)), $exception->getStatusCode(), $exception->getHeaders());
|
|
|
|
|
return Response::create($this->decorate($this->getContent($exception), $this->getStylesheet($exception)), $exception->getStatusCode(), $exception->getHeaders())->setCharset($this->charset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -223,7 +234,7 @@ class ExceptionHandler
|
|
|
|
|
foreach ($exception->toArray() as $position => $e) {
|
|
|
|
|
$ind = $count - $position + 1;
|
|
|
|
|
$class = $this->formatClass($e['class']);
|
|
|
|
|
$message = nl2br(self::utf8Htmlize($e['message']));
|
|
|
|
|
$message = nl2br($this->escapeHtml($e['message']));
|
|
|
|
|
$content .= sprintf(<<<EOF
|
|
|
|
|
<h2 class="block_exception clear_fix">
|
|
|
|
|
<span class="exception_counter">%d/%d</span>
|
|
|
|
|
@@ -251,7 +262,7 @@ EOF
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
// something nasty happened and we cannot throw an exception anymore
|
|
|
|
|
if ($this->debug) {
|
|
|
|
|
$title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $e->getMessage());
|
|
|
|
|
$title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $this->escapeHtml($e->getMessage()));
|
|
|
|
|
} else {
|
|
|
|
|
$title = 'Whoops, looks like something went wrong.';
|
|
|
|
|
}
|
|
|
|
|
@@ -337,7 +348,7 @@ EOF;
|
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<meta charset="UTF-8" />
|
|
|
|
|
<meta charset="{$this->charset}" />
|
|
|
|
|
<meta name="robots" content="noindex,nofollow" />
|
|
|
|
|
<style>
|
|
|
|
|
/* Copyright (c) 2010, Yahoo! Inc. All rights reserved. Code licensed under the BSD License: http://developer.yahoo.com/yui/license.html */
|
|
|
|
|
@@ -365,7 +376,7 @@ EOF;
|
|
|
|
|
|
|
|
|
|
private function formatPath($path, $line)
|
|
|
|
|
{
|
|
|
|
|
$path = self::utf8Htmlize($path);
|
|
|
|
|
$path = $this->escapeHtml($path);
|
|
|
|
|
$file = preg_match('#[^/\\\\]*$#', $path, $file) ? $file[0] : $path;
|
|
|
|
|
|
|
|
|
|
if ($linkFormat = $this->fileLinkFormat) {
|
|
|
|
|
@@ -389,11 +400,11 @@ EOF;
|
|
|
|
|
$result = array();
|
|
|
|
|
foreach ($args as $key => $item) {
|
|
|
|
|
if ('object' === $item[0]) {
|
|
|
|
|
$formattedValue = sprintf("<em>object</em>(%s)", $this->formatClass($item[1]));
|
|
|
|
|
$formattedValue = sprintf('<em>object</em>(%s)', $this->formatClass($item[1]));
|
|
|
|
|
} elseif ('array' === $item[0]) {
|
|
|
|
|
$formattedValue = sprintf("<em>array</em>(%s)", is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
|
|
|
|
|
$formattedValue = sprintf('<em>array</em>(%s)', is_array($item[1]) ? $this->formatArgs($item[1]) : $item[1]);
|
|
|
|
|
} elseif ('string' === $item[0]) {
|
|
|
|
|
$formattedValue = sprintf("'%s'", self::utf8Htmlize($item[1]));
|
|
|
|
|
$formattedValue = sprintf("'%s'", $this->escapeHtml($item[1]));
|
|
|
|
|
} elseif ('null' === $item[0]) {
|
|
|
|
|
$formattedValue = '<em>null</em>';
|
|
|
|
|
} elseif ('boolean' === $item[0]) {
|
|
|
|
|
@@ -401,7 +412,7 @@ EOF;
|
|
|
|
|
} elseif ('resource' === $item[0]) {
|
|
|
|
|
$formattedValue = '<em>resource</em>';
|
|
|
|
|
} else {
|
|
|
|
|
$formattedValue = str_replace("\n", '', var_export(self::utf8Htmlize((string) $item[1]), true));
|
|
|
|
|
$formattedValue = str_replace("\n", '', var_export($this->escapeHtml((string) $item[1]), true));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$result[] = is_int($key) ? $formattedValue : sprintf("'%s' => %s", $key, $formattedValue);
|
|
|
|
|
@@ -429,6 +440,14 @@ EOF;
|
|
|
|
|
return htmlspecialchars($str, ENT_QUOTES | (PHP_VERSION_ID >= 50400 ? ENT_SUBSTITUTE : 0), 'UTF-8');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* HTML-encodes a string
|
|
|
|
|
*/
|
|
|
|
|
private function escapeHtml($str)
|
|
|
|
|
{
|
|
|
|
|
return htmlspecialchars($str, ENT_QUOTES | (PHP_VERSION_ID >= 50400 ? ENT_SUBSTITUTE : 0), $this->charset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @internal
|
|
|
|
|
*/
|
|
|
|
|
|