MediaWiki  master
MWException.php
Go to the documentation of this file.
1 <?php
22 
32 class MWException extends Exception {
38  private function useOutputPage() {
39  // NOTE: keep in sync with MWExceptionRenderer::useOutputPage
40  return $this->useMessageCache() &&
41  !empty( $GLOBALS['wgFullyInitialised'] ) &&
42  !empty( $GLOBALS['wgOut'] ) &&
43  !defined( 'MEDIAWIKI_INSTALL' ) &&
44  // Don't send a skinned HTTP 500 page to API clients.
45  !defined( 'MW_API' );
46  }
47 
56  public function isLoggable() {
57  return true;
58  }
59 
67  public function useMessageCache() {
68  foreach ( $this->getTrace() as $frame ) {
69  if ( isset( $frame['class'] ) && $frame['class'] === LocalisationCache::class ) {
70  return false;
71  }
72  }
73  return true;
74  }
75 
85  public function msg( $key, $fallback, ...$params ) {
86  // NOTE: Keep logic in sync with MWExceptionRenderer::msg.
87  $res = false;
88  if ( $this->useMessageCache() ) {
89  try {
90  $res = wfMessage( $key, ...$params )->text();
91  } catch ( Exception $e ) {
92  }
93  }
94  if ( $res === false ) {
95  // Fallback to static message text and generic sitename.
96  // Avoid live config as this must work before Setup/MediaWikiServices finish.
97  $res = wfMsgReplaceArgs( $fallback, $params );
98  $res = strtr( $res, [
99  '{{SITENAME}}' => 'MediaWiki',
100  ] );
101  }
102  return $res;
103  }
104 
113  public function getHTML() {
115  return '<p>' . nl2br( htmlspecialchars( MWExceptionHandler::getLogMessage( $this ) ) ) .
116  '</p><p>Backtrace:</p><p>' .
117  nl2br( htmlspecialchars( MWExceptionHandler::getRedactedTraceAsString( $this ) ) ) .
118  "</p>\n";
119  } else {
120  $logId = WebRequest::getRequestId();
121  $type = static::class;
122  return Html::errorBox(
123  htmlspecialchars(
124  '[' . $logId . '] ' .
125  gmdate( 'Y-m-d H:i:s' ) . ": " .
126  $this->msg( "internalerror-fatal-exception",
127  "Fatal exception of type $1",
128  $type,
129  $logId,
131  )
132  ) ) .
133  "<!-- Set \$wgShowExceptionDetails = true; " .
134  "at the bottom of LocalSettings.php to show detailed " .
135  "debugging information. -->";
136  }
137  }
138 
146  public function getText() {
148  return MWExceptionHandler::getLogMessage( $this ) .
149  "\nBacktrace:\n" . MWExceptionHandler::getRedactedTraceAsString( $this ) . "\n";
150  } else {
151  return "Set \$wgShowExceptionDetails = true; " .
152  "in LocalSettings.php to show detailed debugging information.\n";
153  }
154  }
155 
163  public function getPageTitle() {
164  return $this->msg( 'internalerror', 'Internal error' );
165  }
166 
171  public function reportHTML() {
172  global $wgOut;
173  if ( $this->useOutputPage() ) {
174  $wgOut->prepareErrorPage( $this->getPageTitle() );
175  // Manually set the html title, since sometimes
176  // {{SITENAME}} does not get replaced for exceptions
177  // happening inside message rendering.
178  $wgOut->setHTMLTitle(
179  $this->msg( 'pagetitle', '$1 - MediaWiki', $this->getPageTitle() )
180  );
181 
182  $wgOut->addHTML( $this->getHTML() );
183  // Content-Type is set by OutputPage::output
184  $wgOut->output();
185  } else {
186  self::header( 'Content-Type: text/html; charset=UTF-8' );
187  echo "<!DOCTYPE html>\n" .
188  '<html><head>' .
189  // Mimic OutputPage::setPageTitle behaviour
190  '<title>' .
191  htmlspecialchars( $this->msg( 'pagetitle', '$1 - MediaWiki', $this->getPageTitle() ) ) .
192  '</title>' .
193  '<style>body { font-family: sans-serif; margin: 0; padding: 0.5em 2em; }</style>' .
194  "</head><body>\n";
195 
196  echo $this->getHTML();
197 
198  echo "</body></html>\n";
199  }
200  }
201 
208  public function report() {
209  if ( defined( 'MW_API' ) ) {
210  self::header( 'MediaWiki-API-Error: internal_api_error_' . static::class );
211  }
212 
213  if ( self::isCommandLine() ) {
214  $message = $this->getText();
215  $this->writeToCommandLine( $message );
216  } else {
217  self::statusHeader( 500 );
218  $this->reportHTML();
219  }
220  }
221 
228  private function writeToCommandLine( $message ) {
229  // T17602: STDERR may not be available
230  if ( !defined( 'MW_PHPUNIT_TEST' ) && defined( 'STDERR' ) ) {
231  fwrite( STDERR, $message );
232  } else {
233  echo $message;
234  }
235  }
236 
243  public static function isCommandLine() {
244  return !empty( $GLOBALS['wgCommandLineMode'] );
245  }
246 
252  private static function header( $header ) {
253  if ( !headers_sent() ) {
254  header( $header );
255  }
256  }
257 
258  private static function statusHeader( $code ) {
259  if ( !headers_sent() ) {
260  HttpStatus::header( $code );
261  }
262  }
263 }
wfMsgReplaceArgs( $message, $args)
Replace message parameter keys on the given formatted output.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
$fallback
Definition: MessagesAb.php:8
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode) $wgOut
Definition: Setup.php:528
static header( $code)
Output an HTTP status code header.
Definition: HttpStatus.php:96
static getRedactedTraceAsString(Throwable $e)
Generate a string representation of a throwable's stack trace.
static getLogMessage(Throwable $e)
Get a message formatting the throwable message and its origin.
static getURL()
If the exception occurred in the course of responding to a request, returns the requested URL.
MediaWiki exception.
Definition: MWException.php:32
isLoggable()
Whether to log this exception in the exception debug log.
Definition: MWException.php:56
useMessageCache()
Can the extension use the Message class/wfMessage to get i18n-ed messages?
Definition: MWException.php:67
msg( $key, $fallback,... $params)
Get a message from i18n.
Definition: MWException.php:85
getHTML()
Format an HTML message for the current exception object.
static isCommandLine()
Check whether we are in command line mode or not to report the exception in the correct format.
report()
Output a report about the exception and takes care of formatting.
getPageTitle()
Return the title of the page when reporting this error in a HTTP response.
reportHTML()
Output the exception report using HTML.
getText()
Format plain text message for the current exception object.
This class is a collection of static functions that serve two purposes:
Definition: Html.php:55
static getRequestId()
Get the current request ID.
Definition: WebRequest.php:345
$header