From 5bc5a7e6a29822141b51eb35045b3d190f81ab05 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 28 Sep 2015 17:13:06 +0200 Subject: [PATCH] Improve Exception / Error printing --- wcfsetup/install/files/lib/core.functions.php | 289 ++++++++++++++++-- .../install/files/lib/system/WCF.class.php | 39 ++- .../exception/SystemException.class.php | 131 +------- 3 files changed, 288 insertions(+), 171 deletions(-) diff --git a/wcfsetup/install/files/lib/core.functions.php b/wcfsetup/install/files/lib/core.functions.php index 8bd22db7ac..35b2121c3c 100644 --- a/wcfsetup/install/files/lib/core.functions.php +++ b/wcfsetup/install/files/lib/core.functions.php @@ -6,35 +6,272 @@ * @package com.woltlab.wcf * @category Community Framework */ -use wcf\system\WCF; - -// set exception handler -set_exception_handler([ WCF::class, 'handleException' ]); -// set php error handler -set_error_handler([ WCF::class, 'handleError' ], E_ALL); -// set shutdown function -register_shutdown_function([ WCF::class, 'destruct' ]); -// set autoload function -spl_autoload_register([ WCF::class, 'autoload' ]); - -// define escape string shortcut -function escapeString($string) { - return WCF::getDB()->escapeString($string); +namespace { + use wcf\system\WCF; + + // set exception handler + set_exception_handler([ WCF::class, 'handleException' ]); + // set php error handler + set_error_handler([ WCF::class, 'handleError' ], E_ALL); + // set shutdown function + register_shutdown_function([ WCF::class, 'destruct' ]); + // set autoload function + spl_autoload_register([ WCF::class, 'autoload' ]); + + // define escape string shortcut + function escapeString($string) { + return WCF::getDB()->escapeString($string); + } + + // define DOCUMENT_ROOT on IIS if not set + if (PHP_EOL == "\r\n") { + if (!isset($_SERVER['DOCUMENT_ROOT']) && isset($_SERVER['SCRIPT_FILENAME'])) { + $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0 - strlen($_SERVER['PHP_SELF']))); + } + if (!isset($_SERVER['DOCUMENT_ROOT']) && isset($_SERVER['PATH_TRANSLATED'])) { + $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr(str_replace('\\\\', '\\', $_SERVER['PATH_TRANSLATED']), 0, 0 - strlen($_SERVER['PHP_SELF']))); + } + + if (!isset($_SERVER['REQUEST_URI'])) { + $_SERVER['REQUEST_URI'] = substr($_SERVER['PHP_SELF'], 1); + if (isset($_SERVER['QUERY_STRING'])) { + $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING']; + } + } + } } -// define DOCUMENT_ROOT on IIS if not set -if (PHP_EOL == "\r\n") { - if (!isset($_SERVER['DOCUMENT_ROOT']) && isset($_SERVER['SCRIPT_FILENAME'])) { - $_SERVER['DOCUMENT_ROOT'] = str_replace( '\\', '/', substr($_SERVER['SCRIPT_FILENAME'], 0, 0 - strlen($_SERVER['PHP_SELF']))); +namespace wcf\functions\exception { + use wcf\system\exception\SystemException; + use wcf\system\WCF; + use wcf\util\FileUtil; + use wcf\util\StringUtil; + + function printThrowable($e) { + $exceptionID = '123456'; // TODO + ?> + + + + Fatal Error: <?php echo StringUtil::encodeHTML($e->getMessage()); ?> + + Fatal Error + + + + + +
+ +

Fatal Error: getMessage()); ?>

+ +

Fatal Error

+ +
+

What happened?

+

An unrecoverable error occured while trying to handle your request. The internal error code is as follows:

+

Please send this code to the administrator to help him fix the issue.

+
+ +
+

System Information:

+
+
PHP Version:
+
WCF Version:
+
Date:
+
Request URI:
+
Referrer:
+
User Agent:
+
Peak Memory Usage:
/ Byte (/ MiB)
+
+
+ +
+

getPrevious() && !$first) { echo "Original "; } else if ($e->getPrevious() && $first) { echo "Final "; } ?>Error:

+ getDescription()) { ?> +

getDescription(); ?>

+ +
+
Error Class:
+
Error Message:
getMessage()); ?>
+
Error Code:
getCode()); ?>
+
File:
getFile())); ?> (getLine(); ?>)
+ show(); + ob_end_clean(); + + $reflection = new \ReflectionClass($e); + $property = $reflection->getProperty('information'); + $property->setAccessible(true); + if ($property->getValue($e)) { + throw new \Exception("Using the 'information' property of SystemException is not supported any more."); + } + } + ?> +
Stack Trace:
+
"'.StringUtil::encodeHTML(addcslashes(StringUtil::truncate($item, 25, StringUtil::HELLIP, true), "\n")).'"'; + case 'boolean': + return $item ? 'true' : 'false'; + case 'array': + $keys = array_keys($item); + if (count($keys) > 5) return "[ ".StringUtil::HELLIP." ]"; + return '[ '.implode(', ', array_map(function ($item) { + return $item.' => '; + }, $keys)).']'; + case 'object': + return get_class($item); + } + }, $trace[$i]['args'])); + echo ")\n"; + } + ?>
+
+
+ getPrevious()); + ?> + +
+ + + getTrace(); + + return array_map(function ($item) use ($ignorePaths) { + // strip database credentials + if (isset($item['class'])) { + if (preg_match('~\\\\?wcf\\\\system\\\\database\\\\[a-zA-Z]*Database~', $item['class']) || $item['class'] === 'PDO') { + if ($item['function'] === '__construct') { + $item['args'] = array_map(function () { + return '[redacted]'; + }, $item['args']); + } + } + } + + if (!$ignorePaths) { + $item['args'] = array_map(function ($item) { + if (preg_match('~^'.preg_quote($_SERVER['DOCUMENT_ROOT'], '~').'~', $item)) { + $item = sanitizePath($item); + } + + return preg_replace('~^'.preg_quote(WCF_DIR, '~').'~', '*/', $item); + }, $item['args']); + + if (isset($item['file'])) $item['file'] = sanitizePath($item['file']); + } + + return $item; + }, $trace); } - - if (!isset($_SERVER['REQUEST_URI'])) { - $_SERVER['REQUEST_URI'] = substr($_SERVER['PHP_SELF'], 1); - if (isset($_SERVER['QUERY_STRING'])) { - $_SERVER['REQUEST_URI'] .= '?' . $_SERVER['QUERY_STRING']; - } + + function sanitizePath($path) { + return '*/'.FileUtil::removeTrailingSlash(FileUtil::getRelativePath(WCF_DIR, $path)); } } diff --git a/wcfsetup/install/files/lib/system/WCF.class.php b/wcfsetup/install/files/lib/system/WCF.class.php index 92be155773..863a0e91b0 100644 --- a/wcfsetup/install/files/lib/system/WCF.class.php +++ b/wcfsetup/install/files/lib/system/WCF.class.php @@ -233,22 +233,31 @@ class WCF { * @param \Exception $e */ public static final function handleException($e) { - try { - if (!($e instanceof \Exception)) throw $e; - - if ($e instanceof IPrintableException) { - $e->show(); - exit; - } - - // repack Exception - self::handleException(new SystemException($e->getMessage(), $e->getCode(), '', $e)); + // backwards compatibility + if ($e instanceof IPrintableException) { + $e->show(); + exit; } - catch (\Throwable $exception) { - die("
WCF::handleException() Unhandled exception: ".$exception->getMessage()."\n\n".$exception->getTraceAsString());
-		}
-		catch (\Exception $exception) {
-			die("
WCF::handleException() Unhandled exception: ".$exception->getMessage()."\n\n".$exception->getTraceAsString());
+		
+		@header('HTTP/1.1 503 Service Unavailable');
+		try {
+			\wcf\functions\exception\printThrowable($e);
+		}
+		catch (\Throwable $e2) {
+			echo "
An Exception was thrown while handling an Exception:\n\n";
+			echo $e2;
+			echo "\n\nwas thrown while:\n\n";
+			echo $e;
+			echo "\n\nwas handled.
"; + exit; + } + catch (\Exception $e2) { + echo "
An Exception was thrown while handling an Exception:\n\n";
+			echo $e2;
+			echo "\n\nwas thrown while:\n\n";
+			echo $e;
+			echo "\n\nwas handled.
"; + exit; } } diff --git a/wcfsetup/install/files/lib/system/exception/SystemException.class.php b/wcfsetup/install/files/lib/system/exception/SystemException.class.php index e4b664fab4..ef1e4458b9 100644 --- a/wcfsetup/install/files/lib/system/exception/SystemException.class.php +++ b/wcfsetup/install/files/lib/system/exception/SystemException.class.php @@ -14,8 +14,7 @@ use wcf\util\StringUtil; * @subpackage system.exception * @category Community Framework */ -// @codingStandardsIgnoreFile -class SystemException extends LoggedException implements IPrintableException { +class SystemException extends LoggedException { /** * error description * @var string @@ -60,134 +59,6 @@ class SystemException extends LoggedException implements IPrintableException { * @see \wcf\system\exception\IPrintableException::show() */ public function show() { - // send status code - @header('HTTP/1.1 503 Service Unavailable'); - // show user-defined system-exception - if (defined('SYSTEMEXCEPTION_FILE') && file_exists(SYSTEMEXCEPTION_FILE)) { - require(SYSTEMEXCEPTION_FILE); - return; - } - - $innerMessage = ''; - try { - if (is_object(WCF::getLanguage())) { - $innerMessage = WCF::getLanguage()->get('wcf.global.error.exception', true); - } - } - catch (\Exception $e) { } - - if (empty($innerMessage)) { - $innerMessage = 'Please send the ID above to the site administrator.
The error message can be looked up at “ACP » Logs » Errors”.'; - } - - // print report - $e = ($this->getPrevious() ?: $this); - ?> - - - Fatal error: <?php echo StringUtil::encodeHTML($this->_getMessage()); ?> - - - - -
-

Fatal error: getExceptionID()) { ?>Unable to write log file, please make "log/" writable!_getMessage()); } ?>

- - -
- getDescription()) { ?>


getDescription(); ?>

- -

Information:

-

- id: getExceptionID(); ?>
- error message: _getMessage()); ?>
- error code: getCode()); ?>
- information; ?> - file: getFile()); ?> (getLine(); ?>)
- php version:
- wcf version:
- date:
- request:
- referer:
-

- -

Stacktrace:

-
__getTraceAsString()); ?>
-
- -
-

Information:

-

- getExceptionID()) { ?> - Unable to write log file, please make "log/" writable! - - ID: getExceptionID(); ?>
- - -

-
- - - functions; ?> -
- - - -