/** * Look for a fatal error as the cause of the request termination and log * as an exception. * * Special handling is included for missing class errors as they may * indicate that the user needs to install 3rd-party libraries via * Composer or other means. * * @since 1.25 */ public static function handleFatalError() { self::$reservedMemory = null; $lastError = error_get_last(); if ($lastError && isset($lastError['type']) && in_array($lastError['type'], self::$fatalErrorTypes)) { $msg = "Fatal Error: {$lastError['message']}"; // HHVM: Class undefined: foo // PHP5: Class 'foo' not found if (preg_match("/Class (undefined: \\w+|'\\w+' not found)/", $lastError['message'])) { // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong $msg = <<<TXT {$msg} MediaWiki or an installed extension requires this class but it is not embedded directly in MediaWiki's git repository and must be installed separately by the end user. Please see <a href="https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a> for help on installing the required components. TXT; // @codingStandardsIgnoreEnd } $e = new ErrorException($msg, 0, $lastError['type']); self::logError($e, 'fatal'); } }
/** * Dual purpose callback used as both a set_error_handler() callback and * a registered shutdown function. Receive a callback from the interpreter * for a raised error or system shutdown, check for a fatal error, and log * to the 'fatal' logging channel. * * Special handling is included for missing class errors as they may * indicate that the user needs to install 3rd-party libraries via * Composer or other means. * * @since 1.25 * * @param int $level Error level raised * @param string $message Error message * @param string $file File that error was raised in * @param int $line Line number error was raised at * @param array $context Active symbol table point of error * @param array $trace Backtrace at point of error (undocumented HHVM * feature) * @return bool Always returns false */ public static function handleFatalError($level = null, $message = null, $file = null, $line = null, $context = null, $trace = null) { // Free reserved memory so that we have space to process OOM // errors self::$reservedMemory = null; if ($level === null) { // Called as a shutdown handler, get data from error_get_last() if (static::$handledFatalCallback) { // Already called once (probably as an error handler callback // under HHVM) so don't log again. return false; } $lastError = error_get_last(); if ($lastError !== null) { $level = $lastError['type']; $message = $lastError['message']; $file = $lastError['file']; $line = $lastError['line']; } else { $level = 0; $message = ''; } } if (!in_array($level, self::$fatalErrorTypes)) { // Only interested in fatal errors, others should have been // handled by MWExceptionHandler::handleError return false; } $msg = "[{exception_id}] PHP Fatal Error: {$message}"; // Look at message to see if this is a class not found failure // HHVM: Class undefined: foo // PHP5: Class 'foo' not found if (preg_match("/Class (undefined: \\w+|'\\w+' not found)/", $msg)) { // @codingStandardsIgnoreStart Generic.Files.LineLength.TooLong $msg = <<<TXT {$msg} MediaWiki or an installed extension requires this class but it is not embedded directly in MediaWiki's git repository and must be installed separately by the end user. Please see <a href="https://www.mediawiki.org/wiki/Download_from_Git#Fetch_external_libraries">mediawiki.org</a> for help on installing the required components. TXT; // @codingStandardsIgnoreEnd } // We can't just create an exception and log it as it is likely that // the interpreter has unwound the stack already. If that is true the // stacktrace we would get would be functionally empty. If however we // have been called as an error handler callback *and* HHVM is in use // we will have been provided with a useful stacktrace that we can // log. $trace = $trace ?: debug_backtrace(); $logger = LoggerFactory::getInstance('fatal'); $logger->error($msg, ['exception' => ['class' => 'ErrorException', 'message' => "PHP Fatal Error: {$message}", 'code' => $level, 'file' => $file, 'line' => $line, 'trace' => static::redactTrace($trace)], 'exception_id' => wfRandomString(8)]); // Remember call so we don't double process via HHVM's fatal // notifications and the shutdown hook behavior static::$handledFatalCallback = true; return false; }