MediaWiki  master
MWException.php
Go to the documentation of this file.
1 <?php
26 class MWException extends Exception {
32  public function useOutputPage() {
33  return $this->useMessageCache() &&
34  !empty( $GLOBALS['wgFullyInitialised'] ) &&
35  !empty( $GLOBALS['wgOut'] ) &&
36  !defined( 'MEDIAWIKI_INSTALL' );
37  }
38 
45  public function isLoggable() {
46  return true;
47  }
48 
54  public function useMessageCache() {
55  global $wgLang;
56 
57  foreach ( $this->getTrace() as $frame ) {
58  if ( isset( $frame['class'] ) && $frame['class'] === LocalisationCache::class ) {
59  return false;
60  }
61  }
62 
63  return $wgLang instanceof Language;
64  }
65 
75  public function msg( $key, $fallback, ...$params ) {
76  global $wgSitename;
77 
78  // FIXME: Keep logic in sync with MWExceptionRenderer::msg.
79  $res = false;
80  if ( $this->useMessageCache() ) {
81  try {
82  $res = wfMessage( $key, ...$params )->text();
83  } catch ( Exception $e ) {
84  }
85  }
86  if ( $res === false ) {
87  $res = wfMsgReplaceArgs( $fallback, $params );
88  // If an exception happens inside message rendering,
89  // {{SITENAME}} sometimes won't be replaced.
90  $res = strtr( $res, [
91  '{{SITENAME}}' => $wgSitename,
92  ] );
93  }
94  return $res;
95  }
96 
104  public function getHTML() {
106 
107  if ( $wgShowExceptionDetails ) {
108  return '<p>' . nl2br( htmlspecialchars( MWExceptionHandler::getLogMessage( $this ) ) ) .
109  '</p><p>Backtrace:</p><p>' .
110  nl2br( htmlspecialchars( MWExceptionHandler::getRedactedTraceAsString( $this ) ) ) .
111  "</p>\n";
112  } else {
113  $logId = WebRequest::getRequestId();
114  $type = static::class;
115  return Html::errorBox(
116  htmlspecialchars(
117  '[' . $logId . '] ' .
118  gmdate( 'Y-m-d H:i:s' ) . ": " .
119  $this->msg( "internalerror-fatal-exception",
120  "Fatal exception of type $1",
121  $type,
122  $logId,
124  )
125  ) ) .
126  "<!-- Set \$wgShowExceptionDetails = true; " .
127  "at the bottom of LocalSettings.php to show detailed " .
128  "debugging information. -->";
129  }
130  }
131 
139  public function getText() {
141 
142  if ( $wgShowExceptionDetails ) {
143  return MWExceptionHandler::getLogMessage( $this ) .
144  "\nBacktrace:\n" . MWExceptionHandler::getRedactedTraceAsString( $this ) . "\n";
145  } else {
146  return "Set \$wgShowExceptionDetails = true; " .
147  "in LocalSettings.php to show detailed debugging information.\n";
148  }
149  }
150 
156  public function getPageTitle() {
157  return $this->msg( 'internalerror', 'Internal error' );
158  }
159 
163  public function reportHTML() {
164  global $wgOut, $wgSitename;
165  if ( $this->useOutputPage() ) {
166  $wgOut->prepareErrorPage( $this->getPageTitle() );
167  // Manually set the html title, since sometimes
168  // {{SITENAME}} does not get replaced for exceptions
169  // happening inside message rendering.
170  $wgOut->setHTMLTitle(
171  $this->msg(
172  'pagetitle',
173  "$1 - $wgSitename",
174  $this->getPageTitle()
175  )
176  );
177 
178  $wgOut->addHTML( $this->getHTML() );
179 
180  $wgOut->output();
181  } else {
182  self::header( 'Content-Type: text/html; charset=utf-8' );
183  echo "<!DOCTYPE html>\n" .
184  '<html><head>' .
185  // Mimick OutputPage::setPageTitle behaviour
186  '<title>' .
187  htmlspecialchars( $this->msg( 'pagetitle', "$1 - $wgSitename", $this->getPageTitle() ) ) .
188  '</title>' .
189  '<style>body { font-family: sans-serif; margin: 0; padding: 0.5em 2em; }</style>' .
190  "</head><body>\n";
191 
192  echo $this->getHTML();
193 
194  echo "</body></html>\n";
195  }
196  }
197 
202  public function report() {
203  global $wgMimeType;
204 
205  if ( defined( 'MW_API' ) ) {
206  // Unhandled API exception, we can't be sure that format printer is alive
207  self::header( 'MediaWiki-API-Error: internal_api_error_' . static::class );
208  wfHttpError( 500, 'Internal Server Error', $this->getText() );
209  } elseif ( self::isCommandLine() ) {
210  $message = $this->getText();
211  $this->writeToCommandLine( $message );
212  } else {
213  self::statusHeader( 500 );
214  self::header( "Content-Type: $wgMimeType; charset=utf-8" );
215 
216  $this->reportHTML();
217  }
218  }
219 
226  private function writeToCommandLine( $message ) {
227  // T17602: STDERR may not be available
228  if ( !defined( 'MW_PHPUNIT_TEST' ) && defined( 'STDERR' ) ) {
229  fwrite( STDERR, $message );
230  } else {
231  echo $message;
232  }
233  }
234 
241  public static function isCommandLine() {
242  return !empty( $GLOBALS['wgCommandLineMode'] );
243  }
244 
250  private static function header( $header ) {
251  if ( !headers_sent() ) {
252  header( $header );
253  }
254  }
255 
256  private static function statusHeader( $code ) {
257  if ( !headers_sent() ) {
258  HttpStatus::header( $code );
259  }
260  }
261 }
static getLogMessage( $e)
Get a message formatting the exception message and its origin.
static getRequestId()
Get the unique request ID.
Definition: WebRequest.php:309
$wgSitename
Name of the site.
$wgMimeType
The default Content-Type header.
getPageTitle()
Return the title of the page when reporting this error in a HTTP response.
isLoggable()
Whether to log this exception in the exception debug log.
Definition: MWException.php:45
useMessageCache()
Can the extension use the Message class/wfMessage to get i18n-ed messages?
Definition: MWException.php:54
static statusHeader( $code)
$wgShowExceptionDetails
If set to true, uncaught exceptions will print the exception message and a complete stack trace to ou...
getHTML()
If $wgShowExceptionDetails is true, return a HTML message with a backtrace to the error...
static errorBox( $html, $heading='', $className='')
Return an error box.
Definition: Html.php:739
$wgLang
Definition: Setup.php:857
msg( $key, $fallback,... $params)
Get a message from i18n.
Definition: MWException.php:75
static getRedactedTraceAsString( $e)
Generate a string representation of an exception&#39;s stack trace.
wfMsgReplaceArgs( $message, $args)
Replace message parameter keys on the given formatted output.
static header( $code)
Output an HTTP status code header.
Definition: HttpStatus.php:96
wfHttpError( $code, $label, $desc)
Provide a simple HTTP error.
static getURL()
If the exception occurred in the course of responding to a request, returns the requested URL...
$GLOBALS['IP']
$header
static isCommandLine()
Check whether we are in command line mode or not to report the exception in the correct format...
getText()
Get the text to display when reporting the error on the command line.
$fallback
Definition: MessagesAb.php:11
useOutputPage()
Should the exception use $wgOut to output the error?
Definition: MWException.php:32
reportHTML()
Output the exception report using HTML.
report()
Output a report about the exception and takes care of formatting.
$wgOut
Definition: Setup.php:862
static header( $header)
Send a header, if we haven&#39;t already sent them.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
writeToCommandLine( $message)
Write a message to stderr falling back to stdout if stderr unavailable.