MediaWiki
REL1_24
|
00001 <?php 00028 class DBError extends MWException { 00030 public $db; 00031 00037 function __construct( DatabaseBase $db = null, $error ) { 00038 $this->db = $db; 00039 parent::__construct( $error ); 00040 } 00041 } 00042 00050 class DBExpectedError extends DBError { 00054 function getText() { 00055 global $wgShowDBErrorBacktrace; 00056 00057 $s = $this->getTextContent() . "\n"; 00058 00059 if ( $wgShowDBErrorBacktrace ) { 00060 $s .= "Backtrace:\n" . $this->getTraceAsString() . "\n"; 00061 } 00062 00063 return $s; 00064 } 00065 00069 function getHTML() { 00070 global $wgShowDBErrorBacktrace; 00071 00072 $s = $this->getHTMLContent(); 00073 00074 if ( $wgShowDBErrorBacktrace ) { 00075 $s .= '<p>Backtrace:</p><pre>' . htmlspecialchars( $this->getTraceAsString() ) . '</pre>'; 00076 } 00077 00078 return $s; 00079 } 00080 00084 protected function getTextContent() { 00085 return $this->getMessage(); 00086 } 00087 00091 protected function getHTMLContent() { 00092 return '<p>' . nl2br( htmlspecialchars( $this->getTextContent() ) ) . '</p>'; 00093 } 00094 } 00095 00099 class DBConnectionError extends DBExpectedError { 00101 public $error; 00102 00107 function __construct( DatabaseBase $db = null, $error = 'unknown error' ) { 00108 $msg = 'DB connection error'; 00109 00110 if ( trim( $error ) != '' ) { 00111 $msg .= ": $error"; 00112 } elseif ( $db ) { 00113 $error = $this->db->getServer(); 00114 } 00115 00116 parent::__construct( $db, $msg ); 00117 $this->error = $error; 00118 } 00119 00123 function useOutputPage() { 00124 // Not likely to work 00125 return false; 00126 } 00127 00135 function msg( $key, $fallback /*[, params...] */ ) { 00136 $args = array_slice( func_get_args(), 2 ); 00137 00138 if ( $this->useMessageCache() ) { 00139 return wfMessage( $key, $args )->useDatabase( false )->text(); 00140 } else { 00141 return wfMsgReplaceArgs( $fallback, $args ); 00142 } 00143 } 00144 00148 function isLoggable() { 00149 // Don't send to the exception log, already in dberror log 00150 return false; 00151 } 00152 00156 function getHTML() { 00157 global $wgShowDBErrorBacktrace, $wgShowHostnames, $wgShowSQLErrors; 00158 00159 $sorry = htmlspecialchars( $this->msg( 00160 'dberr-problems', 00161 'Sorry! This site is experiencing technical difficulties.' 00162 ) ); 00163 $again = htmlspecialchars( $this->msg( 00164 'dberr-again', 00165 'Try waiting a few minutes and reloading.' 00166 ) ); 00167 00168 if ( $wgShowHostnames || $wgShowSQLErrors ) { 00169 $info = str_replace( 00170 '$1', Html::element( 'span', array( 'dir' => 'ltr' ), $this->error ), 00171 htmlspecialchars( $this->msg( 'dberr-info', '(Cannot contact the database server: $1)' ) ) 00172 ); 00173 } else { 00174 $info = htmlspecialchars( $this->msg( 00175 'dberr-info-hidden', 00176 '(Cannot contact the database server)' 00177 ) ); 00178 } 00179 00180 # No database access 00181 MessageCache::singleton()->disable(); 00182 00183 $html = "<h1>$sorry</h1><p>$again</p><p><small>$info</small></p>"; 00184 00185 if ( $wgShowDBErrorBacktrace ) { 00186 $html .= '<p>Backtrace:</p><pre>' . htmlspecialchars( $this->getTraceAsString() ) . '</pre>'; 00187 } 00188 00189 $html .= '<hr />'; 00190 $html .= $this->searchForm(); 00191 00192 return $html; 00193 } 00194 00195 protected function getTextContent() { 00196 global $wgShowHostnames, $wgShowSQLErrors; 00197 00198 if ( $wgShowHostnames || $wgShowSQLErrors ) { 00199 return $this->getMessage(); 00200 } else { 00201 return 'DB connection error'; 00202 } 00203 } 00204 00210 public function reportHTML() { 00211 global $wgUseFileCache; 00212 00213 // Check whether we can serve a file-cached copy of the page with the error underneath 00214 if ( $wgUseFileCache ) { 00215 try { 00216 $cache = $this->fileCachedPage(); 00217 // Cached version on file system? 00218 if ( $cache !== null ) { 00219 // Hack: extend the body for error messages 00220 $cache = str_replace( array( '</html>', '</body>' ), '', $cache ); 00221 // Add cache notice... 00222 $cache .= '<div style="border:1px solid #ffd0d0;padding:1em;">' . 00223 htmlspecialchars( $this->msg( 'dberr-cachederror', 00224 'This is a cached copy of the requested page, and may not be up to date.' ) ) . 00225 '</div>'; 00226 00227 // Output cached page with notices on bottom and re-close body 00228 echo "{$cache}<hr />{$this->getHTML()}</body></html>"; 00229 00230 return; 00231 } 00232 } catch ( MWException $e ) { 00233 // Do nothing, just use the default page 00234 } 00235 } 00236 00237 // We can't, cough and die in the usual fashion 00238 parent::reportHTML(); 00239 } 00240 00244 function searchForm() { 00245 global $wgSitename, $wgCanonicalServer, $wgRequest; 00246 00247 $usegoogle = htmlspecialchars( $this->msg( 00248 'dberr-usegoogle', 00249 'You can try searching via Google in the meantime.' 00250 ) ); 00251 $outofdate = htmlspecialchars( $this->msg( 00252 'dberr-outofdate', 00253 'Note that their indexes of our content may be out of date.' 00254 ) ); 00255 $googlesearch = htmlspecialchars( $this->msg( 'searchbutton', 'Search' ) ); 00256 00257 $search = htmlspecialchars( $wgRequest->getVal( 'search' ) ); 00258 00259 $server = htmlspecialchars( $wgCanonicalServer ); 00260 $sitename = htmlspecialchars( $wgSitename ); 00261 00262 $trygoogle = <<<EOT 00263 <div style="margin: 1.5em">$usegoogle<br /> 00264 <small>$outofdate</small> 00265 </div> 00266 <form method="get" action="//www.google.com/search" id="googlesearch"> 00267 <input type="hidden" name="domains" value="$server" /> 00268 <input type="hidden" name="num" value="50" /> 00269 <input type="hidden" name="ie" value="UTF-8" /> 00270 <input type="hidden" name="oe" value="UTF-8" /> 00271 00272 <input type="text" name="q" size="31" maxlength="255" value="$search" /> 00273 <input type="submit" name="btnG" value="$googlesearch" /> 00274 <p> 00275 <label><input type="radio" name="sitesearch" value="$server" checked="checked" />$sitename</label> 00276 <label><input type="radio" name="sitesearch" value="" />WWW</label> 00277 </p> 00278 </form> 00279 EOT; 00280 00281 return $trygoogle; 00282 } 00283 00287 private function fileCachedPage() { 00288 $context = RequestContext::getMain(); 00289 00290 if ( $context->getOutput()->isDisabled() ) { 00291 // Done already? 00292 return ''; 00293 } 00294 00295 if ( $context->getTitle() ) { 00296 // Use the main context's title if we managed to set it 00297 $t = $context->getTitle()->getPrefixedDBkey(); 00298 } else { 00299 // Fallback to the raw title URL param. We can't use the Title 00300 // class is it may hit the interwiki table and give a DB error. 00301 // We may get a cache miss due to not sanitizing the title though. 00302 $t = str_replace( ' ', '_', $context->getRequest()->getVal( 'title' ) ); 00303 if ( $t == '' ) { // fallback to main page 00304 $t = Title::newFromText( 00305 $this->msg( 'mainpage', 'Main Page' ) )->getPrefixedDBkey(); 00306 } 00307 } 00308 00309 $cache = new HTMLFileCache( $t, 'view' ); 00310 if ( $cache->isCached() ) { 00311 return $cache->fetchText(); 00312 } else { 00313 return ''; 00314 } 00315 } 00316 } 00317 00321 class DBQueryError extends DBExpectedError { 00322 public $error, $errno, $sql, $fname; 00323 00331 function __construct( DatabaseBase $db, $error, $errno, $sql, $fname ) { 00332 $message = "A database error has occurred. Did you forget to run " . 00333 "maintenance/update.php after upgrading? See: " . 00334 "https://www.mediawiki.org/wiki/Manual:Upgrading#Run_the_update_script\n" . 00335 "Query: $sql\n" . 00336 "Function: $fname\n" . 00337 "Error: $errno $error\n"; 00338 parent::__construct( $db, $message ); 00339 00340 $this->error = $error; 00341 $this->errno = $errno; 00342 $this->sql = $sql; 00343 $this->fname = $fname; 00344 } 00345 00349 function getPageTitle() { 00350 return $this->msg( 'databaseerror', 'Database error' ); 00351 } 00352 00356 protected function getHTMLContent() { 00357 $key = 'databaseerror-text'; 00358 $s = Html::element( 'p', array(), $this->msg( $key, $this->getFallbackMessage( $key ) ) ); 00359 00360 $details = $this->getTechnicalDetails(); 00361 if ( $details ) { 00362 $s .= '<ul>'; 00363 foreach ( $details as $key => $detail ) { 00364 $s .= str_replace( 00365 '$1', call_user_func_array( 'Html::element', $detail ), 00366 Html::element( 'li', array(), 00367 $this->msg( $key, $this->getFallbackMessage( $key ) ) 00368 ) 00369 ); 00370 } 00371 $s .= '</ul>'; 00372 } 00373 00374 return $s; 00375 } 00376 00380 protected function getTextContent() { 00381 $key = 'databaseerror-textcl'; 00382 $s = $this->msg( $key, $this->getFallbackMessage( $key ) ) . "\n"; 00383 00384 foreach ( $this->getTechnicalDetails() as $key => $detail ) { 00385 $s .= $this->msg( $key, $this->getFallbackMessage( $key ), $detail[2] ) . "\n"; 00386 } 00387 00388 return $s; 00389 } 00390 00404 protected function getTechnicalDetails() { 00405 global $wgShowHostnames, $wgShowSQLErrors; 00406 00407 $attribs = array( 'dir' => 'ltr' ); 00408 $details = array(); 00409 00410 if ( $wgShowSQLErrors ) { 00411 $details['databaseerror-query'] = array( 00412 'div', array( 'class' => 'mw-code' ) + $attribs, $this->sql ); 00413 } 00414 00415 if ( $wgShowHostnames || $wgShowSQLErrors ) { 00416 $errorMessage = $this->errno . ' ' . $this->error; 00417 $details['databaseerror-function'] = array( 'code', $attribs, $this->fname ); 00418 $details['databaseerror-error'] = array( 'samp', $attribs, $errorMessage ); 00419 } 00420 00421 return $details; 00422 } 00423 00428 private function getFallbackMessage( $key ) { 00429 $messages = array( 00430 'databaseerror-text' => 'A database query error has occurred. 00431 This may indicate a bug in the software.', 00432 'databaseerror-textcl' => 'A database query error has occurred.', 00433 'databaseerror-query' => 'Query: $1', 00434 'databaseerror-function' => 'Function: $1', 00435 'databaseerror-error' => 'Error: $1', 00436 ); 00437 00438 return $messages[$key]; 00439 } 00440 } 00441 00445 class DBUnexpectedError extends DBError { 00446 }