* (T206976, T206977) Also in the bundled LocalisationUpdate and ParserFunctions extensions.
* (T206979) Fix PHP 7.3 warnings of using "compact()" when some variables may
not be set.
- * Fix PHP 7.3 warnings "preg_replace(): [...] invalid range in character class"
+ * (T215632) FormatMetadata and UploadStash regexes fixed to be PHP 7.3-compatible.
* Avoid PHP 7.2 warnings in DBConRefTest about count() on non-Countable
* Suppress "Headers already sent" in PHP 7.2 too
* (T206476) Output only to stderr in unit tests
* (T207112) Add session_write_close() calls to SessionManager tests
* oyejorge/less.php replaced with our fork wikimedia/less.php
* (T209756) Updated wikimedia/ip-set from 1.2.0 to 1.3.0.
+ * (T213489) Avoid session double-start in Setup.php.
* (T207540) Include IP address in "Login for $1 succeeded" log entry.
* (T201781) Database: Allow selectFieldValues() to accept SQL fragments
* (T205765) installer: Don't link to the obsolete "Extension Matrix" page
if --lang is used with the command-line installer (install.php).
* Fix addition of ug_expiry column to user_groups table on MSSQL.
* (T204767) Add join conditions to ActiveUsersPager
+* (T210621) User: Bypass repeatable-read when creating an actor_id.
+* (T204531) rdbms: reduce LoadBalancer replication log spam.
+* (T195525) Fix db error outage page.
+* (T208871) The hard-coded Google search form on the database error page was
+ removed.
== MediaWiki 1.31.1 ==
$session->renew();
if ( MediaWiki\Session\PHPSessionHandler::isEnabled() &&
- ( $session->isPersistent() || $session->shouldRememberUser() )
+ ( $session->isPersistent() || $session->shouldRememberUser() ) &&
+ session_id() !== $session->getId()
) {
// Start the PHP-session for backwards compatibility
+ if ( session_id() !== '' ) {
+ wfDebugLog( 'session', 'PHP session {old_id} was already started, changing to {new_id}', 'all', [
+ 'old_id' => session_id(),
+ 'new_id' => $session->getId(),
+ ] );
+ session_write_close();
+ }
session_id( $session->getId() );
- Wikimedia\quietCall( 'session_start' );
+ session_start();
}
unset( $session );
self::printError( self::getText( $e ) );
} elseif ( $mode === self::AS_PRETTY ) {
self::statusHeader( 500 );
+ self::header( "Content-Type: $wgMimeType; charset=utf-8" );
if ( $e instanceof DBConnectionError ) {
self::reportOutageHTML( $e );
} else {
- self::header( "Content-Type: $wgMimeType; charset=utf-8" );
self::reportHTML( $e );
}
} else {
+ self::statusHeader( 500 );
+ self::header( "Content-Type: $wgMimeType; charset=utf-8" );
if ( $eNew ) {
$message = "MediaWiki internal error.\n\n";
if ( self::showBackTrace( $e ) ) {
* @param Exception|Throwable $e
*/
private static function reportOutageHTML( $e ) {
- global $wgShowDBErrorBacktrace, $wgShowHostnames, $wgShowSQLErrors;
+ global $wgShowDBErrorBacktrace, $wgShowHostnames, $wgShowSQLErrors, $wgSitename;
$sorry = htmlspecialchars( self::msg(
'dberr-problems',
}
MessageCache::singleton()->disable(); // no DB access
-
- $html = "<h1>$sorry</h1><p>$again</p><p><small>$info</small></p>";
+ $html = "<!DOCTYPE html>\n" .
+ '<html><head>' .
+ '<title>' .
+ htmlspecialchars( $wgSitename ) .
+ '</title>' .
+ '<style>body { font-family: sans-serif; margin: 0; padding: 0.5em 2em; }</style>' .
+ "</head><body><h1>$sorry</h1><p>$again</p><p><small>$info</small></p>";
if ( $wgShowDBErrorBacktrace ) {
$html .= '<p>Backtrace:</p><pre>' .
htmlspecialchars( $e->getTraceAsString() ) . '</pre>';
}
- $html .= '<hr />';
- $html .= self::googleSearchForm();
-
+ $html .= '</body></html>';
echo $html;
}
-
- /**
- * @return string
- */
- private static function googleSearchForm() {
- global $wgSitename, $wgCanonicalServer, $wgRequest;
-
- $usegoogle = htmlspecialchars( self::msg(
- 'dberr-usegoogle',
- 'You can try searching via Google in the meantime.'
- ) );
- $outofdate = htmlspecialchars( self::msg(
- 'dberr-outofdate',
- 'Note that their indexes of our content may be out of date.'
- ) );
- $googlesearch = htmlspecialchars( self::msg( 'searchbutton', 'Search' ) );
- $search = htmlspecialchars( $wgRequest->getVal( 'search' ) );
- $server = htmlspecialchars( $wgCanonicalServer );
- $sitename = htmlspecialchars( $wgSitename );
- $trygoogle = <<<EOT
-<div style="margin: 1.5em">$usegoogle<br />
-<small>$outofdate</small>
-</div>
-<form method="get" action="//www.google.com/search" id="googlesearch">
- <input type="hidden" name="domains" value="$server" />
- <input type="hidden" name="num" value="50" />
- <input type="hidden" name="ie" value="UTF-8" />
- <input type="hidden" name="oe" value="UTF-8" />
- <input type="text" name="q" size="31" maxlength="255" value="$search" />
- <input type="submit" name="btnG" value="$googlesearch" />
- <p>
- <label><input type="radio" name="sitesearch" value="$server" checked="checked" />$sitename</label>
- <label><input type="radio" name="sitesearch" value="" />WWW</label>
- </p>
-</form>
-EOT;
- return $trygoogle;
- }
}
": server {host} is not replicating?", [ 'host' => $host ] );
unset( $loads[$i] );
} elseif ( $lag > $maxServerLag ) {
- $this->replLogger->info(
+ $this->replLogger->debug(
__METHOD__ .
": server {host} has {lag} seconds of lag (>= {maxlag})",
[ 'host' => $host, 'lag' => $lag, 'maxlag' => $maxServerLag ]
$this->mActorId = (int)$dbw->insertId();
} else {
// Outdated cache?
- list( , $options ) = DBAccessObjectUtils::getDBOptions( $this->queryFlagsUsed );
- $this->mActorId = (int)$dbw->selectField( 'actor', 'actor_id', $q, __METHOD__, $options );
+ // Use LOCK IN SHARE MODE to bypass any MySQL REPEATABLE-READ snapshot.
+ $this->mActorId = (int)$dbw->selectField(
+ 'actor',
+ 'actor_id',
+ $q,
+ __METHOD__,
+ [ 'LOCK IN SHARE MODE' ]
+ );
if ( !$this->mActorId ) {
throw new CannotCreateActorException(
"Cannot create actor ID for user_id={$this->getId()} user_name={$this->getName()}"
"dberr-again": "Try waiting a few minutes and reloading.",
"dberr-info": "(Cannot access the database: $1)",
"dberr-info-hidden": "(Cannot access the database)",
- "dberr-usegoogle": "You can try searching via Google in the meantime.",
- "dberr-outofdate": "Note that their indexes of our content may be out of date.",
- "dberr-cachederror": "This is a cached copy of the requested page, and may not be up to date.",
"htmlform-invalid-input": "There are problems with some of your input.",
"htmlform-select-badoption": "The value you specified is not a valid option.",
"htmlform-int-invalid": "The value you specified is not an integer.",
"dberr-again": "This message does not allow any wiki nor html markup.",
"dberr-info": "This message does not allow any wiki nor html markup. Parameters:\n* $1 - database server name\nSee also:\n* {{msg-mw|Dberr-info-hidden}} - hides database server name",
"dberr-info-hidden": "This message does not allow any wiki nor html markup.\n\nSee also:\n* {{msg-mw|Dberr-info}} - shows database server name",
- "dberr-usegoogle": "This message does not allow any wiki nor html markup.",
- "dberr-outofdate": "{{doc-singularthey}}\nIn this sentence, '''their''' indexes refers to '''Google's''' indexes. This message does not allow any wiki nor html markup.",
- "dberr-cachederror": "Used as error message at the bottom of the page.",
"htmlform-invalid-input": "Used as error message in HTML forms.\n\n* {{msg-mw|Htmlform-required}}\n* {{msg-mw|Htmlform-float-invalid}}\n* {{msg-mw|Htmlform-int-invalid}}\n* {{msg-mw|Htmlform-int-toolow}}\n* {{msg-mw|Htmlform-int-toohigh}}\n* {{msg-mw|Htmlform-select-badoption}}",
"htmlform-select-badoption": "Used as error message in HTML forms.\n\n* {{msg-mw|Htmlform-invalid-input}}\n* {{msg-mw|Htmlform-required}}\n* {{msg-mw|Htmlform-float-invalid}}\n* {{msg-mw|Htmlform-int-invalid}}\n* {{msg-mw|Htmlform-int-toolow}}\n* {{msg-mw|Htmlform-int-toohigh}}",
"htmlform-int-invalid": "Used as error message in HTML forms.\n\n* {{msg-mw|Htmlform-invalid-input}}\n* {{msg-mw|Htmlform-required}}\n* {{msg-mw|Htmlform-float-invalid}}\n* {{msg-mw|Htmlform-int-toolow}}\n* {{msg-mw|Htmlform-int-toohigh}}\n* {{msg-mw|Htmlform-select-badoption}}",