production anymore. There is now $wgUseKeyHeader that provides similar
functionality but instead of the MediaWiki-specific X-Vary-Options header,
uses the draft Key header standard.
+* $wgScriptExtension (and support for '.php5' entry points) was removed. See the
+ deprecation notice in the release notes for version 1.25 for advice on how to
+ preserve support for '.php5' entry points via URL rewriting.
=== New features in 1.27 ===
* $wgDataCenterId and $wgDataCenterRoles where added, which will serve as
+++ /dev/null
-<?php
-/**
- * Version of api.php to be used in web servers that require the .php5
- * extension to execute scripts with the PHP5 engine.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-define( 'MW_ENTRY_PHP5', true );
-
-require './api.php';
'SqliteInstaller' => __DIR__ . '/includes/installer/SqliteInstaller.php',
'SqliteMaintenance' => __DIR__ . '/maintenance/sqlite.php',
'SqliteUpdater' => __DIR__ . '/includes/installer/SqliteUpdater.php',
- 'SquidPurgeClient' => __DIR__ . '/includes/SquidPurgeClient.php',
- 'SquidPurgeClientPool' => __DIR__ . '/includes/SquidPurgeClient.php',
+ 'SquidPurgeClient' => __DIR__ . '/includes/clientpool/SquidPurgeClient.php',
+ 'SquidPurgeClientPool' => __DIR__ . '/includes/clientpool/SquidPurgeClientPool.php',
'SquidUpdate' => __DIR__ . '/includes/deferred/SquidUpdate.php',
'SrConverter' => __DIR__ . '/languages/classes/LanguageSr.php',
'StatsOutput' => __DIR__ . '/maintenance/language/StatOutputs.php',
+++ /dev/null
-<?php
-/**
- * Version of img_auth.php to be used in web servers that require the .php5
- * extension to execute scripts with the PHP5 engine.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-define( 'MW_ENTRY_PHP5', true );
-
-require './img_auth.php';
* This variable was provided to support those providers.
*
* @since 1.11
- * @deprecated since 1.25; support for '.php5' is being phased out of MediaWiki
+ * @deprecated since 1.25; support for '.php5' has been phased out of MediaWiki
* proper. Backward-compatibility can be maintained by configuring your web
* server to rewrite URLs. See RELEASE-NOTES for details.
*/
/**
* The URL path to index.php.
*
- * Defaults to "{$wgScriptPath}/index{$wgScriptExtension}".
+ * Defaults to "{$wgScriptPath}/index.php".
*/
$wgScript = false;
/**
* The URL path to load.php.
*
- * Defaults to "{$wgScriptPath}/load{$wgScriptExtension}".
+ * Defaults to "{$wgScriptPath}/load.php".
* @since 1.17
*/
$wgLoadScript = false;
* - scriptDirUrl URL of the MediaWiki installation, equivalent to $wgScriptPath, e.g.
* https://en.wikipedia.org/w
* - scriptExtension Script extension of the MediaWiki installation, equivalent to
- * $wgScriptExtension, e.g. .php5 defaults to .php
+ * $wgScriptExtension, e.g. ".php5". Defaults to ".php".
*
* - articleUrl Equivalent to $wgArticlePath, e.g. https://en.wikipedia.org/wiki/$1
* - fetchDescription Fetch the text of the remote file description page. Equivalent to
*
* @par Example:
* @code
- * $wgThumbnailScriptPath = "{$wgScriptPath}/thumb{$wgScriptExtension}";
+ * $wgThumbnailScriptPath = "{$wgScriptPath}/thumb.php";
* @endcode
*/
$wgThumbnailScriptPath = false;
return $status;
}
- $flags = EDIT_DEFER_UPDATES | EDIT_AUTOSUMMARY |
+ $flags = EDIT_AUTOSUMMARY |
( $new ? EDIT_NEW : EDIT_UPDATE ) |
( ( $this->minoredit && !$this->isNew ) ? EDIT_MINOR : 0 ) |
( $bot ? EDIT_FORCE_BOT : 0 );
/**
* Get the path to a specified script file, respecting file
- * extensions; this is a wrapper around $wgScriptExtension etc.
+ * extensions; this is a wrapper around $wgScriptPath etc.
* except for 'index' and 'load' which use $wgScript/$wgLoadScript
*
* @param string $script Script filename, sans extension
* @return string
*/
function wfScript( $script = 'index' ) {
- global $wgScriptPath, $wgScriptExtension, $wgScript, $wgLoadScript;
+ global $wgScriptPath, $wgScript, $wgLoadScript;
if ( $script === 'index' ) {
return $wgScript;
} elseif ( $script === 'load' ) {
return $wgLoadScript;
} else {
- return "{$wgScriptPath}/{$script}{$wgScriptExtension}";
+ return "{$wgScriptPath}/{$script}.php";
}
}
Profiler::instance()->getTransactionProfiler()->resetExpectations();
// Do any deferred jobs
- DeferredUpdates::doUpdates( 'commit' );
+ DeferredUpdates::doUpdates( 'commit', 'enqueue' );
// Make sure any lazy jobs are pushed
JobQueueGroup::pushLazyJobs();
*
* @since 1.17
*
- * @param mixed $params,... Parameters as strings, or a single argument that is
+ * @param mixed ... Parameters as strings, or a single argument that is
* an array of strings.
*
* @return Message $this
function haveCacheVaryCookies() {
$request = $this->getRequest();
foreach ( $this->getCacheVaryCookies() as $cookieName ) {
- if ( $request->getCookie( $cookieName, '' ) ) {
+ if ( $request->getCookie( $cookieName, '', '' ) !== '' ) {
wfDebug( __METHOD__ . ": found $cookieName\n" );
return true;
}
* @return bool
*/
public function userCanPreview() {
- if ( $this->getRequest()->getVal( 'action' ) != 'submit'
- || !$this->getRequest()->wasPosted()
- || !$this->getUser()->matchEditToken(
- $this->getRequest()->getVal( 'wpEditToken' ) )
- ) {
+ $request = $this->getRequest();
+ if ( $request->getVal( 'action' ) !== 'submit' || !$request->wasPosted() ) {
+ return false;
+ }
+
+ $user = $this->getUser();
+ if ( !$user->matchEditToken( $request->getVal( 'wpEditToken' ) ) ) {
return false;
}
- if ( !$this->getTitle()->isJsSubpage() && !$this->getTitle()->isCssSubpage() ) {
+
+ $title = $this->getTitle();
+ if ( !$title->isJsSubpage() && !$title->isCssSubpage() ) {
return false;
}
- if ( !$this->getTitle()->isSubpageOf( $this->getUser()->getUserPage() ) ) {
+ if ( !$title->isSubpageOf( $user->getUserPage() ) ) {
// Don't execute another user's CSS or JS on preview (T85855)
return false;
}
- return !count( $this->getTitle()->getUserPermissionsErrors( 'edit', $this->getUser() ) );
+ $errors = $title->getUserPermissionsErrors( 'edit', $user );
+ if ( count( $errors ) !== 0 ) {
+ return false;
+ }
+
+ return true;
}
/**
$ps_default = Profiler::instance()->scopedProfileIn( $fname . '-defaults' );
if ( $wgScript === false ) {
- $wgScript = "$wgScriptPath/index$wgScriptExtension";
+ $wgScript = "$wgScriptPath/index.php";
}
if ( $wgLoadScript === false ) {
- $wgLoadScript = "$wgScriptPath/load$wgScriptExtension";
+ $wgLoadScript = "$wgScriptPath/load.php";
}
if ( $wgArticlePath === false ) {
'name' => 'local',
'directory' => $wgUploadDirectory,
'scriptDirUrl' => $wgScriptPath,
- 'scriptExtension' => $wgScriptExtension,
+ 'scriptExtension' => '.php',
'url' => $wgUploadBaseUrl ? $wgUploadBaseUrl . $wgUploadPath : $wgUploadPath,
'hashLevels' => $wgHashedUploadDirectory ? 2 : 0,
'thumbScriptUrl' => $wgThumbnailScriptPath,
$ps_default2 = Profiler::instance()->scopedProfileIn( $fname . '-defaults2' );
-if ( $wgScriptExtension !== '.php' || defined( 'MW_ENTRY_PHP5' ) ) {
- wfWarn( 'Script extensions other than ".php" are deprecated.' );
-}
-
if ( $wgCanonicalServer === false ) {
$wgCanonicalServer = wfExpandUrl( $wgServer, PROTO_HTTP );
}
+++ /dev/null
-<?php
-/**
- * Squid and Varnish cache purging.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-/**
- * An HTTP 1.0 client built for the purposes of purging Squid and Varnish.
- * Uses asynchronous I/O, allowing purges to be done in a highly parallel
- * manner.
- *
- * Could be replaced by curl_multi_exec() or some such.
- */
-class SquidPurgeClient {
- /** @var string */
- protected $host;
-
- /** @var int */
- protected $port;
-
- /** @var string|bool */
- protected $ip;
-
- /** @var string */
- protected $readState = 'idle';
-
- /** @var string */
- protected $writeBuffer = '';
-
- /** @var array */
- protected $requests = array();
-
- /** @var mixed */
- protected $currentRequestIndex;
-
- const EINTR = 4;
- const EAGAIN = 11;
- const EINPROGRESS = 115;
- const BUFFER_SIZE = 8192;
-
- /**
- * @var resource|null The socket resource, or null for unconnected, or false
- * for disabled due to error.
- */
- protected $socket;
-
- /** @var string */
- protected $readBuffer;
-
- /** @var int */
- protected $bodyRemaining;
-
- /**
- * @param string $server
- * @param array $options
- */
- public function __construct( $server, $options = array() ) {
- $parts = explode( ':', $server, 2 );
- $this->host = $parts[0];
- $this->port = isset( $parts[1] ) ? $parts[1] : 80;
- }
-
- /**
- * Open a socket if there isn't one open already, return it.
- * Returns false on error.
- *
- * @return bool|resource
- */
- protected function getSocket() {
- if ( $this->socket !== null ) {
- return $this->socket;
- }
-
- $ip = $this->getIP();
- if ( !$ip ) {
- $this->log( "DNS error" );
- $this->markDown();
- return false;
- }
- $this->socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
- socket_set_nonblock( $this->socket );
- MediaWiki\suppressWarnings();
- $ok = socket_connect( $this->socket, $ip, $this->port );
- MediaWiki\restoreWarnings();
- if ( !$ok ) {
- $error = socket_last_error( $this->socket );
- if ( $error !== self::EINPROGRESS ) {
- $this->log( "connection error: " . socket_strerror( $error ) );
- $this->markDown();
- return false;
- }
- }
-
- return $this->socket;
- }
-
- /**
- * Get read socket array for select()
- * @return array
- */
- public function getReadSocketsForSelect() {
- if ( $this->readState == 'idle' ) {
- return array();
- }
- $socket = $this->getSocket();
- if ( $socket === false ) {
- return array();
- }
- return array( $socket );
- }
-
- /**
- * Get write socket array for select()
- * @return array
- */
- public function getWriteSocketsForSelect() {
- if ( !strlen( $this->writeBuffer ) ) {
- return array();
- }
- $socket = $this->getSocket();
- if ( $socket === false ) {
- return array();
- }
- return array( $socket );
- }
-
- /**
- * Get the host's IP address.
- * Does not support IPv6 at present due to the lack of a convenient interface in PHP.
- * @throws MWException
- * @return string
- */
- protected function getIP() {
- if ( $this->ip === null ) {
- if ( IP::isIPv4( $this->host ) ) {
- $this->ip = $this->host;
- } elseif ( IP::isIPv6( $this->host ) ) {
- throw new MWException( '$wgSquidServers does not support IPv6' );
- } else {
- MediaWiki\suppressWarnings();
- $this->ip = gethostbyname( $this->host );
- if ( $this->ip === $this->host ) {
- $this->ip = false;
- }
- MediaWiki\restoreWarnings();
- }
- }
- return $this->ip;
- }
-
- /**
- * Close the socket and ignore any future purge requests.
- * This is called if there is a protocol error.
- */
- protected function markDown() {
- $this->close();
- $this->socket = false;
- }
-
- /**
- * Close the socket but allow it to be reopened for future purge requests
- */
- public function close() {
- if ( $this->socket ) {
- MediaWiki\suppressWarnings();
- socket_set_block( $this->socket );
- socket_shutdown( $this->socket );
- socket_close( $this->socket );
- MediaWiki\restoreWarnings();
- }
- $this->socket = null;
- $this->readBuffer = '';
- // Write buffer is kept since it may contain a request for the next socket
- }
-
- /**
- * Queue a purge operation
- *
- * @param string $url
- */
- public function queuePurge( $url ) {
- global $wgSquidPurgeUseHostHeader;
- $url = SquidUpdate::expand( str_replace( "\n", '', $url ) );
- $request = array();
- if ( $wgSquidPurgeUseHostHeader ) {
- $url = wfParseUrl( $url );
- $host = $url['host'];
- if ( isset( $url['port'] ) && strlen( $url['port'] ) > 0 ) {
- $host .= ":" . $url['port'];
- }
- $path = $url['path'];
- if ( isset( $url['query'] ) && is_string( $url['query'] ) ) {
- $path = wfAppendQuery( $path, $url['query'] );
- }
- $request[] = "PURGE $path HTTP/1.1";
- $request[] = "Host: $host";
- } else {
- $request[] = "PURGE $url HTTP/1.0";
- }
- $request[] = "Connection: Keep-Alive";
- $request[] = "Proxy-Connection: Keep-Alive";
- $request[] = "User-Agent: " . Http::userAgent() . ' ' . __CLASS__;
- // Two ''s to create \r\n\r\n
- $request[] = '';
- $request[] = '';
-
- $this->requests[] = implode( "\r\n", $request );
- if ( $this->currentRequestIndex === null ) {
- $this->nextRequest();
- }
- }
-
- /**
- * @return bool
- */
- public function isIdle() {
- return strlen( $this->writeBuffer ) == 0 && $this->readState == 'idle';
- }
-
- /**
- * Perform pending writes. Call this when socket_select() indicates that writing will not block.
- */
- public function doWrites() {
- if ( !strlen( $this->writeBuffer ) ) {
- return;
- }
- $socket = $this->getSocket();
- if ( !$socket ) {
- return;
- }
-
- if ( strlen( $this->writeBuffer ) <= self::BUFFER_SIZE ) {
- $buf = $this->writeBuffer;
- $flags = MSG_EOR;
- } else {
- $buf = substr( $this->writeBuffer, 0, self::BUFFER_SIZE );
- $flags = 0;
- }
- MediaWiki\suppressWarnings();
- $bytesSent = socket_send( $socket, $buf, strlen( $buf ), $flags );
- MediaWiki\restoreWarnings();
-
- if ( $bytesSent === false ) {
- $error = socket_last_error( $socket );
- if ( $error != self::EAGAIN && $error != self::EINTR ) {
- $this->log( 'write error: ' . socket_strerror( $error ) );
- $this->markDown();
- }
- return;
- }
-
- $this->writeBuffer = substr( $this->writeBuffer, $bytesSent );
- }
-
- /**
- * Read some data. Call this when socket_select() indicates that the read buffer is non-empty.
- */
- public function doReads() {
- $socket = $this->getSocket();
- if ( !$socket ) {
- return;
- }
-
- $buf = '';
- MediaWiki\suppressWarnings();
- $bytesRead = socket_recv( $socket, $buf, self::BUFFER_SIZE, 0 );
- MediaWiki\restoreWarnings();
- if ( $bytesRead === false ) {
- $error = socket_last_error( $socket );
- if ( $error != self::EAGAIN && $error != self::EINTR ) {
- $this->log( 'read error: ' . socket_strerror( $error ) );
- $this->markDown();
- return;
- }
- } elseif ( $bytesRead === 0 ) {
- // Assume EOF
- $this->close();
- return;
- }
-
- $this->readBuffer .= $buf;
- while ( $this->socket && $this->processReadBuffer() === 'continue' );
- }
-
- /**
- * @throws MWException
- * @return string
- */
- protected function processReadBuffer() {
- switch ( $this->readState ) {
- case 'idle':
- return 'done';
- case 'status':
- case 'header':
- $lines = explode( "\r\n", $this->readBuffer, 2 );
- if ( count( $lines ) < 2 ) {
- return 'done';
- }
- if ( $this->readState == 'status' ) {
- $this->processStatusLine( $lines[0] );
- } else { // header
- $this->processHeaderLine( $lines[0] );
- }
- $this->readBuffer = $lines[1];
- return 'continue';
- case 'body':
- if ( $this->bodyRemaining !== null ) {
- if ( $this->bodyRemaining > strlen( $this->readBuffer ) ) {
- $this->bodyRemaining -= strlen( $this->readBuffer );
- $this->readBuffer = '';
- return 'done';
- } else {
- $this->readBuffer = substr( $this->readBuffer, $this->bodyRemaining );
- $this->bodyRemaining = 0;
- $this->nextRequest();
- return 'continue';
- }
- } else {
- // No content length, read all data to EOF
- $this->readBuffer = '';
- return 'done';
- }
- default:
- throw new MWException( __METHOD__ . ': unexpected state' );
- }
- }
-
- /**
- * @param string $line
- */
- protected function processStatusLine( $line ) {
- if ( !preg_match( '!^HTTP/(\d+)\.(\d+) (\d{3}) (.*)$!', $line, $m ) ) {
- $this->log( 'invalid status line' );
- $this->markDown();
- return;
- }
- list( , , , $status, $reason ) = $m;
- $status = intval( $status );
- if ( $status !== 200 && $status !== 404 ) {
- $this->log( "unexpected status code: $status $reason" );
- $this->markDown();
- return;
- }
- $this->readState = 'header';
- }
-
- /**
- * @param string $line
- */
- protected function processHeaderLine( $line ) {
- if ( preg_match( '/^Content-Length: (\d+)$/i', $line, $m ) ) {
- $this->bodyRemaining = intval( $m[1] );
- } elseif ( $line === '' ) {
- $this->readState = 'body';
- }
- }
-
- protected function nextRequest() {
- if ( $this->currentRequestIndex !== null ) {
- unset( $this->requests[$this->currentRequestIndex] );
- }
- if ( count( $this->requests ) ) {
- $this->readState = 'status';
- $this->currentRequestIndex = key( $this->requests );
- $this->writeBuffer = $this->requests[$this->currentRequestIndex];
- } else {
- $this->readState = 'idle';
- $this->currentRequestIndex = null;
- $this->writeBuffer = '';
- }
- $this->bodyRemaining = null;
- }
-
- /**
- * @param string $msg
- */
- protected function log( $msg ) {
- wfDebugLog( 'squid', __CLASS__ . " ($this->host): $msg" );
- }
-}
-
-class SquidPurgeClientPool {
- /** @var array Array of SquidPurgeClient */
- protected $clients = array();
-
- /** @var int */
- protected $timeout = 5;
-
- /**
- * @param array $options
- */
- function __construct( $options = array() ) {
- if ( isset( $options['timeout'] ) ) {
- $this->timeout = $options['timeout'];
- }
- }
-
- /**
- * @param SquidPurgeClient $client
- * @return void
- */
- public function addClient( $client ) {
- $this->clients[] = $client;
- }
-
- public function run() {
- $done = false;
- $startTime = microtime( true );
- while ( !$done ) {
- $readSockets = $writeSockets = array();
- /**
- * @var $client SquidPurgeClient
- */
- foreach ( $this->clients as $clientIndex => $client ) {
- $sockets = $client->getReadSocketsForSelect();
- foreach ( $sockets as $i => $socket ) {
- $readSockets["$clientIndex/$i"] = $socket;
- }
- $sockets = $client->getWriteSocketsForSelect();
- foreach ( $sockets as $i => $socket ) {
- $writeSockets["$clientIndex/$i"] = $socket;
- }
- }
- if ( !count( $readSockets ) && !count( $writeSockets ) ) {
- break;
- }
- $exceptSockets = null;
- $timeout = min( $startTime + $this->timeout - microtime( true ), 1 );
- MediaWiki\suppressWarnings();
- $numReady = socket_select( $readSockets, $writeSockets, $exceptSockets, $timeout );
- MediaWiki\restoreWarnings();
- if ( $numReady === false ) {
- wfDebugLog( 'squid', __METHOD__ . ': Error in stream_select: ' .
- socket_strerror( socket_last_error() ) . "\n" );
- break;
- }
- // Check for timeout, use 1% tolerance since we aimed at having socket_select()
- // exit at precisely the overall timeout
- if ( microtime( true ) - $startTime > $this->timeout * 0.99 ) {
- wfDebugLog( 'squid', __CLASS__ . ": timeout ({$this->timeout}s)\n" );
- break;
- } elseif ( !$numReady ) {
- continue;
- }
-
- foreach ( $readSockets as $key => $socket ) {
- list( $clientIndex, ) = explode( '/', $key );
- $client = $this->clients[$clientIndex];
- $client->doReads();
- }
- foreach ( $writeSockets as $key => $socket ) {
- list( $clientIndex, ) = explode( '/', $key );
- $client = $this->clients[$clientIndex];
- $client->doWrites();
- }
-
- $done = true;
- foreach ( $this->clients as $client ) {
- if ( !$client->isIdle() ) {
- $done = false;
- }
- }
- }
- foreach ( $this->clients as $client ) {
- $client->close();
- }
- }
-}
* @return bool
*/
public function checkUrlExtension( $extWhitelist = array() ) {
- global $wgScriptExtension;
- $extWhitelist[] = ltrim( $wgScriptExtension, '.' );
+ $extWhitelist[] = 'php';
if ( IEUrlExtension::areServerVarsBad( $_SERVER, $extWhitelist ) ) {
if ( !$this->wasPosted() ) {
$newUrl = IEUrlExtension::fixUrlForIE6(
*/
class ApiDelete extends ApiBase {
/**
- * Extracts the title, token, and reason from the request parameters and invokes
+ * Extracts the title and reason from the request parameters and invokes
* the local delete() function with these as arguments. It does not make use of
* the delete function specified by Article.php. If the deletion succeeds, the
* details of the article deleted and the reason for deletion are added to the
$reason = $params['reason'];
$user = $this->getUser();
+ // Check that the user is allowed to carry out the deletion
+ $errors = $titleObj->getUserPermissionsErrors( 'delete', $user );
+ if ( count( $errors ) ) {
+ $this->dieUsageMsg( $errors[0] );
+ }
+
+ // If change tagging was requested, check that the user is allowed to tag,
+ // and the tags are valid
+ if ( count( $params['tags'] ) ) {
+ $tagStatus = ChangeTags::canAddTagsAccompanyingChange( $params['tags'], $user );
+ if ( !$tagStatus->isOK() ) {
+ $this->dieStatus( $tagStatus );
+ }
+ }
+
if ( $titleObj->getNamespace() == NS_FILE ) {
$status = self::deleteFile(
$pageObj,
$user,
- $params['token'],
$params['oldimage'],
$reason,
false
);
} else {
- $status = self::delete( $pageObj, $user, $params['token'], $reason );
+ $status = self::delete( $pageObj, $user, $reason );
}
if ( is_array( $status ) ) {
}
$this->setWatch( $watch, $titleObj, 'watchdeletion' );
+ // Apply change tags to the log entry, if requested
+ if ( count( $params['tags'] ) ) {
+ ChangeTags::addTags( $params['tags'], null, null, $status->value, null, $user );
+ }
+
$r = array(
'title' => $titleObj->getPrefixedText(),
'reason' => $reason,
$this->getResult()->addValue( null, $this->getModuleName(), $r );
}
- /**
- * @param Title $title
- * @param User $user User doing the action
- * @param string $token
- * @return array
- */
- private static function getPermissionsError( $title, $user, $token ) {
- // Check permissions
- return $title->getUserPermissionsErrors( 'delete', $user );
- }
-
/**
* We have our own delete() function, since Article.php's implementation is split in two phases
*
* @param Page|WikiPage $page Page or WikiPage object to work on
* @param User $user User doing the action
- * @param string $token Delete token (same as edit token)
* @param string|null $reason Reason for the deletion. Autogenerated if null
* @return Status|array
*/
- public static function delete( Page $page, User $user, $token, &$reason = null ) {
+ protected static function delete( Page $page, User $user, &$reason = null ) {
$title = $page->getTitle();
- $errors = self::getPermissionsError( $title, $user, $token );
- if ( count( $errors ) ) {
- return $errors;
- }
// Auto-generate a summary, if necessary
if ( is_null( $reason ) ) {
/**
* @param Page $page Object to work on
* @param User $user User doing the action
- * @param string $token Delete token (same as edit token)
* @param string $oldimage Archive name
* @param string $reason Reason for the deletion. Autogenerated if null.
* @param bool $suppress Whether to mark all deleted versions as restricted
* @return Status|array
*/
- public static function deleteFile( Page $page, User $user, $token, $oldimage,
+ protected static function deleteFile( Page $page, User $user, $oldimage,
&$reason = null, $suppress = false
) {
$title = $page->getTitle();
- $errors = self::getPermissionsError( $title, $user, $token );
- if ( count( $errors ) ) {
- return $errors;
- }
$file = $page->getFile();
if ( !$file->exists() || !$file->isLocal() || $file->getRedirected() ) {
- return self::delete( $page, $user, $token, $reason );
+ return self::delete( $page, $user, $reason );
}
if ( $oldimage ) {
ApiBase::PARAM_TYPE => 'integer'
),
'reason' => null,
+ 'tags' => array(
+ ApiBase::PARAM_TYPE => ChangeTags::listExplicitlyDefinedTags(),
+ ApiBase::PARAM_ISMULTI => true,
+ ),
'watch' => array(
ApiBase::PARAM_DFLT => false,
ApiBase::PARAM_DEPRECATED => true,
"apihelp-delete-param-title": "Title of the page to delete. Cannot be used together with <var>$1pageid</var>.",
"apihelp-delete-param-pageid": "Page ID of the page to delete. Cannot be used together with <var>$1title</var>.",
"apihelp-delete-param-reason": "Reason for the deletion. If not set, an automatically generated reason will be used.",
+ "apihelp-delete-param-tags": "Change tags to apply to the entry in the deletion log.",
"apihelp-delete-param-watch": "Add the page to the current user's watchlist.",
"apihelp-delete-param-watchlist": "Unconditionally add or remove the page from the current user's watchlist, use preferences or do not change watch.",
"apihelp-delete-param-unwatch": "Remove the page from the current user's watchlist.",
"apihelp-delete-param-title": "{{doc-apihelp-param|delete|title}}",
"apihelp-delete-param-pageid": "{{doc-apihelp-param|delete|pageid}}",
"apihelp-delete-param-reason": "{{doc-apihelp-param|delete|reason}}",
+ "apihelp-delete-param-tags": "{{doc-apihelp-param|delete|tags}}",
"apihelp-delete-param-watch": "{{doc-apihelp-param|delete|watch}}",
"apihelp-delete-param-watchlist": "{{doc-apihelp-param|delete|watchlist}}",
"apihelp-delete-param-unwatch": "{{doc-apihelp-param|delete|unwatch}}",
--- /dev/null
+<?php
+/**
+ * Squid and Varnish cache purging.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+/**
+ * An HTTP 1.0 client built for the purposes of purging Squid and Varnish.
+ * Uses asynchronous I/O, allowing purges to be done in a highly parallel
+ * manner.
+ *
+ * Could be replaced by curl_multi_exec() or some such.
+ */
+class SquidPurgeClient {
+ /** @var string */
+ protected $host;
+
+ /** @var int */
+ protected $port;
+
+ /** @var string|bool */
+ protected $ip;
+
+ /** @var string */
+ protected $readState = 'idle';
+
+ /** @var string */
+ protected $writeBuffer = '';
+
+ /** @var array */
+ protected $requests = array();
+
+ /** @var mixed */
+ protected $currentRequestIndex;
+
+ const EINTR = 4;
+ const EAGAIN = 11;
+ const EINPROGRESS = 115;
+ const BUFFER_SIZE = 8192;
+
+ /**
+ * @var resource|null The socket resource, or null for unconnected, or false
+ * for disabled due to error.
+ */
+ protected $socket;
+
+ /** @var string */
+ protected $readBuffer;
+
+ /** @var int */
+ protected $bodyRemaining;
+
+ /**
+ * @param string $server
+ * @param array $options
+ */
+ public function __construct( $server, $options = array() ) {
+ $parts = explode( ':', $server, 2 );
+ $this->host = $parts[0];
+ $this->port = isset( $parts[1] ) ? $parts[1] : 80;
+ }
+
+ /**
+ * Open a socket if there isn't one open already, return it.
+ * Returns false on error.
+ *
+ * @return bool|resource
+ */
+ protected function getSocket() {
+ if ( $this->socket !== null ) {
+ return $this->socket;
+ }
+
+ $ip = $this->getIP();
+ if ( !$ip ) {
+ $this->log( "DNS error" );
+ $this->markDown();
+ return false;
+ }
+ $this->socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP );
+ socket_set_nonblock( $this->socket );
+ MediaWiki\suppressWarnings();
+ $ok = socket_connect( $this->socket, $ip, $this->port );
+ MediaWiki\restoreWarnings();
+ if ( !$ok ) {
+ $error = socket_last_error( $this->socket );
+ if ( $error !== self::EINPROGRESS ) {
+ $this->log( "connection error: " . socket_strerror( $error ) );
+ $this->markDown();
+ return false;
+ }
+ }
+
+ return $this->socket;
+ }
+
+ /**
+ * Get read socket array for select()
+ * @return array
+ */
+ public function getReadSocketsForSelect() {
+ if ( $this->readState == 'idle' ) {
+ return array();
+ }
+ $socket = $this->getSocket();
+ if ( $socket === false ) {
+ return array();
+ }
+ return array( $socket );
+ }
+
+ /**
+ * Get write socket array for select()
+ * @return array
+ */
+ public function getWriteSocketsForSelect() {
+ if ( !strlen( $this->writeBuffer ) ) {
+ return array();
+ }
+ $socket = $this->getSocket();
+ if ( $socket === false ) {
+ return array();
+ }
+ return array( $socket );
+ }
+
+ /**
+ * Get the host's IP address.
+ * Does not support IPv6 at present due to the lack of a convenient interface in PHP.
+ * @throws MWException
+ * @return string
+ */
+ protected function getIP() {
+ if ( $this->ip === null ) {
+ if ( IP::isIPv4( $this->host ) ) {
+ $this->ip = $this->host;
+ } elseif ( IP::isIPv6( $this->host ) ) {
+ throw new MWException( '$wgSquidServers does not support IPv6' );
+ } else {
+ MediaWiki\suppressWarnings();
+ $this->ip = gethostbyname( $this->host );
+ if ( $this->ip === $this->host ) {
+ $this->ip = false;
+ }
+ MediaWiki\restoreWarnings();
+ }
+ }
+ return $this->ip;
+ }
+
+ /**
+ * Close the socket and ignore any future purge requests.
+ * This is called if there is a protocol error.
+ */
+ protected function markDown() {
+ $this->close();
+ $this->socket = false;
+ }
+
+ /**
+ * Close the socket but allow it to be reopened for future purge requests
+ */
+ public function close() {
+ if ( $this->socket ) {
+ MediaWiki\suppressWarnings();
+ socket_set_block( $this->socket );
+ socket_shutdown( $this->socket );
+ socket_close( $this->socket );
+ MediaWiki\restoreWarnings();
+ }
+ $this->socket = null;
+ $this->readBuffer = '';
+ // Write buffer is kept since it may contain a request for the next socket
+ }
+
+ /**
+ * Queue a purge operation
+ *
+ * @param string $url
+ */
+ public function queuePurge( $url ) {
+ global $wgSquidPurgeUseHostHeader;
+ $url = SquidUpdate::expand( str_replace( "\n", '', $url ) );
+ $request = array();
+ if ( $wgSquidPurgeUseHostHeader ) {
+ $url = wfParseUrl( $url );
+ $host = $url['host'];
+ if ( isset( $url['port'] ) && strlen( $url['port'] ) > 0 ) {
+ $host .= ":" . $url['port'];
+ }
+ $path = $url['path'];
+ if ( isset( $url['query'] ) && is_string( $url['query'] ) ) {
+ $path = wfAppendQuery( $path, $url['query'] );
+ }
+ $request[] = "PURGE $path HTTP/1.1";
+ $request[] = "Host: $host";
+ } else {
+ $request[] = "PURGE $url HTTP/1.0";
+ }
+ $request[] = "Connection: Keep-Alive";
+ $request[] = "Proxy-Connection: Keep-Alive";
+ $request[] = "User-Agent: " . Http::userAgent() . ' ' . __CLASS__;
+ // Two ''s to create \r\n\r\n
+ $request[] = '';
+ $request[] = '';
+
+ $this->requests[] = implode( "\r\n", $request );
+ if ( $this->currentRequestIndex === null ) {
+ $this->nextRequest();
+ }
+ }
+
+ /**
+ * @return bool
+ */
+ public function isIdle() {
+ return strlen( $this->writeBuffer ) == 0 && $this->readState == 'idle';
+ }
+
+ /**
+ * Perform pending writes. Call this when socket_select() indicates that writing will not block.
+ */
+ public function doWrites() {
+ if ( !strlen( $this->writeBuffer ) ) {
+ return;
+ }
+ $socket = $this->getSocket();
+ if ( !$socket ) {
+ return;
+ }
+
+ if ( strlen( $this->writeBuffer ) <= self::BUFFER_SIZE ) {
+ $buf = $this->writeBuffer;
+ $flags = MSG_EOR;
+ } else {
+ $buf = substr( $this->writeBuffer, 0, self::BUFFER_SIZE );
+ $flags = 0;
+ }
+ MediaWiki\suppressWarnings();
+ $bytesSent = socket_send( $socket, $buf, strlen( $buf ), $flags );
+ MediaWiki\restoreWarnings();
+
+ if ( $bytesSent === false ) {
+ $error = socket_last_error( $socket );
+ if ( $error != self::EAGAIN && $error != self::EINTR ) {
+ $this->log( 'write error: ' . socket_strerror( $error ) );
+ $this->markDown();
+ }
+ return;
+ }
+
+ $this->writeBuffer = substr( $this->writeBuffer, $bytesSent );
+ }
+
+ /**
+ * Read some data. Call this when socket_select() indicates that the read buffer is non-empty.
+ */
+ public function doReads() {
+ $socket = $this->getSocket();
+ if ( !$socket ) {
+ return;
+ }
+
+ $buf = '';
+ MediaWiki\suppressWarnings();
+ $bytesRead = socket_recv( $socket, $buf, self::BUFFER_SIZE, 0 );
+ MediaWiki\restoreWarnings();
+ if ( $bytesRead === false ) {
+ $error = socket_last_error( $socket );
+ if ( $error != self::EAGAIN && $error != self::EINTR ) {
+ $this->log( 'read error: ' . socket_strerror( $error ) );
+ $this->markDown();
+ return;
+ }
+ } elseif ( $bytesRead === 0 ) {
+ // Assume EOF
+ $this->close();
+ return;
+ }
+
+ $this->readBuffer .= $buf;
+ while ( $this->socket && $this->processReadBuffer() === 'continue' );
+ }
+
+ /**
+ * @throws MWException
+ * @return string
+ */
+ protected function processReadBuffer() {
+ switch ( $this->readState ) {
+ case 'idle':
+ return 'done';
+ case 'status':
+ case 'header':
+ $lines = explode( "\r\n", $this->readBuffer, 2 );
+ if ( count( $lines ) < 2 ) {
+ return 'done';
+ }
+ if ( $this->readState == 'status' ) {
+ $this->processStatusLine( $lines[0] );
+ } else { // header
+ $this->processHeaderLine( $lines[0] );
+ }
+ $this->readBuffer = $lines[1];
+ return 'continue';
+ case 'body':
+ if ( $this->bodyRemaining !== null ) {
+ if ( $this->bodyRemaining > strlen( $this->readBuffer ) ) {
+ $this->bodyRemaining -= strlen( $this->readBuffer );
+ $this->readBuffer = '';
+ return 'done';
+ } else {
+ $this->readBuffer = substr( $this->readBuffer, $this->bodyRemaining );
+ $this->bodyRemaining = 0;
+ $this->nextRequest();
+ return 'continue';
+ }
+ } else {
+ // No content length, read all data to EOF
+ $this->readBuffer = '';
+ return 'done';
+ }
+ default:
+ throw new MWException( __METHOD__ . ': unexpected state' );
+ }
+ }
+
+ /**
+ * @param string $line
+ */
+ protected function processStatusLine( $line ) {
+ if ( !preg_match( '!^HTTP/(\d+)\.(\d+) (\d{3}) (.*)$!', $line, $m ) ) {
+ $this->log( 'invalid status line' );
+ $this->markDown();
+ return;
+ }
+ list( , , , $status, $reason ) = $m;
+ $status = intval( $status );
+ if ( $status !== 200 && $status !== 404 ) {
+ $this->log( "unexpected status code: $status $reason" );
+ $this->markDown();
+ return;
+ }
+ $this->readState = 'header';
+ }
+
+ /**
+ * @param string $line
+ */
+ protected function processHeaderLine( $line ) {
+ if ( preg_match( '/^Content-Length: (\d+)$/i', $line, $m ) ) {
+ $this->bodyRemaining = intval( $m[1] );
+ } elseif ( $line === '' ) {
+ $this->readState = 'body';
+ }
+ }
+
+ protected function nextRequest() {
+ if ( $this->currentRequestIndex !== null ) {
+ unset( $this->requests[$this->currentRequestIndex] );
+ }
+ if ( count( $this->requests ) ) {
+ $this->readState = 'status';
+ $this->currentRequestIndex = key( $this->requests );
+ $this->writeBuffer = $this->requests[$this->currentRequestIndex];
+ } else {
+ $this->readState = 'idle';
+ $this->currentRequestIndex = null;
+ $this->writeBuffer = '';
+ }
+ $this->bodyRemaining = null;
+ }
+
+ /**
+ * @param string $msg
+ */
+ protected function log( $msg ) {
+ wfDebugLog( 'squid', __CLASS__ . " ($this->host): $msg" );
+ }
+}
--- /dev/null
+<?php
+/**
+ * Squid and Varnish cache purging.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+class SquidPurgeClientPool {
+ /** @var array Array of SquidPurgeClient */
+ protected $clients = array();
+
+ /** @var int */
+ protected $timeout = 5;
+
+ /**
+ * @param array $options
+ */
+ function __construct( $options = array() ) {
+ if ( isset( $options['timeout'] ) ) {
+ $this->timeout = $options['timeout'];
+ }
+ }
+
+ /**
+ * @param SquidPurgeClient $client
+ * @return void
+ */
+ public function addClient( $client ) {
+ $this->clients[] = $client;
+ }
+
+ public function run() {
+ $done = false;
+ $startTime = microtime( true );
+ while ( !$done ) {
+ $readSockets = $writeSockets = array();
+ /**
+ * @var $client SquidPurgeClient
+ */
+ foreach ( $this->clients as $clientIndex => $client ) {
+ $sockets = $client->getReadSocketsForSelect();
+ foreach ( $sockets as $i => $socket ) {
+ $readSockets["$clientIndex/$i"] = $socket;
+ }
+ $sockets = $client->getWriteSocketsForSelect();
+ foreach ( $sockets as $i => $socket ) {
+ $writeSockets["$clientIndex/$i"] = $socket;
+ }
+ }
+ if ( !count( $readSockets ) && !count( $writeSockets ) ) {
+ break;
+ }
+ $exceptSockets = null;
+ $timeout = min( $startTime + $this->timeout - microtime( true ), 1 );
+ MediaWiki\suppressWarnings();
+ $numReady = socket_select( $readSockets, $writeSockets, $exceptSockets, $timeout );
+ MediaWiki\restoreWarnings();
+ if ( $numReady === false ) {
+ wfDebugLog( 'squid', __METHOD__ . ': Error in stream_select: ' .
+ socket_strerror( socket_last_error() ) . "\n" );
+ break;
+ }
+ // Check for timeout, use 1% tolerance since we aimed at having socket_select()
+ // exit at precisely the overall timeout
+ if ( microtime( true ) - $startTime > $this->timeout * 0.99 ) {
+ wfDebugLog( 'squid', __CLASS__ . ": timeout ({$this->timeout}s)\n" );
+ break;
+ } elseif ( !$numReady ) {
+ continue;
+ }
+
+ foreach ( $readSockets as $key => $socket ) {
+ list( $clientIndex, ) = explode( '/', $key );
+ $client = $this->clients[$clientIndex];
+ $client->doReads();
+ }
+ foreach ( $writeSockets as $key => $socket ) {
+ list( $clientIndex, ) = explode( '/', $key );
+ $client = $this->clients[$clientIndex];
+ $client->doWrites();
+ }
+
+ $done = true;
+ foreach ( $this->clients as $client ) {
+ if ( !$client->isIdle() ) {
+ $done = false;
+ }
+ }
+ }
+ foreach ( $this->clients as $client ) {
+ $client->close();
+ }
+ }
+}
/** @var array|stdClass|bool */
protected $currentRow = null;
+ /**
+ * @param array $array
+ */
function __construct( $array ) {
$this->result = $array;
}
/** @var LBFactory */
private static $instance;
+ /**
+ * Construct a factory based on a configuration array (typically from $wgLBFactoryConf)
+ * @param array $conf
+ */
+ public function __construct( array $conf ) {
+ }
+
/**
* Disables all access to the load balancer, will cause all database access
* to throw a DBAccessError
self::$instance = $instance;
}
- /**
- * Construct a factory based on a configuration array (typically from $wgLBFactoryConf)
- * @param array $conf
- */
- abstract public function __construct( array $conf );
-
/**
* Create a new load balancer object. The resulting object will be untracked,
* not chronology-protected, and the caller is responsible for cleaning it up.
* @throws MWException
*/
public function __construct( array $conf ) {
+ parent::__construct( $conf );
+
$this->chronProt = new ChronologyProtector;
$this->conf = $conf;
$required = array( 'sectionsByDB', 'sectionLoads', 'serverTemplate' );
private $loadMonitorClass;
public function __construct( array $conf ) {
+ parent::__construct( $conf );
+
$this->chronProt = new ChronologyProtector;
$this->loadMonitorClass = isset( $conf['loadMonitorClass'] )
? $conf['loadMonitorClass']
/** @var integer Warn when this many connection are held */
const CONN_HELD_WARN_THRESHOLD = 10;
+ /** @var integer Default 'max lag' when unspecified */
+ const MAX_LAG = 30;
/**
* @param array $params Array with keys:
* @param float $maxLag Restrict the maximum allowed lag to this many seconds
* @return bool|int|string
*/
- private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = INF ) {
+ private function getRandomNonLagged( array $loads, $wiki = false, $maxLag = self::MAX_LAG ) {
$lags = $this->getLagTimes( $wiki );
# Unset excessively lagged servers
* @since 1.19
*/
class DeferredUpdates {
- /** @var array Updates to be deferred until the end of the request */
+ /** @var DeferrableUpdate[] Updates to be deferred until the end of the request */
private static $updates = array();
/** @var bool Defer updates fully even in CLI mode */
private static $forceDeferral = false;
* Do any deferred updates and clear the list
*
* @param string $commit Set to 'commit' to commit after every update to
+ * @param string $mode Use "enqueue" to use the job queue when possible [Default: run]
* prevent lock contention
*/
- public static function doUpdates( $commit = '' ) {
+ public static function doUpdates( $commit = '', $mode = 'run' ) {
$updates = self::$updates;
while ( count( $updates ) ) {
self::clearPendingUpdates();
-
- /** @var DeferrableUpdate $update */
+ /** @var DataUpdate[] $dataUpdates */
+ $dataUpdates = array();
+ /** @var DeferrableUpdate[] $otherUpdates */
+ $otherUpdates = array();
foreach ( $updates as $update ) {
+ if ( $update instanceof DataUpdate ) {
+ $dataUpdates[] = $update;
+ } else {
+ $otherUpdates[] = $update;
+ }
+ }
+
+ // Delegate DataUpdate execution to the DataUpdate class
+ DataUpdate::runUpdates( $dataUpdates, $mode );
+ // Execute the non-DataUpdate tasks
+ foreach ( $otherUpdates as $update ) {
try {
$update->doUpdate();
-
if ( $commit === 'commit' ) {
wfGetLBFactory()->commitMasterChanges();
}
*
* @todo document (e.g. one-sentence top-level class description).
*/
-class LinksUpdate extends SqlDataUpdate {
+class LinksUpdate extends SqlDataUpdate implements EnqueueableDataUpdate {
// @todo make members protected, but make sure extensions don't break
/** @var int Page ID of the article linked from */
);
}
}
+
+ public function getAsJobSpecification() {
+ return array(
+ 'wiki' => $this->mDb->getWikiID(),
+ 'job' => new JobSpecification(
+ 'refreshLinks',
+ array( 'prioritize' => true ),
+ array( 'removeDuplicates' => true ),
+ $this->getTitle()
+ )
+ );
+ }
}
protected $scriptDirUrl;
/** @var string Script extension of the MediaWiki installation, equivalent
- * to $wgScriptExtension, e.g. .php5 defaults to .php */
+ * to the old $wgScriptExtension, e.g. .php5 defaults to .php */
protected $scriptExtension;
/** @var string Equivalent to $wgArticlePath, e.g. https://en.wikipedia.org/wiki/$1 */
* @return Closure
*/
protected function getDBFactory() {
- return function( $index ) {
- return DatabaseBase::factory( $this->dbType,
- array(
- 'host' => $this->dbServer,
- 'user' => $this->dbUser,
- 'password' => $this->dbPassword,
- 'dbname' => $this->dbName,
- 'flags' => $this->dbFlags,
- 'tablePrefix' => $this->tablePrefix,
- 'foreign' => true,
- )
- );
+ $type = $this->dbType;
+ $params = array(
+ 'host' => $this->dbServer,
+ 'user' => $this->dbUser,
+ 'password' => $this->dbPassword,
+ 'dbname' => $this->dbName,
+ 'flags' => $this->dbFlags,
+ 'tablePrefix' => $this->tablePrefix,
+ 'foreign' => true,
+ );
+
+ return function ( $index ) use ( $type, $params ) {
+ return DatabaseBase::factory( $type, $params );
};
}
}
public function showDoneMessage() {
- global $wgScriptExtension;
-
$this->startForm();
$regenerate = !$this->getVar( '_ExistingDBSettings' );
if ( $regenerate ) {
$this->parent->getInfoBox(
wfMessage( $msg,
$this->getVar( 'wgServer' ) .
- $this->getVar( 'wgScriptPath' ) . '/index' .
- $wgScriptExtension
+ $this->getVar( 'wgScriptPath' ) . '/index.php'
)->plain(), 'tick-32.png'
)
);
$from = self::convertSelectType( $from );
$db = wfGetDB( $from === self::READ_LATEST ? DB_MASTER : DB_SLAVE );
- $row = $db->selectRow( 'page', self::selectFields(), array( 'page_id' => $id ), __METHOD__ );
+ $row = $db->selectRow(
+ 'page', self::selectFields(), array( 'page_id' => $id ), __METHOD__ );
if ( !$row ) {
return null;
}
* Load the object from a database row
*
* @since 1.20
- * @param object $data Database row containing at least fields returned by selectFields()
+ * @param object|bool $data DB row containing fields returned by selectFields() or false
* @param string|int $from One of the following:
* - "fromdb" or WikiPage::READ_NORMAL if the data comes from a slave DB
* - "fromdbmaster" or WikiPage::READ_LATEST if the data comes from the master DB
// SELECT. Thus we need S1 to also gets the revision row FOR UPDATE; otherwise, it
// may not find it since a page row UPDATE and revision row INSERT by S2 may have
// happened after the first S1 SELECT.
- // http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read.
+ // http://dev.mysql.com/doc/refman/5.0/en/set-transaction.html#isolevel_repeatable-read
$flags = Revision::READ_LOCKING;
} elseif ( $this->mDataLoadedFrom == self::READ_LATEST ) {
// Bug T93976: if page_latest was loaded from the master, fetch the
$conds[] = "rev_user_text != {$dbr->addQuotes( $this->getUserText() )}";
}
- $conds[] = "{$dbr->bitAnd( 'rev_deleted', Revision::DELETED_USER )} = 0"; // username hidden?
+ // Username hidden?
+ $conds[] = "{$dbr->bitAnd( 'rev_deleted', Revision::DELETED_USER )} = 0";
$jconds = array(
'user' => array( 'LEFT JOIN', 'rev_user = user_id' ),
public function getParserOutput( ParserOptions $parserOptions, $oldid = null ) {
$useParserCache = $this->shouldCheckParserCache( $parserOptions, $oldid );
- wfDebug( __METHOD__ . ': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
+ wfDebug( __METHOD__ .
+ ': using parser cache: ' . ( $useParserCache ? 'yes' : 'no' ) . "\n" );
if ( $parserOptions->getStubThreshold() ) {
wfIncrStats( 'pcache.miss.stub' );
}
/**
* Do standard deferred updates after page view (existing or missing page)
* @param User $user The relevant user
- * @param int $oldid The revision id being viewed. If not given or 0, latest revision is assumed.
+ * @param int $oldid Revision id being viewed; if not given or 0, latest revision is assumed
*/
public function doViewUpdates( User $user, $oldid = 0 ) {
if ( wfReadOnly() ) {
return true;
}
-
/**
* Insert a new empty page record for this article.
* This *must* be followed up by creating a revision
* @return int|bool The newly created page_id key; false if the title already existed
*/
public function insertOn( $dbw ) {
- $page_id = $dbw->nextSequenceValue( 'page_page_id_seq' );
- $dbw->insert( 'page', array(
- 'page_id' => $page_id,
- 'page_namespace' => $this->mTitle->getNamespace(),
- 'page_title' => $this->mTitle->getDBkey(),
- 'page_restrictions' => '',
- 'page_is_redirect' => 0, // Will set this shortly...
- 'page_is_new' => 1,
- 'page_random' => wfRandom(),
- 'page_touched' => $dbw->timestamp(),
- 'page_latest' => 0, // Fill this in shortly...
- 'page_len' => 0, // Fill this in shortly...
- ), __METHOD__, 'IGNORE' );
-
- $affected = $dbw->affectedRows();
-
- if ( $affected ) {
+ $dbw->insert(
+ 'page',
+ array(
+ 'page_id' => $dbw->nextSequenceValue( 'page_page_id_seq' ),
+ 'page_namespace' => $this->mTitle->getNamespace(),
+ 'page_title' => $this->mTitle->getDBkey(),
+ 'page_restrictions' => '',
+ 'page_is_redirect' => 0, // Will set this shortly...
+ 'page_is_new' => 1,
+ 'page_random' => wfRandom(),
+ 'page_touched' => $dbw->timestamp(),
+ 'page_latest' => 0, // Fill this in shortly...
+ 'page_len' => 0, // Fill this in shortly...
+ ),
+ __METHOD__,
+ 'IGNORE'
+ );
+
+ if ( $dbw->affectedRows() > 0 ) {
$newid = $dbw->insertId();
$this->mId = $newid;
$this->mTitle->resetArticleID( $newid );
return $newid;
} else {
- return false;
+ return false; // nothing changed
}
}
$this->mLatest = $revision->getId();
$this->mIsRedirect = (bool)$rt;
// Update the LinkCache.
- LinkCache::singleton()->addGoodLinkObj( $this->getId(), $this->mTitle, $len, $this->mIsRedirect,
- $this->mLatest, $revision->getContentModel() );
+ LinkCache::singleton()->addGoodLinkObj(
+ $this->getId(),
+ $this->mTitle,
+ $len,
+ $this->mIsRedirect,
+ $this->mLatest,
+ $revision->getContentModel()
+ );
}
return $result;
* @since 1.21
* @deprecated since 1.24, use replaceSectionAtRev instead
*/
- public function replaceSectionContent( $sectionId, Content $sectionContent, $sectionTitle = '',
- $edittime = null ) {
+ public function replaceSectionContent(
+ $sectionId, Content $sectionContent, $sectionTitle = '', $edittime = null
+ ) {
$baseRevId = null;
if ( $edittime && $sectionId !== 'new' ) {
* Do not log the change in recentchanges
* EDIT_FORCE_BOT
* Mark the edit a "bot" edit regardless of user rights
- * EDIT_DEFER_UPDATES
- * Defer some of the updates until the end of index.php
* EDIT_AUTOSUMMARY
* Fill in blank summaries with generated text where possible
*
* Do not log the change in recentchanges
* EDIT_FORCE_BOT
* Mark the edit a "bot" edit regardless of user rights
- * EDIT_DEFER_UPDATES
- * Defer some of the updates until the end of index.php
* EDIT_AUTOSUMMARY
* Fill in blank summaries with generated text where possible
*
return $status;
}
- Hooks::run( 'NewRevisionFromEditComplete', array( $this, $revision, $baseRevId, $user ) );
+ Hooks::run( 'NewRevisionFromEditComplete',
+ array( $this, $revision, $baseRevId, $user ) );
// Update recentchanges
if ( !( $flags & EDIT_SUPPRESS_RC ) ) {
Hooks::run( 'PageContentInsertComplete', $hook_args );
}
- // Do updates right now unless deferral was requested
- if ( !( $flags & EDIT_DEFER_UPDATES ) ) {
- DeferredUpdates::doUpdates();
- }
-
// Return the new revision (or null) to the caller
$status->value['revision'] = $revision;
* @since 1.21
*/
public function prepareContentForEdit(
- Content $content, $revision = null, User $user = null, $serialFormat = null, $useCache = true
+ Content $content, $revision = null, User $user = null,
+ $serialFormat = null, $useCache = true
) {
global $wgContLang, $wgUser, $wgAjaxEditStash;
// itself (such as via self-transclusion). In this case, we need to make sure
// that any such self-references refer to the newly-saved revision, and not
// to the previous one, which could otherwise happen due to slave lag.
- $oldCallback = $edit->popts->setCurrentRevisionCallback(
- function ( $title, $parser = false ) use ( $revision, &$oldCallback ) {
+ $oldCallback = $edit->popts->getCurrentRevisionCallback();
+ $edit->popts->setCurrentRevisionCallback(
+ function ( Title $title, $parser = false ) use ( $revision, &$oldCallback ) {
if ( $title->equals( $revision->getTitle() ) ) {
return $revision;
} else {
- return call_user_func(
- $oldCallback,
- $title,
- $parser
- );
+ return call_user_func( $oldCallback, $title, $parser );
}
}
);
$edit->oldContent = $this->getContent( Revision::RAW );
// NOTE: B/C for hooks! don't use these fields!
- $edit->newText = $edit->newContent ? ContentHandler::getContentText( $edit->newContent ) : '';
- $edit->oldText = $edit->oldContent ? ContentHandler::getContentText( $edit->oldContent ) : '';
+ $edit->newText = $edit->newContent
+ ? ContentHandler::getContentText( $edit->newContent )
+ : '';
+ $edit->oldText = $edit->oldContent
+ ? ContentHandler::getContentText( $edit->oldContent )
+ : '';
$edit->pst = $edit->pstContent ? $edit->pstContent->serialize( $serialFormat ) : '';
$this->mPreparedEdit = $edit;
if ( !$recipient ) {
wfDebug( __METHOD__ . ": invalid username\n" );
} else {
- // Allow extensions to prevent user notification when a new message is added to their talk page
+ // Allow extensions to prevent user notification
+ // when a new message is added to their talk page
if ( Hooks::run( 'ArticleEditUpdateNewTalk', array( &$this, $recipient ) ) ) {
if ( User::isIP( $shortTitle ) ) {
// An anonymous user
* @param bool $minor Whereas it's a minor modification
* @param string $serialFormat Format for storing the content in the database
*/
- public function doQuickEditContent( Content $content, User $user, $comment = '', $minor = false,
- $serialFormat = null
+ public function doQuickEditContent(
+ Content $content, User $user, $comment = '', $minor = false, $serialFormat = null
) {
$serialized = $content->serialize( $serialFormat );
__METHOD__
);
- Hooks::run( 'NewRevisionFromEditComplete', array( $this, $nullRevision, $latest, $user ) );
+ Hooks::run( 'NewRevisionFromEditComplete',
+ array( $this, $nullRevision, $latest, $user ) );
Hooks::run( 'ArticleProtectComplete', array( &$this, &$user, $limit, $reason ) );
} else { // Protection of non-existing page (also known as "title protection")
// Cascade protection is meaningless in this case
# with '' filtered out. All possible message keys are listed below:
# * protect-level-autoconfirmed
# * protect-level-sysop
- $restrictionsText = wfMessage( 'protect-level-' . $restrictions )->inContentLanguage()->text();
+ $restrictionsText = wfMessage( 'protect-level-' . $restrictions )
+ ->inContentLanguage()->text();
$expiryText = $this->formatExpiry( $expiry[$action] );
foreach ( array_filter( $limit ) as $action => $restrictions ) {
$expiryText = $this->formatExpiry( $expiry[$action] );
- $protectDescriptionLog .= $wgContLang->getDirMark() . "[$action=$restrictions] ($expiryText)";
+ $protectDescriptionLog .= $wgContLang->getDirMark() .
+ "[$action=$restrictions] ($expiryText)";
}
return trim( $protectDescriptionLog );
*/
protected static function flattenRestrictions( $limit ) {
if ( !is_array( $limit ) ) {
- throw new MWException( 'WikiPage::flattenRestrictions given non-array restriction set' );
+ throw new MWException( __METHOD__ . ' given non-array restriction set' );
}
$bits = array();
$status = Status::newGood();
if ( $this->mTitle->getDBkey() === '' ) {
- $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
+ $status->error( 'cannotdelete',
+ wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
return $status;
}
$user = is_null( $user ) ? $wgUser : $user;
- if ( !Hooks::run( 'ArticleDelete', array( &$this, &$user, &$reason, &$error, &$status ) ) ) {
+ if ( !Hooks::run( 'ArticleDelete',
+ array( &$this, &$user, &$reason, &$error, &$status )
+ ) ) {
if ( $status->isOK() ) {
// Hook aborted but didn't set a fatal status
$status->fatal( 'delete-hook-aborted' );
$dbw->begin( __METHOD__ );
if ( $id == 0 ) {
+ $this->loadPageData( self::READ_LATEST );
+ $id = $this->getID();
// T98706: lock the page from various other updates but avoid using
// WikiPage::READ_LOCKING as that will carry over the FOR UPDATE to
// the revisions queries (which also JOIN on user). Only lock the page
// row and CAS check on page_latest to see if the trx snapshot matches.
- $latest = $this->lock();
-
- $this->loadPageData( WikiPage::READ_LATEST );
- $id = $this->getID();
- if ( $id == 0 || $this->getLatest() != $latest ) {
+ $lockedLatest = $this->lock();
+ if ( $id == 0 || $this->getLatest() != $lockedLatest ) {
// Page not there or trx snapshot is stale
$dbw->rollback( __METHOD__ );
- $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
+ $status->error( 'cannotdelete',
+ wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
return $status;
}
}
if ( !$ok ) {
$dbw->rollback( __METHOD__ );
- $status->error( 'cannotdelete', wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
+ $status->error( 'cannotdelete',
+ wfEscapeWikiText( $this->getTitle()->getPrefixedText() ) );
return $status;
}
$this->doDeleteUpdates( $id, $content );
- Hooks::run( 'ArticleDeleteComplete', array( &$this, &$user, $reason, $id, $content, $logEntry ) );
+ Hooks::run( 'ArticleDeleteComplete',
+ array( &$this, &$user, $reason, $id, $content, $logEntry ) );
$status->value = $logid;
return $status;
}
/**
- * Lock the page row for this title and return page_latest (or 0)
+ * Lock the page row for this title+id and return page_latest (or 0)
*
- * @return integer
+ * @return integer Returns 0 if no row was found with this title+id
*/
protected function lock() {
return (int)wfGetDB( DB_MASTER )->selectField(
'page',
'page_latest',
array(
+ 'page_id' => $this->getId(),
+ // Typically page_id is enough, but some code might try to do
+ // updates assuming the title is the same, so verify that
'page_namespace' => $this->getTitle()->getNamespace(),
'page_title' => $this->getTitle()->getDBkey()
),
// Delete pagelinks, update secondary indexes, etc
$updates = $this->getDeletionUpdates( $content );
- // Make sure an enqueued jobs run after commit so they see the deletion
- wfGetDB( DB_MASTER )->onTransactionIdle( function() use ( $updates ) {
- DataUpdate::runUpdates( $updates, 'enqueue' );
- } );
+ foreach ( $updates as $update ) {
+ DeferredUpdates::addUpdate( $update );
+ }
// Reparse any pages transcluding this page
LinksUpdate::queueRecursiveJobsForTable( $this->mTitle, 'templatelinks' );
}
// raise error, when the edit is an edit without a new version
- if ( empty( $status->value['revision'] ) ) {
+ $statusRev = isset( $status->value['revision'] )
+ ? $status->value['revision']
+ : null;
+ if ( !( $statusRev instanceof Revision ) ) {
$resultDetails = array( 'current' => $current );
return array( array( 'alreadyrolled',
htmlspecialchars( $this->mTitle->getPrefixedText() ),
) );
}
- $revId = $status->value['revision']->getId();
+ $revId = $statusRev->getId();
Hooks::run( 'ArticleRollbackComplete', array( $this, $guser, $target, $current ) );
return;
}
- if ( !Hooks::run( 'OpportunisticLinksUpdate', array( $this, $this->mTitle, $parserOutput ) ) ) {
+ if ( !Hooks::run( 'OpportunisticLinksUpdate',
+ array( $this, $this->mTitle, $parserOutput )
+ ) ) {
return;
}
*/
public function getDeletionUpdates( Content $content = null ) {
if ( !$content ) {
- // load content object, which may be used to determine the necessary updates
- // XXX: the content may not be needed to determine the updates, then this would be overhead.
+ // load content object, which may be used to determine the necessary updates.
+ // XXX: the content may not be needed to determine the updates.
$content = $this->getContent( Revision::RAW );
}
'wgUrlProtocols' => wfUrlProtocols(),
'wgArticlePath' => $conf->get( 'ArticlePath' ),
'wgScriptPath' => $conf->get( 'ScriptPath' ),
- 'wgScriptExtension' => $conf->get( 'ScriptExtension' ),
+ 'wgScriptExtension' => '.php',
'wgScript' => wfScript(),
'wgSearchType' => $conf->get( 'SearchType' ),
'wgVariantArticlePath' => $conf->get( 'VariantArticlePath' ),
$form->setTableId( 'mw-changeemail-table' );
$form->setSubmitTextMsg( 'changeemail-submit' );
$form->addHiddenFields( $this->getRequest()->getValues( 'returnto', 'returntoquery' ) );
+
+ $form->addHeaderText( $this->msg( 'changeemail-header' )->parseAsBlock() );
+ if ( $this->getConfig()->get( 'RequirePasswordforEmailChange' ) ) {
+ $form->addHeaderText( $this->msg( 'changeemail-passwordrequired' )->parseAsBlock() );
+ }
}
public function onSubmit( array $data ) {
}
if ( $title instanceof Title ) {
- $output .= "<li>"
- . Linker::link( $title )
- . ' (' . Linker::link( $title->getTalkPage(), $talk )
- . ")</li>\n";
+ $output .= '<li>' .
+ Linker::link( $title ) . ' ' .
+ $this->msg( 'parentheses' )->rawParams(
+ Linker::link( $title->getTalkPage(), $talk )
+ )->escaped() .
+ "</li>\n";
}
}
$link = '<span class="watchlistredir">' . $link . '</span>';
}
- return $link . " (" . $this->getLanguage()->pipeList( $tools ) . ")";
+ return $link . ' ' .
+ $this->msg( 'parentheses' )->rawParams( $this->getLanguage()->pipeList( $tools ) )->escaped();
}
/**
$dbw = $this->repo->getMasterDb();
// Use a quick transaction since we will upload the full temp file into shared
// storage, which takes time for large files. We don't want to hold locks then.
- $dbw->begin( __METHOD__ );
$dbw->update(
'uploadstash',
array(
array( 'us_key' => $this->mFileKey ),
__METHOD__
);
- $dbw->commit( __METHOD__ );
+ $dbw->commit( __METHOD__, 'flush' );
}
/**
+++ /dev/null
-<?php
-/**
- * Version of index.php to be used in web servers that require the .php5
- * extension to execute scripts with the PHP5 engine.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-define( 'MW_ENTRY_PHP5', true );
-
-require './index.php';
"passwordreset-emailerror-capture": "A password reset email was generated, which is shown below, but sending it to the {{GENDER:$2|user}} failed: $1",
"changeemail": "Change or remove email address",
"changeemail-summary": "",
- "changeemail-text": "Complete this form to change your email address. You will need to enter your password to confirm this change. If you would like to remove the association of any email address from your account, leave the new email address blank when submitting the form.",
+ "changeemail-header": "Complete this form to change your email address. If you would like to remove the association of any email address from your account, leave the new email address blank when submitting the form.",
+ "changeemail-passwordrequired": "You will need to enter your password to confirm this change.",
"changeemail-no-info": "You must be logged in to access this page directly.",
"changeemail-oldemail": "Current email address:",
"changeemail-newemail": "New email address:",
"passwordreset-emailerror-capture": "Error message displayed in [[Special:PasswordReset]] when sending an email fails. Parameters:\n* $1 - error message\n* $2 - username, used for GENDER\nSee also:\n* {{msg-mw|Passwordreset-emailsent}}\n* {{msg-mw|Passwordreset-emailsent-capture}}",
"changeemail": "Title of [[Special:ChangeEmail|special page]]. This page also allows removing the user's email address.",
"changeemail-summary": "{{ignored}}",
- "changeemail-text": "Text of [[Special:ChangeEmail]].",
+ "changeemail-header": "Text of [[Special:ChangeEmail]].",
+ "changeemail-passwordrequired": "Shown on [[Special:ChangeEmail]] if users are required to enter their password to change their email address..",
"changeemail-no-info": "Error message for [[Special:ChangeEmail]].\n\nParameters:\n* $1 (unused) - a link to [[Special:UserLogin]] with {{msg-mw|loginreqlink}} as link description",
"changeemail-oldemail": "Label for e-mail address field in [[Special:ChangeEmail]].",
"changeemail-newemail": "Label for e-mail address field in [[Special:ChangeEmail]]. See also {{msg-mw|changeemail-newemail-help}}",
+++ /dev/null
-<?php
-/**
- * Version of load.php to be used in web servers that require the .php5
- * extension to execute scripts with the PHP5 engine.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-define( 'MW_ENTRY_PHP5', true );
-
-require './load.php';
+++ /dev/null
-<?php
-/**
- * Version of opensearch_desc.php to be used in web servers that require the .php5
- * extension to execute scripts with the PHP5 engine.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-define( 'MW_ENTRY_PHP5', true );
-
-require './opensearch_desc.php';
+++ /dev/null
-<?php
-/**
- * Version of profileinfo.php to be used in web servers that require the .php5
- * extension to execute scripts with the PHP5 engine.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- */
-
-define( 'MW_ENTRY_PHP5', true );
-
-require './profileinfo.php';
} else if ( str === 'load' ) {
return mw.config.get( 'wgLoadScript' );
} else {
- return mw.config.get( 'wgScriptPath' ) + '/' + str +
- mw.config.get( 'wgScriptExtension' );
+ return mw.config.get( 'wgScriptPath' ) + '/' + str + '.php';
}
},
),
);
}
+
+ /**
+ * @covers OutputPage::haveCacheVaryCookies
+ */
+ function testHaveCacheVaryCookies() {
+ $request = new FauxRequest();
+ $context = new RequestContext();
+ $context->setRequest( $request );
+ $outputPage = new OutputPage( $context );
+
+ // No cookies are set.
+ $this->assertFalse( $outputPage->haveCacheVaryCookies() );
+
+ // 'Token' is present but empty, so it shouldn't count.
+ $request->setCookie( 'Token', '' );
+ $this->assertFalse( $outputPage->haveCacheVaryCookies() );
+
+ // 'Token' present and nonempty.
+ $request->setCookie( 'Token', '123' );
+ $this->assertTrue( $outputPage->haveCacheVaryCookies() );
+ }
}
/**
mw.config.set( {
wgScript: '/w/i.php', // customized wgScript for bug 39103
wgLoadScript: '/w/l.php', // customized wgLoadScript for bug 39103
- wgScriptPath: '/w',
- wgScriptExtension: '.php'
+ wgScriptPath: '/w'
} );
assert.equal( mw.util.wikiScript(), mw.config.get( 'wgScript' ),
+++ /dev/null
-<?php
-/**
- * Version of thumb.php to be used in web servers that require the .php5
- * extension to execute scripts with the PHP5 engine.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-define( 'MW_ENTRY_PHP5', true );
-
-require './thumb.php';
+++ /dev/null
-<?php
-/**
- * Version of thumb_handler.php to be used in web servers that require the .php5
- * extension to execute scripts with the PHP5 engine.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Media
- */
-
-define( 'MW_ENTRY_PHP5', true );
-
-require './thumb_handler.php';