* @package WoltLabSuite\Core */ 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']); spl_autoload_register(function ($className) { /** * @deprecated 5.3 This file is a compatibility layer mapping from Leafo\\ to ScssPhp\\ */ $leafo = 'Leafo\\'; if (substr($className, 0, strlen($leafo)) === $leafo) { class_alias('ScssPhp\\'.substr($className, strlen($leafo)), $className, true); } }); /** * Escapes a string for use in sql query. * * @see \wcf\system\database\Database::escapeString() * @param string $string * @return string */ function escapeString($string) { return WCF::getDB()->escapeString($string); } /** * Helper method to output debug data for all passed variables, * uses `print_r()` for arrays and objects, `var_dump()` otherwise. */ function wcfDebug() { echo "
";
		
		$args = func_get_args();
		$length = count($args);
		if ($length === 0) {
			echo "ERROR: No arguments provided.
"; } else { for ($i = 0; $i < $length; $i++) { $arg = $args[$i]; echo "

Argument {$i} (" . gettype($arg) . ")

"; if (is_array($arg) || is_object($arg)) { print_r($arg); } else { var_dump($arg); } echo "
"; } } $backtrace = debug_backtrace(); // output call location to help finding these debug outputs again echo "wcfDebug() called in {$backtrace[0]['file']} on line {$backtrace[0]['line']}"; echo "
"; exit; } // 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']; } } } // setting global gzip compression breaks output buffering if (@ini_get('zlib.output_compression')) { @ini_set('zlib.output_compression', '0'); } if (!function_exists('is_countable')) { function is_countable($var) { return is_array($var) || $var instanceof Countable || $var instanceof ResourceBundle || $var instanceof SimpleXmlElement; } } } // @codingStandardsIgnoreStart namespace wcf { function getRequestId() { if (!defined('WCF_REQUEST_ID_HEADER') || !WCF_REQUEST_ID_HEADER) return ''; return $_SERVER[WCF_REQUEST_ID_HEADER] ?? ''; } function getMinorVersion() { return preg_replace('/^(\d+\.\d+)\..*$/', '\\1', WCF_VERSION); } } namespace wcf\functions\exception { use wcf\system\WCF; use wcf\system\exception\IExtraInformationException; use wcf\system\exception\SystemException; use wcf\util\FileUtil; use wcf\util\StringUtil; /** * Logs the given Throwable. * * @param \Throwable|\Exception $e * @param string $logFile The log file to use. If set to `null` the default log file will be used and the variable contents will be replaced by the actual path. * @return string The ID of the log entry. */ function logThrowable($e, &$logFile = null) { if ($logFile === null) $logFile = WCF_DIR . 'log/' . gmdate('Y-m-d', TIME_NOW) . '.txt'; touch($logFile); $stripNewlines = function ($item) { return str_replace("\n", ' ', $item); }; // don't forget to update ExceptionLogUtil / ExceptionLogViewPage, when changing the log file format $message = gmdate('r', TIME_NOW)."\n". 'Message: '.$stripNewlines($e->getMessage())."\n". 'PHP version: '.phpversion()."\n". 'WoltLab Suite version: '.WCF_VERSION."\n". 'Request URI: '.$stripNewlines(($_SERVER['REQUEST_METHOD'] ?? '').' '.($_SERVER['REQUEST_URI'] ?? '')).(\wcf\getRequestId() ? ' ('.\wcf\getRequestId().')' : '')."\n". 'Referrer: '.$stripNewlines($_SERVER['HTTP_REFERER'] ?? '')."\n". 'User Agent: '.$stripNewlines($_SERVER['HTTP_USER_AGENT'] ?? '')."\n". 'Peak Memory Usage: '.memory_get_peak_usage().'/'.FileUtil::getMemoryLimit()."\n"; $prev = $e; do { $message .= "======\n". 'Error Class: '.get_class($prev)."\n". 'Error Message: '.$stripNewlines($prev->getMessage())."\n". 'Error Code: '.$stripNewlines($prev->getCode())."\n". 'File: '.$stripNewlines($prev->getFile()).' ('.$prev->getLine().')'."\n". 'Extra Information: '.($prev instanceof IExtraInformationException ? base64_encode(serialize($prev->getExtraInformation())) : '-')."\n". 'Stack Trace: '.json_encode(array_map(function ($item) { $item['args'] = array_map(function ($item) { switch (gettype($item)) { case 'object': return get_class($item); case 'array': return array_map(function () { return '[redacted]'; }, $item); case 'resource': return 'resource('.get_resource_type($item).')'; default: return $item; } }, $item['args']); return $item; }, sanitizeStacktrace($prev, true)))."\n"; } while ($prev = $prev->getPrevious()); // calculate Exception-ID $exceptionID = sha1($message); $entry = "<<<<<<<<".$exceptionID."<<<<\n".$message."<<<<\n\n"; file_put_contents($logFile, $entry, FILE_APPEND); // let the Exception know it has been logged if (method_exists($e, 'finalizeLog') && is_callable([$e, 'finalizeLog'])) $e->finalizeLog($exceptionID, $logFile); return $exceptionID; } /** * Pretty prints the given Throwable. It is recommended to `exit;` * the request after calling this function. * * @param \Throwable|\Exception $e * @throws \Exception */ function printThrowable($e) { $exceptionID = logThrowable($e, $logFile); if (\wcf\getRequestId()) $exceptionID .= '/'.\wcf\getRequestId(); $exceptionTitle = $exceptionSubtitle = $exceptionExplanation = ''; $logFile = sanitizePath($logFile); try { if (WCF::getLanguage() !== null) { $exceptionTitle = WCF::getLanguage()->get('wcf.global.exception.title', true); $exceptionSubtitle = str_replace('{$exceptionID}', $exceptionID, WCF::getLanguage()->get('wcf.global.exception.subtitle', true)); $exceptionExplanation = str_replace('{$logFile}', $logFile, WCF::getLanguage()->get('wcf.global.exception.explanation', true)); } } catch (\Throwable $e) { // ignore } if (!$exceptionTitle || !$exceptionSubtitle || !$exceptionExplanation) { // one or more failed, fallback to english $exceptionTitle = 'An error has occurred'; $exceptionSubtitle = 'Internal error code: '.$exceptionID.''; $exceptionExplanation = <<What happened?

An error has occured while trying to handle your request and execution has been terminated. Please forward the above error code to the site administrator.

 

The error code can be used by an administrator to lookup the full error message in the Administration Control Panel via “Logs » Errors”. In addition the error has been written to the log file located at {$logFile} and can be accessed with a FTP program or similar.

 

Notice: The error code was randomly generated and has no use beyond looking up the full message.

EXPLANATION; } /* * A notice on the HTML used below: * * It might appear a bit weird to use

all over the place where semantically * other elements would fit in way better. The reason behind this is that we avoid * inheriting unwanted styles (e.g. exception displayed in an overlay) and that * the output needs to be properly readable when copied & pasted somewhere. * * Besides the visual appearance, the output was built to provide a maximum of * compatibility and readability when pasted somewhere else, e.g. a WYSIWYG editor * without the potential of messing up the formatting and thus harming the readability. */ ?> Fatal Error: <?php echo StringUtil::encodeHTML($e->getMessage()); ?> Fatal Error

System Information

  • PHP Version:

  • WoltLab Suite Core:

  • Peak Memory Usage:

    / MiB

  • Request URI:

  • Referrer:

  • User Agent:

getPrevious()); $e = array_pop($exceptions); do { ?>

Error

getDescription()) { ?>

getDescription(); ?>

  • Error Type:

  • Error Message:

    getMessage()); ?>

  • getCode()) { ?>
  • 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."); } } if ($e instanceof IExtraInformationException) { foreach ($e->getExtraInformation() as list($key, $value)) { ?>
  • :

  • Stack Trace:

    • 5) return "[ ".count($keys)." items ]"; return '[ '.implode(', ', array_map(function ($item) { return $item.' => '; }, $keys)).']'; case 'object': return get_class($item); case 'resource': return 'resource('.get_resource_type($item).')'; case 'resource (closed)': return 'resource (closed)'; } throw new \LogicException('Unreachable'); }, $trace[$i]['args'])); echo ')
    • '; } ?>
getTrace(); return array_map(function ($item) use ($ignorePaths) { if (!isset($item['file'])) $item['file'] = '[internal function]'; if (!isset($item['line'])) $item['line'] = '?'; if (!isset($item['class'])) $item['class'] = ''; if (!isset($item['type'])) $item['type'] = ''; if (!isset($item['args'])) $item['args'] = []; // strip database credentials 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 (!is_string($item)) return $item; if (preg_match('~^('.preg_quote($_SERVER['DOCUMENT_ROOT'], '~').'|'.preg_quote(WCF_DIR, '~').')~', $item)) { $item = sanitizePath($item); } return $item; }, $item['args']); $item['file'] = sanitizePath($item['file']); } return $item; }, $trace); } /** * Returns the given path relative to `WCF_DIR`, unless both, * `EXCEPTION_PRIVACY` is `public` and the debug mode is enabled. * * @param string $path * @return string */ function sanitizePath($path) { if (WCF::debugModeIsEnabled() && defined('EXCEPTION_PRIVACY') && EXCEPTION_PRIVACY === 'public') { return $path; } return '*/'.FileUtil::removeTrailingSlash(FileUtil::getRelativePath(WCF_DIR, $path)); } } // @codingStandardsIgnoreEnd