diff options
Diffstat (limited to 'includes/db/DatabaseError.php')
-rw-r--r-- | includes/db/DatabaseError.php | 202 |
1 files changed, 135 insertions, 67 deletions
diff --git a/includes/db/DatabaseError.php b/includes/db/DatabaseError.php index 628a2afc..0875695f 100644 --- a/includes/db/DatabaseError.php +++ b/includes/db/DatabaseError.php @@ -43,24 +43,12 @@ class DBError extends MWException { } /** - * @param $html string - * @return string - */ - protected function getContentMessage( $html ) { - if ( $html ) { - return nl2br( htmlspecialchars( $this->getMessage() ) ); - } else { - return $this->getMessage(); - } - } - - /** * @return string */ function getText() { global $wgShowDBErrorBacktrace; - $s = $this->getContentMessage( false ) . "\n"; + $s = $this->getTextContent() . "\n"; if ( $wgShowDBErrorBacktrace ) { $s .= "Backtrace:\n" . $this->getTraceAsString() . "\n"; @@ -75,14 +63,29 @@ class DBError extends MWException { function getHTML() { global $wgShowDBErrorBacktrace; - $s = $this->getContentMessage( true ); + $s = $this->getHTMLContent(); if ( $wgShowDBErrorBacktrace ) { - $s .= '<p>Backtrace:</p><p>' . nl2br( htmlspecialchars( $this->getTraceAsString() ) ); + $s .= '<p>Backtrace:</p><p>' . + nl2br( htmlspecialchars( $this->getTraceAsString() ) ) . '</p>'; } return $s; } + + /** + * @return string + */ + protected function getTextContent() { + return $this->getMessage(); + } + + /** + * @return string + */ + protected function getHTMLContent() { + return '<p>' . nl2br( htmlspecialchars( $this->getMessage() ) ) . '</p>'; + } } /** @@ -96,11 +99,12 @@ class DBConnectionError extends DBError { if ( trim( $error ) != '' ) { $msg .= ": $error"; + } elseif ( $db ) { + $error = $this->db->getServer(); } - $this->error = $error; - parent::__construct( $db, $msg ); + $this->error = $error; } /** @@ -130,10 +134,10 @@ class DBConnectionError extends DBError { } /** - * @return bool + * @return boolean */ - function getLogMessage() { - # Don't send to the exception log + function isLoggable() { + // Don't send to the exception log, already in dberror log return false; } @@ -141,39 +145,51 @@ class DBConnectionError extends DBError { * @return string */ function getPageTitle() { - global $wgSitename; - return htmlspecialchars( $this->msg( 'dberr-header', "$wgSitename has a problem" ) ); + return $this->msg( 'dberr-header', 'This wiki has a problem' ); } /** * @return string */ function getHTML() { - global $wgShowDBErrorBacktrace; + global $wgShowDBErrorBacktrace, $wgShowHostnames, $wgShowSQLErrors; - $sorry = htmlspecialchars( $this->msg( 'dberr-problems', 'Sorry! This site is experiencing technical difficulties.' ) ); + $sorry = htmlspecialchars( $this->msg( 'dberr-problems', "Sorry!\nThis site is experiencing technical difficulties." ) ); $again = htmlspecialchars( $this->msg( 'dberr-again', 'Try waiting a few minutes and reloading.' ) ); - $info = htmlspecialchars( $this->msg( 'dberr-info', '(Can\'t contact the database server: $1)' ) ); - - # No database access - MessageCache::singleton()->disable(); - if ( trim( $this->error ) == '' && $this->db ) { - $this->error = $this->db->getProperty( 'mServer' ); + if ( $wgShowHostnames || $wgShowSQLErrors ) { + $info = str_replace( + '$1', Html::element( 'span', array( 'dir' => 'ltr' ), $this->error ), + htmlspecialchars( $this->msg( 'dberr-info', '(Cannot contact the database server: $1)' ) ) + ); + } else { + $info = htmlspecialchars( $this->msg( 'dberr-info-hidden', '(Cannot contact the database server)' ) ); } - $this->error = Html::element( 'span', array( 'dir' => 'ltr' ), $this->error ); + # No database access + MessageCache::singleton()->disable(); - $noconnect = "<h1>$sorry</h1><p>$again</p><p><small>$info</small></p>"; - $text = str_replace( '$1', $this->error, $noconnect ); + $text = "<h1>$sorry</h1><p>$again</p><p><small>$info</small></p>"; if ( $wgShowDBErrorBacktrace ) { - $text .= '<p>Backtrace:</p><p>' . nl2br( htmlspecialchars( $this->getTraceAsString() ) ); + $text .= '<p>Backtrace:</p><p>' . + nl2br( htmlspecialchars( $this->getTraceAsString() ) ) . '</p>'; } - $extra = $this->searchForm(); + $text .= '<hr />'; + $text .= $this->searchForm(); - return "$text<hr />$extra"; + return $text; + } + + protected function getTextContent() { + global $wgShowHostnames, $wgShowSQLErrors; + + if ( $wgShowHostnames || $wgShowSQLErrors ) { + return $this->getMessage(); + } else { + return 'DB connection error'; + } } public function reportHTML() { @@ -188,7 +204,7 @@ class DBConnectionError extends DBError { # Hack: extend the body for error messages $cache = str_replace( array( '</html>', '</body>' ), '', $cache ); # Add cache notice... - $cache .= '<div style="color:red;font-size:150%;font-weight:bold;">'. + $cache .= '<div style="color:red;font-size:150%;font-weight:bold;">' . htmlspecialchars( $this->msg( 'dberr-cachederror', 'This is a cached copy of the requested page, and may not be up to date. ' ) ) . '</div>'; @@ -302,55 +318,107 @@ class DBQueryError extends DBError { } /** - * @param $html string + * @return boolean + */ + function isLoggable() { + // Don't send to the exception log, already in dberror log + return false; + } + + /** * @return string */ - function getContentMessage( $html ) { - if ( $this->useMessageCache() ) { - if ( $html ) { - $msg = 'dberrortext'; - $sql = htmlspecialchars( $this->getSQL() ); - $fname = htmlspecialchars( $this->fname ); - $error = htmlspecialchars( $this->error ); - } else { - $msg = 'dberrortextcl'; - $sql = $this->getSQL(); - $fname = $this->fname; - $error = $this->error; + function getPageTitle() { + return $this->msg( 'databaseerror', 'Database error' ); + } + + /** + * @return string + */ + protected function getHTMLContent() { + $key = 'databaseerror-text'; + $s = Html::element( 'p', array(), $this->msg( $key, $this->getFallbackMessage( $key ) ) ); + + $details = $this->getTechnicalDetails(); + if ( $details ) { + $s .= '<ul>'; + foreach ( $details as $key => $detail ) { + $s .= str_replace( + '$1', call_user_func_array( 'Html::element', $detail ), + Html::element( 'li', array(), + $this->msg( $key, $this->getFallbackMessage( $key ) ) + ) + ); } - return wfMessage( $msg )->rawParams( $sql, $fname, $this->errno, $error )->text(); - } else { - return parent::getContentMessage( $html ); + $s .= '</ul>'; } + + return $s; } /** - * @return String + * @return string */ - function getSQL() { - global $wgShowSQLErrors; + protected function getTextContent() { + $key = 'databaseerror-textcl'; + $s = $this->msg( $key, $this->getFallbackMessage( $key ) ) . "\n"; - if ( !$wgShowSQLErrors ) { - return $this->msg( 'sqlhidden', 'SQL hidden' ); - } else { - return $this->sql; + foreach ( $this->getTechnicalDetails() as $key => $detail ) { + $s .= $this->msg( $key, $this->getFallbackMessage( $key ), $detail[2] ) . "\n"; } + + return $s; } /** - * @return bool + * Make a list of technical details that can be shown to the user. This information can + * aid in debugging yet may be useful to an attacker trying to exploit a security weakness + * in the software or server configuration. + * + * Thus no such details are shown by default, though if $wgShowHostnames is true, only the + * full SQL query is hidden; in fact, the error message often does contain a hostname, and + * sites using this option probably don't care much about "security by obscurity". Of course, + * if $wgShowSQLErrors is true, the SQL query *is* shown. + * + * @return array: Keys are message keys; values are arrays of arguments for Html::element(). + * Array will be empty if users are not allowed to see any of these details at all. */ - function getLogMessage() { - # Don't send to the exception log - return false; + protected function getTechnicalDetails() { + global $wgShowHostnames, $wgShowSQLErrors; + + $attribs = array( 'dir' => 'ltr' ); + $details = array(); + + if ( $wgShowSQLErrors ) { + $details['databaseerror-query'] = array( + 'div', array( 'class' => 'mw-code' ) + $attribs, $this->sql ); + } + + if ( $wgShowHostnames || $wgShowSQLErrors ) { + $errorMessage = $this->errno . ' ' . $this->error; + $details['databaseerror-function'] = array( 'code', $attribs, $this->fname ); + $details['databaseerror-error'] = array( 'samp', $attribs, $errorMessage ); + } + + return $details; } /** - * @return String + * @param string $key Message key + * @return string: English message text */ - function getPageTitle() { - return $this->msg( 'databaseerror', 'Database error' ); + private function getFallbackMessage( $key ) { + $messages = array( + 'databaseerror-text' => 'A database query error has occurred. +This may indicate a bug in the software.', + 'databaseerror-textcl' => 'A database query error has occurred.', + 'databaseerror-query' => 'Query: $1', + 'databaseerror-function' => 'Function: $1', + 'databaseerror-error' => 'Error: $1', + ); + return $messages[$key]; } + } /** |