MediaWiki  REL1_22
DatabaseError.php
Go to the documentation of this file.
00001 <?php
00028 class DBError extends MWException {
00029 
00033     public $db;
00034 
00040     function __construct( DatabaseBase $db = null, $error ) {
00041         $this->db = $db;
00042         parent::__construct( $error );
00043     }
00044 
00048     function getText() {
00049         global $wgShowDBErrorBacktrace;
00050 
00051         $s = $this->getTextContent() . "\n";
00052 
00053         if ( $wgShowDBErrorBacktrace ) {
00054             $s .= "Backtrace:\n" . $this->getTraceAsString() . "\n";
00055         }
00056 
00057         return $s;
00058     }
00059 
00063     function getHTML() {
00064         global $wgShowDBErrorBacktrace;
00065 
00066         $s = $this->getHTMLContent();
00067 
00068         if ( $wgShowDBErrorBacktrace ) {
00069             $s .= '<p>Backtrace:</p><p>' .
00070                 nl2br( htmlspecialchars( $this->getTraceAsString() ) ) . '</p>';
00071         }
00072 
00073         return $s;
00074     }
00075 
00079     protected function getTextContent() {
00080         return $this->getMessage();
00081     }
00082 
00086     protected function getHTMLContent() {
00087         return '<p>' . nl2br( htmlspecialchars( $this->getMessage() ) ) . '</p>';
00088     }
00089 }
00090 
00094 class DBConnectionError extends DBError {
00095     public $error;
00096 
00097     function __construct( DatabaseBase $db = null, $error = 'unknown error' ) {
00098         $msg = 'DB connection error';
00099 
00100         if ( trim( $error ) != '' ) {
00101             $msg .= ": $error";
00102         } elseif ( $db ) {
00103             $error = $this->db->getServer();
00104         }
00105 
00106         parent::__construct( $db, $msg );
00107         $this->error = $error;
00108     }
00109 
00113     function useOutputPage() {
00114         // Not likely to work
00115         return false;
00116     }
00117 
00123     function msg( $key, $fallback /*[, params...] */ ) {
00124         global $wgLang;
00125 
00126         $args = array_slice( func_get_args(), 2 );
00127 
00128         if ( $this->useMessageCache() ) {
00129             $message = $wgLang->getMessage( $key );
00130         } else {
00131             $message = $fallback;
00132         }
00133         return wfMsgReplaceArgs( $message, $args );
00134     }
00135 
00139     function isLoggable() {
00140         // Don't send to the exception log, already in dberror log
00141         return false;
00142     }
00143 
00147     function getPageTitle() {
00148         return $this->msg( 'dberr-header', 'This wiki has a problem' );
00149     }
00150 
00154     function getHTML() {
00155         global $wgShowDBErrorBacktrace, $wgShowHostnames, $wgShowSQLErrors;
00156 
00157         $sorry = htmlspecialchars( $this->msg( 'dberr-problems', "Sorry!\nThis site is experiencing technical difficulties." ) );
00158         $again = htmlspecialchars( $this->msg( 'dberr-again', 'Try waiting a few minutes and reloading.' ) );
00159 
00160         if ( $wgShowHostnames || $wgShowSQLErrors ) {
00161             $info = str_replace(
00162                 '$1', Html::element( 'span', array( 'dir' => 'ltr' ), $this->error ),
00163                 htmlspecialchars( $this->msg( 'dberr-info', '(Cannot contact the database server: $1)' ) )
00164             );
00165         } else {
00166             $info = htmlspecialchars( $this->msg( 'dberr-info-hidden', '(Cannot contact the database server)' ) );
00167         }
00168 
00169         # No database access
00170         MessageCache::singleton()->disable();
00171 
00172         $text = "<h1>$sorry</h1><p>$again</p><p><small>$info</small></p>";
00173 
00174         if ( $wgShowDBErrorBacktrace ) {
00175             $text .= '<p>Backtrace:</p><p>' .
00176                 nl2br( htmlspecialchars( $this->getTraceAsString() ) ) . '</p>';
00177         }
00178 
00179         $text .= '<hr />';
00180         $text .= $this->searchForm();
00181 
00182         return $text;
00183     }
00184 
00185     protected function getTextContent() {
00186         global $wgShowHostnames, $wgShowSQLErrors;
00187 
00188         if ( $wgShowHostnames || $wgShowSQLErrors ) {
00189             return $this->getMessage();
00190         } else {
00191             return 'DB connection error';
00192         }
00193     }
00194 
00195     public function reportHTML() {
00196         global $wgUseFileCache;
00197 
00198         # Check whether we can serve a file-cached copy of the page with the error underneath
00199         if ( $wgUseFileCache ) {
00200             try {
00201                 $cache = $this->fileCachedPage();
00202                 # Cached version on file system?
00203                 if ( $cache !== null ) {
00204                     # Hack: extend the body for error messages
00205                     $cache = str_replace( array( '</html>', '</body>' ), '', $cache );
00206                     # Add cache notice...
00207                     $cache .= '<div style="color:red;font-size:150%;font-weight:bold;">' .
00208                         htmlspecialchars( $this->msg( 'dberr-cachederror',
00209                             'This is a cached copy of the requested page, and may not be up to date. ' ) ) .
00210                         '</div>';
00211 
00212                     # Output cached page with notices on bottom and re-close body
00213                     echo "{$cache}<hr />{$this->getHTML()}</body></html>";
00214                     return;
00215                 }
00216             } catch ( MWException $e ) {
00217                 // Do nothing, just use the default page
00218             }
00219         }
00220 
00221         # We can't, cough and die in the usual fashion
00222         parent::reportHTML();
00223     }
00224 
00228     function searchForm() {
00229         global $wgSitename, $wgCanonicalServer, $wgRequest;
00230 
00231         $usegoogle = htmlspecialchars( $this->msg( 'dberr-usegoogle', 'You can try searching via Google in the meantime.' ) );
00232         $outofdate = htmlspecialchars( $this->msg( 'dberr-outofdate', 'Note that their indexes of our content may be out of date.' ) );
00233         $googlesearch = htmlspecialchars( $this->msg( 'searchbutton', 'Search' ) );
00234 
00235         $search = htmlspecialchars( $wgRequest->getVal( 'search' ) );
00236 
00237         $server = htmlspecialchars( $wgCanonicalServer );
00238         $sitename = htmlspecialchars( $wgSitename );
00239 
00240         $trygoogle = <<<EOT
00241 <div style="margin: 1.5em">$usegoogle<br />
00242 <small>$outofdate</small></div>
00243 <!-- SiteSearch Google -->
00244 <form method="get" action="//www.google.com/search" id="googlesearch">
00245     <input type="hidden" name="domains" value="$server" />
00246     <input type="hidden" name="num" value="50" />
00247     <input type="hidden" name="ie" value="UTF-8" />
00248     <input type="hidden" name="oe" value="UTF-8" />
00249 
00250     <input type="text" name="q" size="31" maxlength="255" value="$search" />
00251     <input type="submit" name="btnG" value="$googlesearch" />
00252   <div>
00253     <input type="radio" name="sitesearch" id="gwiki" value="$server" checked="checked" /><label for="gwiki">$sitename</label>
00254     <input type="radio" name="sitesearch" id="gWWW" value="" /><label for="gWWW">WWW</label>
00255   </div>
00256 </form>
00257 <!-- SiteSearch Google -->
00258 EOT;
00259         return $trygoogle;
00260     }
00261 
00265     private function fileCachedPage() {
00266         global $wgTitle, $wgOut, $wgRequest;
00267 
00268         if ( $wgOut->isDisabled() ) {
00269             return ''; // Done already?
00270         }
00271 
00272         if ( $wgTitle ) { // use $wgTitle if we managed to set it
00273             $t = $wgTitle->getPrefixedDBkey();
00274         } else {
00275             # Fallback to the raw title URL param. We can't use the Title
00276             # class is it may hit the interwiki table and give a DB error.
00277             # We may get a cache miss due to not sanitizing the title though.
00278             $t = str_replace( ' ', '_', $wgRequest->getVal( 'title' ) );
00279             if ( $t == '' ) { // fallback to main page
00280                 $t = Title::newFromText(
00281                     $this->msg( 'mainpage', 'Main Page' ) )->getPrefixedDBkey();
00282             }
00283         }
00284 
00285         $cache = HTMLFileCache::newFromTitle( $t, 'view' );
00286         if ( $cache->isCached() ) {
00287             return $cache->fetchText();
00288         } else {
00289             return '';
00290         }
00291     }
00292 }
00293 
00297 class DBQueryError extends DBError {
00298     public $error, $errno, $sql, $fname;
00299 
00307     function __construct( DatabaseBase $db, $error, $errno, $sql, $fname ) {
00308         $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" .
00309             "Query: $sql\n" .
00310             "Function: $fname\n" .
00311             "Error: $errno $error\n";
00312         parent::__construct( $db, $message );
00313 
00314         $this->error = $error;
00315         $this->errno = $errno;
00316         $this->sql = $sql;
00317         $this->fname = $fname;
00318     }
00319 
00323     function isLoggable() {
00324         // Don't send to the exception log, already in dberror log
00325         return false;
00326     }
00327 
00331     function getPageTitle() {
00332         return $this->msg( 'databaseerror', 'Database error' );
00333     }
00334 
00338     protected function getHTMLContent() {
00339         $key = 'databaseerror-text';
00340         $s = Html::element( 'p', array(), $this->msg( $key, $this->getFallbackMessage( $key ) ) );
00341 
00342         $details = $this->getTechnicalDetails();
00343         if ( $details ) {
00344             $s .= '<ul>';
00345             foreach ( $details as $key => $detail ) {
00346                 $s .= str_replace(
00347                     '$1', call_user_func_array( 'Html::element', $detail ),
00348                     Html::element( 'li', array(),
00349                         $this->msg( $key, $this->getFallbackMessage( $key ) )
00350                     )
00351                 );
00352             }
00353             $s .= '</ul>';
00354         }
00355 
00356         return $s;
00357     }
00358 
00362     protected function getTextContent() {
00363         $key = 'databaseerror-textcl';
00364         $s = $this->msg( $key, $this->getFallbackMessage( $key ) ) . "\n";
00365 
00366         foreach ( $this->getTechnicalDetails() as $key => $detail ) {
00367             $s .= $this->msg( $key, $this->getFallbackMessage( $key ), $detail[2] ) . "\n";
00368         }
00369 
00370         return $s;
00371     }
00372 
00386     protected function getTechnicalDetails() {
00387         global $wgShowHostnames, $wgShowSQLErrors;
00388 
00389         $attribs = array( 'dir' => 'ltr' );
00390         $details = array();
00391 
00392         if ( $wgShowSQLErrors ) {
00393             $details['databaseerror-query'] = array(
00394                 'div', array( 'class' => 'mw-code' ) + $attribs, $this->sql );
00395         }
00396 
00397         if ( $wgShowHostnames || $wgShowSQLErrors ) {
00398             $errorMessage = $this->errno . ' ' . $this->error;
00399             $details['databaseerror-function'] = array( 'code', $attribs, $this->fname );
00400             $details['databaseerror-error'] = array( 'samp', $attribs, $errorMessage );
00401         }
00402 
00403         return $details;
00404     }
00405 
00410     private function getFallbackMessage( $key ) {
00411         $messages = array(
00412             'databaseerror-text' => 'A database query error has occurred.
00413 This may indicate a bug in the software.',
00414             'databaseerror-textcl' => 'A database query error has occurred.',
00415             'databaseerror-query' => 'Query: $1',
00416             'databaseerror-function' => 'Function: $1',
00417             'databaseerror-error' => 'Error: $1',
00418         );
00419         return $messages[$key];
00420     }
00421 
00422 }
00423 
00427 class DBUnexpectedError extends DBError {}