MediaWiki  1.23.5
MWExceptionHandler.php
Go to the documentation of this file.
1 <?php
29  public static function installHandler() {
30  set_exception_handler( array( 'MWExceptionHandler', 'handle' ) );
31  }
32 
36  protected static function report( Exception $e ) {
37  global $wgShowExceptionDetails;
38 
39  $cmdLine = MWException::isCommandLine();
40 
41  if ( $e instanceof MWException ) {
42  try {
43  // Try and show the exception prettily, with the normal skin infrastructure
44  $e->report();
45  } catch ( Exception $e2 ) {
46  // Exception occurred from within exception handler
47  // Show a simpler error message for the original exception,
48  // don't try to invoke report()
49  $message = "MediaWiki internal error.\n\n";
50 
51  if ( $wgShowExceptionDetails ) {
52  $message .= 'Original exception: ' . self::getLogMessage( $e ) .
53  "\nBacktrace:\n" . self::getRedactedTraceAsString( $e ) .
54  "\n\nException caught inside exception handler: " . self::getLogMessage( $e2 ) .
55  "\nBacktrace:\n" . self::getRedactedTraceAsString( $e2 );
56  } else {
57  $message .= "Exception caught inside exception handler.\n\n" .
58  "Set \$wgShowExceptionDetails = true; at the bottom of LocalSettings.php " .
59  "to show detailed debugging information.";
60  }
61 
62  $message .= "\n";
63 
64  if ( $cmdLine ) {
65  self::printError( $message );
66  } else {
67  echo nl2br( htmlspecialchars( $message ) ) . "\n";
68  }
69  }
70  } else {
71  $message = "Unexpected non-MediaWiki exception encountered, of type \"" .
72  get_class( $e ) . "\"";
73 
74  if ( $wgShowExceptionDetails ) {
75  $message .= "\n" . MWExceptionHandler::getLogMessage( $e ) . "\nBacktrace:\n" .
77  }
78 
79  if ( $cmdLine ) {
80  self::printError( $message );
81  } else {
82  echo nl2br( htmlspecialchars( $message ) ) . "\n";
83  }
84  }
85  }
86 
93  public static function printError( $message ) {
94  # NOTE: STDERR may not be available, especially if php-cgi is used from the
95  # command line (bug #15602). Try to produce meaningful output anyway. Using
96  # echo may corrupt output to STDOUT though.
97  if ( defined( 'STDERR' ) ) {
98  fwrite( STDERR, $message );
99  } else {
100  echo $message;
101  }
102  }
103 
111  public static function rollbackMasterChangesAndLog( Exception $e ) {
113  if ( $factory->hasMasterChanges() ) {
114  wfDebugLog( 'Bug56269',
115  'Exception thrown with an uncommited database transaction: ' .
117  $e->getTraceAsString()
118  );
119  $factory->rollbackMasterChanges();
120  }
121  }
122 
134  public static function handle( $e ) {
136 
138 
139  self::report( $e );
140 
141  // Final cleanup
142  if ( $wgFullyInitialised ) {
143  try {
144  // uses $wgRequest, hence the $wgFullyInitialised condition
146  } catch ( Exception $e ) {
147  }
148  }
149 
150  // Exit value should be nonzero for the benefit of shell jobs
151  exit( 1 );
152  }
153 
163  public static function getRedactedTraceAsString( Exception $e ) {
164  $text = '';
165 
166  foreach ( self::getRedactedTrace( $e ) as $level => $frame ) {
167  if ( isset( $frame['file'] ) && isset( $frame['line'] ) ) {
168  $text .= "#{$level} {$frame['file']}({$frame['line']}): ";
169  } else {
170  // 'file' and 'line' are unset for calls via call_user_func (bug 55634)
171  // This matches behaviour of Exception::getTraceAsString to instead
172  // display "[internal function]".
173  $text .= "#{$level} [internal function]: ";
174  }
175 
176  if ( isset( $frame['class'] ) ) {
177  $text .= $frame['class'] . $frame['type'] . $frame['function'];
178  } else {
179  $text .= $frame['function'];
180  }
181 
182  if ( isset( $frame['args'] ) ) {
183  $text .= '(' . implode( ', ', $frame['args'] ) . ")\n";
184  } else {
185  $text .= "()\n";
186  }
187  }
188 
189  $level = $level + 1;
190  $text .= "#{$level} {main}";
191 
192  return $text;
193  }
194 
206  public static function getRedactedTrace( Exception $e ) {
207  return array_map( function ( $frame ) {
208  if ( isset( $frame['args'] ) ) {
209  $frame['args'] = array_map( function ( $arg ) {
210  return is_object( $arg ) ? get_class( $arg ) : gettype( $arg );
211  }, $frame['args'] );
212  }
213  return $frame;
214  }, $e->getTrace() );
215  }
216 
227  public static function getLogId( Exception $e ) {
228  if ( !isset( $e->_mwLogId ) ) {
229  $e->_mwLogId = wfRandomString( 8 );
230  }
231  return $e->_mwLogId;
232  }
233 
241  public static function getURL() {
242  global $wgRequest;
243  if ( !isset( $wgRequest ) || $wgRequest instanceof FauxRequest ) {
244  return false;
245  }
246  return $wgRequest->getRequestURL();
247  }
248 
257  public static function getLogMessage( Exception $e ) {
258  $id = self::getLogId( $e );
259  $file = $e->getFile();
260  $line = $e->getLine();
261  $message = $e->getMessage();
262  $url = self::getURL() ?: '[no req]';
263 
264  return "[$id] $url Exception from line $line of $file: $message";
265  }
266 
318  public static function jsonSerializeException( Exception $e, $pretty = false, $escaping = 0 ) {
319  global $wgLogExceptionBacktrace;
320 
321  $exceptionData = array(
322  'id' => self::getLogId( $e ),
323  'file' => $e->getFile(),
324  'line' => $e->getLine(),
325  'message' => $e->getMessage(),
326  );
327 
328  // Because MediaWiki is first and foremost a web application, we set a
329  // 'url' key unconditionally, but set it to null if the exception does
330  // not occur in the context of a web request, as a way of making that
331  // fact visible and explicit.
332  $exceptionData['url'] = self::getURL() ?: null;
333 
334  if ( $wgLogExceptionBacktrace ) {
335  // Argument values may not be serializable, so redact them.
336  $exceptionData['backtrace'] = self::getRedactedTrace( $e );
337  }
338 
339  return FormatJson::encode( $exceptionData, $pretty, $escaping );
340  }
341 
351  public static function logException( Exception $e ) {
352  global $wgLogExceptionBacktrace;
353 
354  if ( !( $e instanceof MWException ) || $e->isLoggable() ) {
355  $log = self::getLogMessage( $e );
356  if ( $wgLogExceptionBacktrace ) {
357  wfDebugLog( 'exception', $log . "\n" . $e->getTraceAsString() );
358  } else {
359  wfDebugLog( 'exception', $log );
360  }
361 
363  if ( $json !== false ) {
364  wfDebugLog( 'exception-json', $json, 'private' );
365  }
366  }
367 
368  }
369 
370 }
$factory
$factory
Definition: img_auth.php:54
FauxRequest
WebRequest clone which takes values from a provided array.
Definition: WebRequest.php:1275
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
MWExceptionHandler
Handler class for MWExceptions.
Definition: MWExceptionHandler.php:25
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all')
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:1040
MWExceptionHandler\getLogMessage
static getLogMessage(Exception $e)
Return the requested URL and point to file and line number from which the exception occurred.
Definition: MWExceptionHandler.php:257
MWExceptionHandler\installHandler
static installHandler()
Install an exception handler for MediaWiki exception types.
Definition: MWExceptionHandler.php:29
FormatJson\ALL_OK
const ALL_OK
Skip escaping as many characters as reasonably possible.
Definition: FormatJson.php:55
MWExceptionHandler\getRedactedTrace
static getRedactedTrace(Exception $e)
Return a copy of an exception's backtrace as an array.
Definition: MWExceptionHandler.php:206
MWExceptionHandler\printError
static printError( $message)
Print a message, if possible to STDERR.
Definition: MWExceptionHandler.php:93
MWException\isCommandLine
static isCommandLine()
Check whether we are in command line mode or not to report the exception in the correct format.
Definition: MWException.php:270
MWExceptionHandler\jsonSerializeException
static jsonSerializeException(Exception $e, $pretty=false, $escaping=0)
Serialize an Exception object to JSON.
Definition: MWExceptionHandler.php:318
FormatJson\encode
static encode( $value, $pretty=false, $escaping=0)
Returns the JSON representation of a value.
Definition: FormatJson.php:104
MWExceptionHandler\getRedactedTraceAsString
static getRedactedTraceAsString(Exception $e)
Generate a string representation of an exception's stack trace.
Definition: MWExceptionHandler.php:163
MWException
MediaWiki exception.
Definition: MWException.php:26
$wgFullyInitialised
$wgFullyInitialised
Definition: Setup.php:606
MWExceptionHandler\getURL
static getURL()
If the exception occurred in the course of responding to a request, returns the requested URL.
Definition: MWExceptionHandler.php:241
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
$line
$line
Definition: cdb.php:57
MWExceptionHandler\getLogId
static getLogId(Exception $e)
Get the ID for this error.
Definition: MWExceptionHandler.php:227
MWExceptionHandler\report
static report(Exception $e)
Report an exception to the user.
Definition: MWExceptionHandler.php:36
MWExceptionHandler\handle
static handle( $e)
Exception handler which simulates the appropriate catch() handling:
Definition: MWExceptionHandler.php:134
$file
if(PHP_SAPI !='cli') $file
Definition: UtfNormalTest2.php:30
wfGetLBFactory
& wfGetLBFactory()
Get the load balancer factory object.
Definition: GlobalFunctions.php:3678
MWExceptionHandler\rollbackMasterChangesAndLog
static rollbackMasterChangesAndLog(Exception $e)
If there are any open database transactions, roll them back and log the stack trace of the exception ...
Definition: MWExceptionHandler.php:111
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
MWExceptionHandler\logException
static logException(Exception $e)
Log an exception to the exception log (if enabled).
Definition: MWExceptionHandler.php:351
$e
if( $useReadline) $e
Definition: eval.php:66
wfLogProfilingData
wfLogProfilingData()
Definition: GlobalFunctions.php:1226
wfRandomString
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.
Definition: GlobalFunctions.php:300