* @ingroup Exception
*/
class MWException extends Exception {
+ var $logId;
+
/**
* Should the exception use $wgOut to output the error ?
* @return bool
global $wgExceptionHooks;
if ( !isset( $wgExceptionHooks ) || !is_array( $wgExceptionHooks ) ) {
- return; // Just silently ignore
+ return null; // Just silently ignore
}
if ( !array_key_exists( $name, $wgExceptionHooks ) || !is_array( $wgExceptionHooks[ $name ] ) ) {
- return;
+ return null;
}
$hooks = $wgExceptionHooks[ $name ];
$result = null;
}
- if ( is_string( $result ) )
+ if ( is_string( $result ) ) {
return $result;
+ }
}
+ return null;
}
/**
'</p><p>Backtrace:</p><p>' . nl2br( htmlspecialchars( $this->getTraceAsString() ) ) .
"</p>\n";
} else {
- return "<p>Set <b><tt>\$wgShowExceptionDetails = true;</tt></b> " .
+ return
+ "<div class=\"errorbox\">" .
+ '[' . $this->getLogId() . '] ' .
+ gmdate( 'Y-m-d H:i:s' ) .
+ ": Fatal exception of type " . get_class( $this ) . "</div>\n" .
+ "<!-- Set \$wgShowExceptionDetails = true; " .
"at the bottom of LocalSettings.php to show detailed " .
- "debugging information.</p>";
+ "debugging information. -->";
}
}
/**
* If $wgShowExceptionDetails is true, return a text message with a
* backtrace to the error.
+ * @return string
*/
function getText() {
global $wgShowExceptionDetails;
}
}
- /* Return titles of this error page */
+ /**
+ * Return titles of this error page
+ * @return String
+ */
function getPageTitle() {
- global $wgSitename;
- return $this->msg( 'internalerror', "$wgSitename error" );
+ return $this->msg( 'internalerror', "Internal error" );
+ }
+
+ function getLogId() {
+ if ( $this->logId === null ) {
+ $this->logId = wfRandomString( 8 );
+ }
+ return $this->logId;
}
/**
function getLogMessage() {
global $wgRequest;
+ $id = $this->getLogId();
$file = $this->getFile();
$line = $this->getLine();
$message = $this->getMessage();
- if ( isset( $wgRequest ) ) {
+ if ( isset( $wgRequest ) && !$wgRequest instanceof FauxRequest ) {
$url = $wgRequest->getRequestURL();
if ( !$url ) {
$url = '[no URL]';
$url = '[no req]';
}
- return "$url Exception from line $line of $file: $message";
+ return "[$id] $url Exception from line $line of $file: $message";
}
/** Output the exception report using HTML */
function reportHTML() {
global $wgOut;
if ( $this->useOutputPage() ) {
- $wgOut->setPageTitle( $this->getPageTitle() );
- $wgOut->setRobotPolicy( "noindex,nofollow" );
- $wgOut->setArticleRelated( false );
- $wgOut->enableClientCache( false );
- $wgOut->redirect( '' );
- $wgOut->clearHTML();
+ $wgOut->prepareErrorPage( $this->getPageTitle() );
$hookResult = $this->runHooks( get_class( $this ) );
if ( $hookResult ) {
$wgOut->output();
} else {
+ header( "Content-Type: text/html; charset=utf-8" );
$hookResult = $this->runHooks( get_class( $this ) . "Raw" );
if ( $hookResult ) {
die( $hookResult );
* It will be either HTML or plain text based on isCommandLine().
*/
function report() {
+ global $wgLogExceptionBacktrace;
$log = $this->getLogMessage();
if ( $log ) {
- wfDebugLog( 'exception', $log );
+ if ( $wgLogExceptionBacktrace ) {
+ wfDebugLog( 'exception', $log . "\n" . $this->getTraceAsString() . "\n" );
+ } else {
+ wfDebugLog( 'exception', $log );
+ }
}
- if ( self::isCommandLine() ) {
+ if ( defined( 'MW_API' ) ) {
+ // Unhandled API exception, we can't be sure that format printer is alive
+ header( 'MediaWiki-API-Error: internal_api_error_' . get_class( $this ) );
+ wfHttpError(500, 'Internal Server Error', $this->getText() );
+ } elseif ( self::isCommandLine() ) {
MWExceptionHandler::printError( $this->getText() );
} else {
$this->reportHTML();
}
}
+ /**
+ * @static
+ * @return bool
+ */
static function isCommandLine() {
return !empty( $GLOBALS['wgCommandLineMode'] );
}
* @ingroup Exception
*/
class FatalError extends MWException {
+
+ /**
+ * @return string
+ */
function getHTML() {
return $this->getMessage();
}
+ /**
+ * @return string
+ */
function getText() {
return $this->getMessage();
}
function report() {
global $wgOut;
- if ( $wgOut->getTitle() ) {
- $wgOut->debug( 'Original title: ' . $wgOut->getTitle()->getPrefixedText() . "\n" );
- }
- $wgOut->setPageTitle( wfMsg( $this->title ) );
- $wgOut->setHTMLTitle( wfMsg( 'errorpagetitle' ) );
- $wgOut->setRobotPolicy( 'noindex,nofollow' );
- $wgOut->setArticleRelated( false );
- $wgOut->enableClientCache( false );
- $wgOut->mRedirect = '';
- $wgOut->clearHTML();
-
- if( $this->msg instanceof Message ){
- $wgOut->addHTML( $this->msg->parse() );
- } else {
- $wgOut->addWikiMsgArray( $this->msg, $this->params );
- }
-
- $wgOut->returnToMain();
+ $wgOut->showErrorPage( $this->title, $this->msg, $this->params );
$wgOut->output();
}
}
+/**
+ * Show an error page on a badtitle.
+ * Similar to ErrorPage, but emit a 400 HTTP error code to let mobile
+ * browser it is not really a valid content.
+ */
+class BadTitleError extends ErrorPageError {
+
+ /**
+ * @param $msg string A message key (default: 'badtitletext')
+ * @param $params Array parameter to wfMsg()
+ */
+ function __construct( $msg = 'badtitletext', $params = null ) {
+ parent::__construct( 'badtitle', $msg, $params );
+ }
+
+ /**
+ * Just like ErrorPageError::report() but additionally set
+ * a 400 HTTP status code (bug 33646).
+ */
+ function report() {
+ global $wgOut;
+
+ // bug 33646: a badtitle error page need to return an error code
+ // to let mobile browser now that it is not a normal page.
+ $wgOut->setStatusCode( 400 );
+ parent::report();
+ }
+
+}
+
/**
* Show an error when a user tries to do something they do not have the necessary
* permissions for.
* @ingroup Exception
*/
class PermissionsError extends ErrorPageError {
- public $permission;
+ public $permission, $errors;
- function __construct( $permission ) {
+ function __construct( $permission, $errors = array() ) {
global $wgLang;
$this->permission = $permission;
- $groups = array_map(
- array( 'User', 'makeGroupLinkWiki' ),
- User::getGroupsWithPermission( $this->permission )
- );
-
- if( $groups ) {
- parent::__construct(
- 'badaccess',
- 'badaccess-groups',
- array(
- $wgLang->commaList( $groups ),
- count( $groups )
- )
- );
- } else {
- parent::__construct(
- 'badaccess',
- 'badaccess-group0'
+ if ( !count( $errors ) ) {
+ $groups = array_map(
+ array( 'User', 'makeGroupLinkWiki' ),
+ User::getGroupsWithPermission( $this->permission )
);
+
+ if ( $groups ) {
+ $errors[] = array( 'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
+ } else {
+ $errors[] = array( 'badaccess-group0' );
+ }
}
+
+ $this->errors = $errors;
+ }
+
+ function report() {
+ global $wgOut;
+
+ $wgOut->showPermissionsErrorPage( $this->errors, $this->permission );
+ $wgOut->output();
}
}
'actionthrottledtext'
);
}
+
public function report(){
global $wgOut;
$wgOut->setStatusCode( 503 );
- return parent::report();
+ parent::report();
}
}
*/
class UserBlockedError extends ErrorPageError {
public function __construct( Block $block ){
- global $wgLang;
-
- $blockerUserpage = $block->getBlocker()->getUserPage();
- $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
+ global $wgLang, $wgRequest;
+
+ $blocker = $block->getBlocker();
+ if ( $blocker instanceof User ) { // local user
+ $blockerUserpage = $block->getBlocker()->getUserPage();
+ $link = "[[{$blockerUserpage->getPrefixedText()}|{$blockerUserpage->getText()}]]";
+ } else { // foreign user
+ $link = $blocker;
+ }
$reason = $block->mReason;
if( $reason == '' ) {
array(
$link,
$reason,
- wfGetIP(),
- $block->getBlocker()->getName(),
+ $wgRequest->getIP(),
+ $block->getByName(),
$block->getId(),
$wgLang->formatExpiry( $block->mExpiry ),
$intended,
}
}
+/**
+ * Show an error that looks like an HTTP server error.
+ * Replacement for wfHttpError().
+ *
+ * @ingroup Exception
+ */
+class HttpError extends MWException {
+ private $httpCode, $header, $content;
+
+ /**
+ * Constructor
+ *
+ * @param $httpCode Integer: HTTP status code to send to the client
+ * @param $content String|Message: content of the message
+ * @param $header String|Message: content of the header (\<title\> and \<h1\>)
+ */
+ public function __construct( $httpCode, $content, $header = null ){
+ parent::__construct( $content );
+ $this->httpCode = (int)$httpCode;
+ $this->header = $header;
+ $this->content = $content;
+ }
+
+ public function report() {
+ $httpMessage = HttpStatus::getMessage( $this->httpCode );
+
+ header( "Status: {$this->httpCode} {$httpMessage}" );
+ header( 'Content-type: text/html; charset=utf-8' );
+
+ if ( $this->header === null ) {
+ $header = $httpMessage;
+ } elseif ( $this->header instanceof Message ) {
+ $header = $this->header->escaped();
+ } else {
+ $header = htmlspecialchars( $this->header );
+ }
+
+ if ( $this->content instanceof Message ) {
+ $content = $this->content->escaped();
+ } else {
+ $content = htmlspecialchars( $this->content );
+ }
+
+ print "<!DOCTYPE html>\n".
+ "<html><head><title>$header</title></head>\n" .
+ "<body><h1>$header</h1><p>$content</p></body></html>\n";
+ }
+}
+
/**
* Handler class for MWExceptions
* @ingroup Exception