MediaWiki  REL1_19
DatabaseError.php
Go to the documentation of this file.
00001 <?php
00002 
00007 class DBError extends MWException {
00008 
00012         public $db;
00013 
00019         function __construct( DatabaseBase &$db, $error ) {
00020                 $this->db = $db;
00021                 parent::__construct( $error );
00022         }
00023 
00028         protected function getContentMessage( $html ) {
00029                 if ( $html ) {
00030                         return nl2br( htmlspecialchars( $this->getMessage() ) );
00031                 } else {
00032                         return $this->getMessage();
00033                 }
00034         }
00035 
00039         function getText() {
00040                 global $wgShowDBErrorBacktrace;
00041 
00042                 $s = $this->getContentMessage( false ) . "\n";
00043 
00044                 if ( $wgShowDBErrorBacktrace ) {
00045                         $s .= "Backtrace:\n" . $this->getTraceAsString() . "\n";
00046                 }
00047 
00048                 return $s;
00049         }
00050 
00054         function getHTML() {
00055                 global $wgShowDBErrorBacktrace;
00056 
00057                 $s = $this->getContentMessage( true );
00058 
00059                 if ( $wgShowDBErrorBacktrace ) {
00060                         $s .= '<p>Backtrace:</p><p>' . nl2br( htmlspecialchars( $this->getTraceAsString() ) );
00061                 }
00062 
00063                 return $s;
00064         }
00065 }
00066 
00070 class DBConnectionError extends DBError {
00071         public $error;
00072 
00073         function __construct( DatabaseBase &$db, $error = 'unknown error' ) {
00074                 $msg = 'DB connection error';
00075 
00076                 if ( trim( $error ) != '' ) {
00077                         $msg .= ": $error";
00078                 }
00079 
00080                 $this->error = $error;
00081 
00082                 parent::__construct( $db, $msg );
00083         }
00084 
00088         function useOutputPage() {
00089                 // Not likely to work
00090                 return false;
00091         }
00092 
00098         function msg( $key, $fallback /*[, params...] */ ) {
00099                 global $wgLang;
00100 
00101                 $args = array_slice( func_get_args(), 2 );
00102 
00103                 if ( $this->useMessageCache() ) {
00104                         $message = $wgLang->getMessage( $key );
00105                 } else {
00106                         $message = $fallback;
00107                 }
00108                 return wfMsgReplaceArgs( $message, $args );
00109         }
00110 
00114         function getLogMessage() {
00115                 # Don't send to the exception log
00116                 return false;
00117         }
00118 
00122         function getPageTitle() {
00123                 global $wgSitename;
00124                 return htmlspecialchars( $this->msg( 'dberr-header', "$wgSitename has a problem" ) );
00125         }
00126 
00130         function getHTML() {
00131                 global $wgShowDBErrorBacktrace;
00132 
00133                 $sorry = htmlspecialchars( $this->msg( 'dberr-problems', 'Sorry! This site is experiencing technical difficulties.' ) );
00134                 $again = htmlspecialchars( $this->msg( 'dberr-again', 'Try waiting a few minutes and reloading.' ) );
00135                 $info  = htmlspecialchars( $this->msg( 'dberr-info', '(Can\'t contact the database server: $1)' ) );
00136 
00137                 # No database access
00138                 MessageCache::singleton()->disable();
00139 
00140                 if ( trim( $this->error ) == '' ) {
00141                         $this->error = $this->db->getProperty( 'mServer' );
00142                 }
00143 
00144                 $this->error = Html::element( 'span', array( 'dir' => 'ltr' ), $this->error );
00145 
00146                 $noconnect = "<h1>$sorry</h1><p>$again</p><p><small>$info</small></p>";
00147                 $text = str_replace( '$1', $this->error, $noconnect );
00148 
00149                 if ( $wgShowDBErrorBacktrace ) {
00150                         $text .= '<p>Backtrace:</p><p>' . nl2br( htmlspecialchars( $this->getTraceAsString() ) );
00151                 }
00152 
00153                 $extra = $this->searchForm();
00154 
00155                 return "$text<hr />$extra";
00156         }
00157 
00158         public function reportHTML(){
00159                 global $wgUseFileCache;
00160 
00161                 # Check whether we can serve a file-cached copy of the page with the error underneath
00162                 if ( $wgUseFileCache ) {
00163                         try {
00164                                 $cache = $this->fileCachedPage();
00165                                 # Cached version on file system?
00166                                 if ( $cache !== null ) {
00167                                         # Hack: extend the body for error messages
00168                                         $cache = str_replace( array( '</html>', '</body>' ), '', $cache );
00169                                         # Add cache notice...
00170                                         $cache .= '<div style="color:red;font-size:150%;font-weight:bold;">'.
00171                                                 htmlspecialchars( $this->msg( 'dberr-cachederror',
00172                                                         'This is a cached copy of the requested page, and may not be up to date. ' ) ) .
00173                                                 '</div>';
00174 
00175                                         # Output cached page with notices on bottom and re-close body
00176                                         echo "{$cache}<hr />{$this->getHTML()}</body></html>";
00177                                         return;
00178                                 }
00179                         } catch ( MWException $e ) {
00180                                 // Do nothing, just use the default page
00181                         }
00182                 }
00183 
00184                 # We can't, cough and die in the usual fashion
00185                 parent::reportHTML();
00186         }
00187 
00191         function searchForm() {
00192                 global $wgSitename, $wgServer, $wgRequest;
00193 
00194                 $usegoogle = htmlspecialchars( $this->msg( 'dberr-usegoogle', 'You can try searching via Google in the meantime.' ) );
00195                 $outofdate = htmlspecialchars( $this->msg( 'dberr-outofdate', 'Note that their indexes of our content may be out of date.' ) );
00196                 $googlesearch = htmlspecialchars( $this->msg( 'searchbutton', 'Search' ) );
00197 
00198                 $search = htmlspecialchars( $wgRequest->getVal( 'search' ) );
00199 
00200                 $server = htmlspecialchars( $wgServer );
00201                 $sitename = htmlspecialchars( $wgSitename );
00202 
00203                 $trygoogle = <<<EOT
00204 <div style="margin: 1.5em">$usegoogle<br />
00205 <small>$outofdate</small></div>
00206 <!-- SiteSearch Google -->
00207 <form method="get" action="//www.google.com/search" id="googlesearch">
00208         <input type="hidden" name="domains" value="$server" />
00209         <input type="hidden" name="num" value="50" />
00210         <input type="hidden" name="ie" value="UTF-8" />
00211         <input type="hidden" name="oe" value="UTF-8" />
00212 
00213         <input type="text" name="q" size="31" maxlength="255" value="$search" />
00214         <input type="submit" name="btnG" value="$googlesearch" />
00215   <div>
00216         <input type="radio" name="sitesearch" id="gwiki" value="$server" checked="checked" /><label for="gwiki">$sitename</label>
00217         <input type="radio" name="sitesearch" id="gWWW" value="" /><label for="gWWW">WWW</label>
00218   </div>
00219 </form>
00220 <!-- SiteSearch Google -->
00221 EOT;
00222                 return $trygoogle;
00223         }
00224 
00228         private function fileCachedPage() {
00229                 global $wgTitle, $wgOut, $wgRequest;
00230 
00231                 if ( $wgOut->isDisabled() ) {
00232                         return ''; // Done already?
00233                 }
00234 
00235                 if ( $wgTitle ) { // use $wgTitle if we managed to set it
00236                         $t = $wgTitle->getPrefixedDBkey();
00237                 } else {
00238                         # Fallback to the raw title URL param. We can't use the Title
00239                         # class is it may hit the interwiki table and give a DB error.
00240                         # We may get a cache miss due to not sanitizing the title though.
00241                         $t = str_replace( ' ', '_', $wgRequest->getVal( 'title' ) );
00242                         if ( $t == '' ) { // fallback to main page
00243                                 $t = Title::newFromText(
00244                                         $this->msg( 'mainpage', 'Main Page' ) )->getPrefixedDBkey();
00245                         }
00246                 }
00247 
00248                 $cache = HTMLFileCache::newFromTitle( $t, 'view' );
00249                 if ( $cache->isCached() ) {
00250                         return $cache->fetchText();
00251                 } else {
00252                         return '';
00253                 }
00254         }
00255 }
00256 
00260 class DBQueryError extends DBError {
00261         public $error, $errno, $sql, $fname;
00262 
00270         function __construct( DatabaseBase &$db, $error, $errno, $sql, $fname ) {
00271                 $message = "A database error has occurred.  Did you forget to run maintenance/update.php after upgrading?  See: https://www.mediawiki.org/wiki/Manual:Upgrading#Run_the_update_script\n" .
00272                   "Query: $sql\n" .
00273                   "Function: $fname\n" .
00274                   "Error: $errno $error\n";
00275                 parent::__construct( $db, $message );
00276 
00277                 $this->error = $error;
00278                 $this->errno = $errno;
00279                 $this->sql = $sql;
00280                 $this->fname = $fname;
00281         }
00282 
00287         function getContentMessage( $html ) {
00288                 if ( $this->useMessageCache() ) {
00289                         if ( $html ) {
00290                                 $msg = 'dberrortext';
00291                                 $sql = htmlspecialchars( $this->getSQL() );
00292                                 $fname = htmlspecialchars( $this->fname );
00293                                 $error = htmlspecialchars( $this->error );
00294                         } else {
00295                                 $msg = 'dberrortextcl';
00296                                 $sql = $this->getSQL();
00297                                 $fname = $this->fname;
00298                                 $error = $this->error;
00299                         }
00300                         return wfMsg( $msg, $sql, $fname, $this->errno, $error );
00301                 } else {
00302                         return parent::getContentMessage( $html );
00303                 }
00304         }
00305 
00309         function getSQL() {
00310                 global $wgShowSQLErrors;
00311 
00312                 if ( !$wgShowSQLErrors ) {
00313                         return $this->msg( 'sqlhidden', 'SQL hidden' );
00314                 } else {
00315                         return $this->sql;
00316                 }
00317         }
00318 
00322         function getLogMessage() {
00323                 # Don't send to the exception log
00324                 return false;
00325         }
00326 
00330         function getPageTitle() {
00331                 return $this->msg( 'databaseerror', 'Database error' );
00332         }
00333 }
00334 
00338 class DBUnexpectedError extends DBError {}