useMessageCache() && !empty( $GLOBALS['wgFullyInitialised'] ) && !empty( $GLOBALS['wgOut'] ) && !defined( 'MEDIAWIKI_INSTALL' ) && // Don't send a skinned HTTP 500 page to API clients. !defined( 'MW_API' ); } /** * Whether to log this exception in the exception debug log. * * @stable to override * * @since 1.23 * @return bool */ public function isLoggable() { return true; } /** * Can the extension use the Message class/wfMessage to get i18n-ed messages? * * @stable to override * * @return bool */ public function useMessageCache() { foreach ( $this->getTrace() as $frame ) { if ( isset( $frame['class'] ) && $frame['class'] === LocalisationCache::class ) { return false; } } return true; } /** * Get a message from i18n * * @param string $key Message name * @param string $fallback Default message if the message cache can't be * called by the exception * @param mixed ...$params To pass to wfMessage() * @return string Message with arguments replaced */ public function msg( $key, $fallback, ...$params ) { // NOTE: Keep logic in sync with MWExceptionRenderer::msg. $res = false; if ( $this->useMessageCache() ) { try { $res = wfMessage( $key, ...$params )->text(); } catch ( Exception $e ) { } } if ( $res === false ) { // Fallback to static message text and generic sitename. // Avoid live config as this must work before Setup/MediaWikiServices finish. $res = wfMsgReplaceArgs( $fallback, $params ); $res = strtr( $res, [ '{{SITENAME}}' => 'MediaWiki', ] ); } return $res; } /** * Format an HTML message for the current exception object. * * * @stable to override * @todo Rarely used, remove in favour of generic MWExceptionRenderer * @return string HTML to output */ public function getHTML() { if ( MWExceptionRenderer::shouldShowExceptionDetails() ) { return '
' . nl2br( htmlspecialchars( MWExceptionHandler::getLogMessage( $this ) ) ) . '
Backtrace:
' . nl2br( htmlspecialchars( MWExceptionHandler::getRedactedTraceAsString( $this ) ) ) . "
\n"; } else { $logId = WebRequest::getRequestId(); $type = static::class; return Html::errorBox( htmlspecialchars( '[' . $logId . '] ' . gmdate( 'Y-m-d H:i:s' ) . ": " . $this->msg( "internalerror-fatal-exception", "Fatal exception of type $1", $type, $logId, MWExceptionHandler::getURL() ) ) ) . ""; } } /** * Format plain text message for the current exception object. * * @stable to override * @todo Rarely used, remove in favour of generic MWExceptionRenderer * @return string */ public function getText() { if ( MWExceptionRenderer::shouldShowExceptionDetails() ) { return MWExceptionHandler::getLogMessage( $this ) . "\nBacktrace:\n" . MWExceptionHandler::getRedactedTraceAsString( $this ) . "\n"; } else { return "Set \$wgShowExceptionDetails = true; " . "in LocalSettings.php to show detailed debugging information.\n"; } } /** * Return the title of the page when reporting this error in a HTTP response. * * @stable to override * * @return string */ public function getPageTitle() { return $this->msg( 'internalerror', 'Internal error' ); } /** * Output the exception report using HTML. * @stable to override */ public function reportHTML() { global $wgOut; if ( $this->useOutputPage() ) { $wgOut->prepareErrorPage( $this->getPageTitle() ); // Manually set the html title, since sometimes // {{SITENAME}} does not get replaced for exceptions // happening inside message rendering. $wgOut->setHTMLTitle( $this->msg( 'pagetitle', '$1 - MediaWiki', $this->getPageTitle() ) ); $wgOut->addHTML( $this->getHTML() ); // Content-Type is set by OutputPage::output $wgOut->output(); } else { self::header( 'Content-Type: text/html; charset=UTF-8' ); echo "\n" . '' . // Mimic OutputPage::setPageTitle behaviour '