wiki.techinc.nl/includes/Exception.php

360 lines
9.3 KiB
PHP
Raw Normal View History

<?php
/**
* @defgroup Exception Exception
*/
/**
2007-04-21 12:42:27 +00:00
* MediaWiki exception
* @ingroup Exception
*/
class MWException extends Exception {
/**
* Should the exception use $wgOut to output the error ?
* @return bool
*/
function useOutputPage() {
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput. * The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true; * Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache. * Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words. * $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c. * Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess. * Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly. * Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load() * Fixed FileDependency::__sleep() * In Cdb.php, fixed newlines in debug messages In MessageCache::get(): * Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII. * Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us * Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us. * Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
return $this->useMessageCache() &&
!empty( $GLOBALS['wgFullyInitialised'] ) &&
( !empty( $GLOBALS['wgArticle'] ) || ( !empty( $GLOBALS['wgOut'] ) && !$GLOBALS['wgOut']->isArticle() ) ) &&
!empty( $GLOBALS['wgTitle'] );
}
/**
* Can the extension use wfMsg() to get i18n messages ?
* @return bool
*/
function useMessageCache() {
global $wgLang;
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput. * The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true; * Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache. * Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words. * $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c. * Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess. * Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly. * Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load() * Fixed FileDependency::__sleep() * In Cdb.php, fixed newlines in debug messages In MessageCache::get(): * Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII. * Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us * Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us. * Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
foreach ( $this->getTrace() as $frame ) {
if ( isset( $frame['class'] ) && $frame['class'] === 'LocalisationCache' ) {
* Introduced a new system for localisation caching. The system is based around fast fetches of individual messages, minimising memory overhead and startup time in the typical case. It handles both core messages (formerly in Language.php) and extension messages (formerly in MessageCache.php). Profiling indicates a significant win for average throughput. * The serialized message cache, which would have been redundant, has been removed. Similar performance characteristics can be achieved with $wgLocalisationCacheConf['manualRecache'] = true; * Added a maintenance script rebuildLocalisationCache.php for offline rebuilding of the localisation cache. * Extension i18n files can now contain any of the variables which can be set in Messages*.php. It is possible, and recommended, to use this feature instead of the hooks for special page aliases and magic words. * $wgExtensionAliasesFiles, LanguageGetMagic and LanguageGetSpecialPageAliases are retained for backwards compatibility. $wgMessageCache->addMessages() and related functions have been removed. wfLoadExtensionMessages() is a no-op and can continue to be called for b/c. * Introduced $wgCacheDirectory as a default location for the various local caches that have accumulated. Suggested $IP/cache as a good place for it in the default LocalSettings.php and created this directory with a deny-all .htaccess. * Patched Exception.php to avoid using the message cache when an exception is thrown from within LocalisationCache, since this tends to fail horribly. * Removed Language::getLocalisationArray(), Language::loadLocalisation(), Language::load() * Fixed FileDependency::__sleep() * In Cdb.php, fixed newlines in debug messages In MessageCache::get(): * Replaced calls to $wgContLang capitalisation functions with plain PHP functions, reducing the typical case from 99us to 93us. Message cache keys are already documented as being restricted to ASCII. * Implemented a more efficient way to filter out bogus language codes, reducing the "foo/en" case from 430us to 101us * Optimised wfRunHooks() in the typical do-nothing case, from ~30us to ~3us. This reduced MessageCache::get() typical case time from 93us to 38us. * Removed hook MessageNotInMwNs to save an extra 3us per cache hit. Reimplemented the only user (LocalisationUpdate) using the new hook LocalisationCacheRecache.
2009-06-28 07:11:43 +00:00
return false;
}
}
return is_object( $wgLang );
}
/**
* Run hook to allow extensions to modify the text of the exception
*
2010-03-05 21:39:21 +00:00
* @param $name String: class name of the exception
* @param $args Array: arguments to pass to the callback functions
* @return Mixed: string to output or null if any hook has been called
*/
function runHooks( $name, $args = array() ) {
global $wgExceptionHooks;
if( !isset( $wgExceptionHooks ) || !is_array( $wgExceptionHooks ) )
return; // Just silently ignore
if( !array_key_exists( $name, $wgExceptionHooks ) || !is_array( $wgExceptionHooks[ $name ] ) )
return;
$hooks = $wgExceptionHooks[ $name ];
$callargs = array_merge( array( $this ), $args );
foreach( $hooks as $hook ) {
if( is_string( $hook ) || ( is_array( $hook ) && count( $hook ) >= 2 && is_string( $hook[0] ) ) ) { //'function' or array( 'class', hook' )
$result = call_user_func_array( $hook, $callargs );
} else {
$result = null;
}
if( is_string( $result ) )
return $result;
}
}
/**
* Get a message from i18n
*
2010-03-05 21:39:21 +00:00
* @param $key String: message name
* @param $fallback String: default message if the message cache can't be
* called by the exception
* The function also has other parameters that are arguments for the message
* @return String message with arguments replaced
*/
function msg( $key, $fallback /*[, params...] */ ) {
$args = array_slice( func_get_args(), 2 );
if ( $this->useMessageCache() ) {
return wfMsgReal( $key, $args );
} else {
return wfMsgReplaceArgs( $fallback, $args );
}
}
/**
* If $wgShowExceptionDetails is true, return a HTML message with a
* backtrace to the error, otherwise show a message to ask to set it to true
* to show that information.
*
* @return String html to output
*/
function getHTML() {
global $wgShowExceptionDetails;
if( $wgShowExceptionDetails ) {
return '<p>' . nl2br( htmlspecialchars( $this->getMessage() ) ) .
'</p><p>Backtrace:</p><p>' . nl2br( htmlspecialchars( $this->getTraceAsString() ) ) .
"</p>\n";
} else {
return "<p>Set <b><tt>\$wgShowExceptionDetails = true;</tt></b> " .
"at the bottom of LocalSettings.php to show detailed " .
"debugging information.</p>";
}
}
/**
* If $wgShowExceptionDetails is true, return a text message with a
* backtrace to the error.
*/
function getText() {
global $wgShowExceptionDetails;
if( $wgShowExceptionDetails ) {
return $this->getMessage() .
"\nBacktrace:\n" . $this->getTraceAsString() . "\n";
} else {
return "Set \$wgShowExceptionDetails = true; " .
"in LocalSettings.php to show detailed debugging information.\n";
}
}
2007-04-21 12:42:27 +00:00
/* Return titles of this error page */
function getPageTitle() {
if ( $this->useMessageCache() ) {
return wfMsg( 'internalerror' );
} else {
global $wgSitename;
return "$wgSitename error";
}
}
2007-04-21 12:42:27 +00:00
/**
* Return the requested URL and point to file and line number from which the
2007-04-21 12:42:27 +00:00
* exception occured
*
2010-03-05 21:39:21 +00:00
* @return String
2007-04-21 12:42:27 +00:00
*/
2006-08-02 17:40:09 +00:00
function getLogMessage() {
global $wgRequest;
2006-08-02 17:40:09 +00:00
$file = $this->getFile();
$line = $this->getLine();
$message = $this->getMessage();
if ( isset( $wgRequest ) ) {
$url = $wgRequest->getRequestURL();
if ( !$url ) {
$url = '[no URL]';
}
} else {
$url = '[no req]';
}
return "$url Exception from line $line of $file: $message";
2006-08-02 17:40:09 +00:00
}
2007-04-21 12:42:27 +00:00
/** 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();
if( $hookResult = $this->runHooks( get_class( $this ) ) ) {
$wgOut->addHTML( $hookResult );
} else {
$wgOut->addHTML( $this->getHTML() );
}
$wgOut->output();
} else {
if( $hookResult = $this->runHooks( get_class( $this ) . "Raw" ) ) {
die( $hookResult );
}
if ( defined( 'MEDIAWIKI_INSTALL' ) || $this->htmlBodyOnly() ) {
echo $this->getHTML();
} else {
echo $this->htmlHeader();
echo $this->getHTML();
echo $this->htmlFooter();
}
}
}
2007-04-21 12:42:27 +00:00
/**
* Output a report about the exception and takes care of formatting.
* It will be either HTML or plain text based on isCommandLine().
2007-04-21 12:42:27 +00:00
*/
function report() {
$log = $this->getLogMessage();
if ( $log ) {
wfDebugLog( 'exception', $log );
}
if ( self::isCommandLine() ) {
wfPrintError( $this->getText() );
} else {
$this->reportHTML();
}
}
/**
* Send headers and output the beginning of the html page if not using
* $wgOut to output the exception.
*/
function htmlHeader() {
global $wgLogo, $wgSitename, $wgOutputEncoding;
if ( !headers_sent() ) {
header( 'HTTP/1.0 500 Internal Server Error' );
header( 'Content-type: text/html; charset='.$wgOutputEncoding );
/* Don't cache error pages! They cause no end of trouble... */
header( 'Cache-control: none' );
header( 'Pragma: nocache' );
}
$title = $this->getPageTitle();
return "<html>
<head>
<title>$title</title>
</head>
<body>
<h1><img src='$wgLogo' style='float:left;margin-right:1em' alt=''/>$title</h1>
";
}
/**
* print the end of the html page if not using $wgOut.
*/
function htmlFooter() {
return "</body></html>";
2006-07-11 17:40:11 +00:00
}
/**
* headers handled by subclass?
*/
function htmlBodyOnly() {
return false;
}
static function isCommandLine() {
return !empty( $GLOBALS['wgCommandLineMode'] ) && !defined( 'MEDIAWIKI_INSTALL' );
}
}
/**
2006-07-11 17:40:11 +00:00
* Exception class which takes an HTML error message, and does not
* produce a backtrace. Replacement for OutputPage::fatalError().
* @ingroup Exception
*/
class FatalError extends MWException {
function getHTML() {
return $this->getMessage();
}
function getText() {
return $this->getMessage();
}
}
/**
* @ingroup Exception
*/
class ErrorPageError extends MWException {
public $title, $msg;
/**
* Note: these arguments are keys into wfMsg(), not text!
*/
function __construct( $title, $msg ) {
$this->title = $title;
$this->msg = $msg;
parent::__construct( wfMsg( $msg ) );
}
function report() {
global $wgOut;
$wgOut->showErrorPage( $this->title, $this->msg );
$wgOut->output();
}
}
/**
* Install an exception handler for MediaWiki exception types.
*/
function wfInstallExceptionHandler() {
set_exception_handler( 'wfExceptionHandler' );
}
/**
* Report an exception to the user
*/
function wfReportException( Exception $e ) {
$cmdLine = MWException::isCommandLine();
if ( $e instanceof MWException ) {
2009-02-17 21:14:34 +00:00
try {
$e->report();
} catch ( Exception $e2 ) {
// Exception occurred from within exception handler
// Show a simpler error message for the original exception,
// don't try to invoke report()
$message = "MediaWiki internal error.\n\n";
if ( $GLOBALS['wgShowExceptionDetails'] )
$message .= "Original exception: " . $e->__toString();
$message .= "\n\nException caught inside exception handler";
if ( $GLOBALS['wgShowExceptionDetails'] )
$message .= ": " . $e2->__toString();
$message .= "\n";
if ( $cmdLine ) {
wfPrintError( $message );
} else {
echo nl2br( htmlspecialchars( $message ) ). "\n";
}
2009-02-17 21:14:34 +00:00
}
} else {
$message = "Unexpected non-MediaWiki exception encountered, of type \"" . get_class( $e ) . "\"\n" .
$e->__toString() . "\n";
if ( $GLOBALS['wgShowExceptionDetails'] ) {
$message .= "\n" . $e->getTraceAsString() ."\n";
}
if ( $cmdLine ) {
wfPrintError( $message );
} else {
echo nl2br( htmlspecialchars( $message ) ). "\n";
}
2009-02-17 21:14:34 +00:00
}
}
/**
* Print a message, if possible to STDERR.
* Use this in command line mode only (see isCommandLine)
*/
function wfPrintError( $message ) {
#NOTE: STDERR may not be available, especially if php-cgi is used from the command line (bug #15602).
# Try to produce meaningful output anyway. Using echo may corrupt output to STDOUT though.
if ( defined( 'STDERR' ) ) {
fwrite( STDERR, $message );
} else {
echo( $message );
}
}
/**
* Exception handler which simulates the appropriate catch() handling:
2006-07-11 17:40:11 +00:00
*
* try {
* ...
* } catch ( MWException $e ) {
* $e->report();
* } catch ( Exception $e ) {
* echo $e->__toString();
* }
*/
function wfExceptionHandler( $e ) {
global $wgFullyInitialised;
wfReportException( $e );
2007-04-21 12:42:27 +00:00
// Final cleanup, similar to wfErrorExit()
if ( $wgFullyInitialised ) {
try {
wfLogProfilingData(); // uses $wgRequest, hence the $wgFullyInitialised condition
} catch ( Exception $e ) {}
}
// Exit value should be nonzero for the benefit of shell jobs
exit( 1 );
}