diff options
Diffstat (limited to 'includes')
25 files changed, 219 insertions, 91 deletions
diff --git a/includes/AjaxDispatcher.php b/includes/AjaxDispatcher.php index e36787fd..f7583188 100644 --- a/includes/AjaxDispatcher.php +++ b/includes/AjaxDispatcher.php @@ -74,7 +74,7 @@ class AjaxDispatcher { * request. */ function performAction() { - global $wgAjaxExportList, $wgOut; + global $wgAjaxExportList, $wgOut, $wgUser; if ( empty( $this->mode ) ) { return; @@ -90,6 +90,13 @@ class AjaxDispatcher { 'Bad Request', "unknown function " . (string) $this->func_name ); + } elseif ( !in_array( 'read', User::getGroupPermissions( array( '*' ) ), true ) + && !$wgUser->isAllowed( 'read' ) ) + { + wfHttpError( + 403, + 'Forbidden', + 'You must log in to view pages.' ); } else { wfDebug( __METHOD__ . ' dispatching ' . $this->func_name . "\n" ); diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index f1605a56..347ed694 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -707,6 +707,8 @@ $wgAutoloadLocalClasses = array( 'DeleteArchivedRevisionsImplementation' => 'maintenance/deleteArchivedRevisions.inc', 'DeleteDefaultMessages' => 'maintenance/deleteDefaultMessages.php', 'DummyTermColorer' => 'maintenance/tests/testHelpers.inc', + 'FakeMaintenance' => 'maintenance/Maintenance.php', + 'Maintenance' => 'maintenance/Maintenance.php', 'ParserTest' => 'maintenance/tests/parser/parserTest.inc', 'ParserTestParserHook' => 'maintenance/tests/parser/parserTestsParserHook.php', 'ParserTestStaticParserHook' => 'maintenance/tests/parser/parserTestsStaticParserHook.php', diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index ae6fc1b7..0395633d 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -34,7 +34,7 @@ if ( !defined( 'MW_PHP4' ) ) { /** @endcond */ /** MediaWiki version number */ -$wgVersion = '1.17.0'; +$wgVersion = '1.17.1'; /** Name of the site. It must be changed in LocalSettings.php */ $wgSitename = 'MediaWiki'; @@ -2928,11 +2928,6 @@ $wgPasswordSalt = true; $wgMinimalPasswordLength = 1; /** - * Enabes or disables JavaScript-based suggestions of password strength - */ -$wgLivePasswordStrengthChecks = false; - -/** * Maximum number of Unicode characters in signature */ $wgMaxSigChars = 255; diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index b21779c1..2c35568b 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -1341,10 +1341,11 @@ function wfTime() { /** * Sets dest to source and returns the original value of dest * If source is NULL, it just returns the value, it doesn't set the variable + * If force is true, it will set the value even if source is NULL */ -function wfSetVar( &$dest, $source ) { +function wfSetVar( &$dest, $source, $force = false ) { $temp = $dest; - if ( !is_null( $source ) ) { + if ( !is_null( $source ) || $force ) { $dest = $source; } return $temp; diff --git a/includes/HttpFunctions.php b/includes/HttpFunctions.php index e6124426..3d4d77a9 100644 --- a/includes/HttpFunctions.php +++ b/includes/HttpFunctions.php @@ -200,6 +200,15 @@ class MWHttpRequest { } /** + * Simple function to test if we can make any sort of requests at all, using + * cURL or fopen() + * @return bool + */ + public static function canMakeRequests() { + return function_exists( 'curl_init' ) || wfIniGetBool( 'allow_url_fopen' ); + } + + /** * Generate a new request object * @see MWHttpRequest::__construct */ diff --git a/includes/IP.php b/includes/IP.php index 5f492c66..50d57583 100644 --- a/includes/IP.php +++ b/includes/IP.php @@ -303,7 +303,7 @@ class IP { static $privateRanges = false; if ( !$privateRanges ) { $privateRanges = array( - array( 'fc::', 'fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' ), # RFC 4193 (local) + array( 'fc00::', 'fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff' ), # RFC 4193 (local) array( '0:0:0:0:0:0:0:1', '0:0:0:0:0:0:0:1' ), # loopback ); } diff --git a/includes/MessageCache.php b/includes/MessageCache.php index cc14ec2b..a111211f 100644 --- a/includes/MessageCache.php +++ b/includes/MessageCache.php @@ -677,8 +677,9 @@ class MessageCache { $popts = $this->getParserOptions(); $popts->setInterfaceMessage( $interface ); $popts->setTargetLanguage( $language ); - $popts->setUserLang( $language ); + $userlang = $popts->setUserLang( $language ); $message = $this->mParser->transformMsg( $message, $popts ); + $popts->setUserLang( $userlang ); } return $message; } diff --git a/includes/ObjectCache.php b/includes/ObjectCache.php index db22c074..05ae9c9c 100644 --- a/includes/ObjectCache.php +++ b/includes/ObjectCache.php @@ -66,7 +66,7 @@ function &wfGetCache( $inputType ) { $wgCaches[CACHE_ACCEL] = new eAccelBagOStuff; } elseif ( function_exists( 'apc_fetch') ) { $wgCaches[CACHE_ACCEL] = new APCBagOStuff; - } elseif( function_exists( 'xcache_get' ) ) { + } elseif( function_exists( 'xcache_get' ) && wfIniGetBool( 'xcache.var_size' ) ) { $wgCaches[CACHE_ACCEL] = new XCacheBagOStuff(); } elseif( function_exists( 'wincache_ucache_get' ) ) { $wgCaches[CACHE_ACCEL] = new WinCacheBagOStuff(); diff --git a/includes/SkinTemplate.php b/includes/SkinTemplate.php index cfb67250..023afdd8 100644 --- a/includes/SkinTemplate.php +++ b/includes/SkinTemplate.php @@ -549,11 +549,22 @@ class SkinTemplate extends Skin { /* set up the default links for the personal toolbar */ $personal_urls = array(); - $page = $wgRequest->getVal( 'returnto', $this->thisurl ); - $query = $wgRequest->getVal( 'returntoquery', $this->thisquery ); - $returnto = "returnto=$page"; - if( $this->thisquery != '' ) - $returnto .= "&returntoquery=$query"; + + # Due to bug 32276, if a user does not have read permissions, + # $wgOut->getTitle() will just give Special:Badtitle, which is + # not especially useful as a returnto parameter. Use the title + # from the request instead, if there was one. + $page = Title::newFromURL( $wgRequest->getVal( 'title', '' ) ); + $page = $wgRequest->getVal( 'returnto', $page ); + $returnto = ''; + if( strval( $page ) !== '' ) { + $returnto = "returnto=$page"; + $query = $wgRequest->getVal( 'returntoquery', $this->thisquery ); + if( $query != '' ) { + $returnto .= "&returntoquery=$query"; + } + } + if( $this->loggedin ) { $personal_urls['userpage'] = array( 'text' => $this->username, diff --git a/includes/Wiki.php b/includes/Wiki.php index b2cb1eb0..4c3af0f7 100644 --- a/includes/Wiki.php +++ b/includes/Wiki.php @@ -149,10 +149,21 @@ class MediaWiki { * @return boolean true if successful */ function preliminaryChecks( &$title, &$output ) { + global $wgTitle; // If the user is not logged in, the Namespace:title of the article must be in // the Read array in order for the user to see it. (We have to check here to // catch special pages etc. We check again in Article::view()) if( !is_null( $title ) && !$title->userCanRead() ) { + // Bug 32276: allowing the skin to generate output with $wgTitle + // set to the input title would allow anonymous users to + // determine whether a page exists, potentially leaking private data. In fact, the + // curid and oldid request parameters would allow page titles to be enumerated even + // when they are not guessable. So we reset the title to Special:Badtitle before the + // permissions error is displayed. + $badtitle = SpecialPage::getTitleFor( 'Badtitle' ); + $output->setTitle( $badtitle ); + $wgTitle = $badtitle; + $output->loginToUse(); $this->finalCleanup( $output ); $output->disable(); diff --git a/includes/db/DatabaseOracle.php b/includes/db/DatabaseOracle.php index 4fe3e980..3c4d00ac 100644 --- a/includes/db/DatabaseOracle.php +++ b/includes/db/DatabaseOracle.php @@ -275,6 +275,8 @@ class DatabaseOracle extends DatabaseBase { # removed putenv calls because they interfere with the system globaly $this->doQuery( 'ALTER SESSION SET NLS_TIMESTAMP_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'' ); $this->doQuery( 'ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT=\'DD-MM-YYYY HH24:MI:SS.FF6\'' ); + $this->doQuery( 'ALTER SESSION SET NLS_NUMERIC_CHARACTERS=\'.,\'' ); + return $this->mConn; } @@ -490,6 +492,10 @@ class DatabaseOracle extends DatabaseBase { $val = null; } + if ( $val === 'NULL' ) { + $val = null; + } + if ( $val === null ) { if ( $col_info != false && $col_info->isNullable() == 0 && $col_info->defaultValue() != null ) { $bind .= 'DEFAULT'; @@ -771,15 +777,23 @@ class DatabaseOracle extends DatabaseBase { foreach ( $rows as $row ) { # Delete rows which collide if ( $uniqueIndexes ) { - $condsDelete = array(); - foreach ( $uniqueIndexes as $index ) { - $condsDelete[$index] = $row[$index]; - } - if ( count( $condsDelete ) > 0 ) { - $this->delete( $table, $condsDelete, $fname ); + $deleteConds = array(); + foreach ( $uniqueIndexes as $key=>$index ) { + if ( is_array( $index ) ) { + $deleteConds2 = array(); + foreach ( $index as $col ) { + $deleteConds2[$col] = $row[$col]; + } + $deleteConds[$key] = $this->makeList( $deleteConds2, LIST_AND ); + } else { + $deleteConds[$index] = $row[$index]; + } } + $deleteConds = array( $this->makeList( $deleteConds, LIST_OR ) ); + $this->delete( $table, $deleteConds, $fname ); } + if ( $sequenceData !== false && !isset( $row[$sequenceData['column']] ) ) { $row[$sequenceData['column']] = $this->nextSequenceValue( $sequenceData['sequence'] ); } @@ -1146,28 +1160,41 @@ class DatabaseOracle extends DatabaseBase { return $s; } - function selectRow( $table, $vars, $conds, $fname = 'DatabaseOracle::selectRow', $options = array(), $join_conds = array() ) { + private function wrapFieldForWhere( $table, &$col, &$val ) { global $wgContLang; + + $col_info = $this->fieldInfoMulti( $table, $col ); + $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; + if ( $col_type == 'CLOB' ) { + $col = 'TO_CHAR(' . $col . ')'; + $val = $wgContLang->checkTitleEncoding( $val ); + } elseif ( $col_type == 'VARCHAR2' && !mb_check_encoding( $val ) ) { + $val = $wgContLang->checkTitleEncoding( $val ); + } + } - if ($conds != null) { - $conds2 = array(); - $conds = ( !is_array( $conds ) ) ? array( $conds ) : $conds; - foreach ( $conds as $col => $val ) { - $col_info = $this->fieldInfoMulti( $table, $col ); - $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; - if ( $col_type == 'CLOB' ) { - $conds2['TO_CHAR(' . $col . ')'] = $wgContLang->checkTitleEncoding( $val ); - } elseif ( $col_type == 'VARCHAR2' && !mb_check_encoding( $val ) ) { - $conds2[$col] = $wgContLang->checkTitleEncoding( $val ); + private function wrapConditionsForWhere ( $table, $conds, $parentCol = null ) { + $conds2 = array(); + foreach ( $conds as $col => $val ) { + if ( is_array( $val ) ) { + $conds2[$col] = $this->wrapConditionsForWhere ( $table, $val, $col ); + } else { + if ( is_numeric( $col ) && $parentCol != null ) { + $this->wrapFieldForWhere ( $table, $parentCol, $val ); } else { - $conds2[$col] = $val; + $this->wrapFieldForWhere ( $table, $col, $val ); } + $conds2[$col] = $val; } + } + return $conds2; + } - return parent::selectRow( $table, $vars, $conds2, $fname, $options, $join_conds ); - } else { - return parent::selectRow( $table, $vars, $conds, $fname, $options, $join_conds ); + function selectRow( $table, $vars, $conds, $fname = 'DatabaseOracle::selectRow', $options = array(), $join_conds = array() ) { + if ( is_array($conds) ) { + $conds = $this->wrapConditionsForWhere( $table, $conds ); } + return parent::selectRow( $table, $vars, $conds, $fname, $options, $join_conds ); } /** @@ -1214,32 +1241,10 @@ class DatabaseOracle extends DatabaseBase { } public function delete( $table, $conds, $fname = 'DatabaseOracle::delete' ) { - global $wgContLang; - - if ( $wgContLang != null && $conds != null && $conds != '*' ) { - $conds2 = array(); - $conds = ( !is_array( $conds ) ) ? array( $conds ) : $conds; - foreach ( $conds as $col => $val ) { - $col_info = $this->fieldInfoMulti( $table, $col ); - $col_type = $col_info != false ? $col_info->type() : 'CONSTANT'; - if ( $col_type == 'CLOB' ) { - $conds2['TO_CHAR(' . $col . ')'] = $wgContLang->checkTitleEncoding( $val ); - } else { - if ( is_array( $val ) ) { - $conds2[$col] = $val; - foreach ( $conds2[$col] as &$val2 ) { - $val2 = $wgContLang->checkTitleEncoding( $val2 ); - } - } else { - $conds2[$col] = $wgContLang->checkTitleEncoding( $val ); - } - } - } - - return parent::delete( $table, $conds2, $fname ); - } else { - return parent::delete( $table, $conds, $fname ); + if ( is_array($conds) ) { + $conds = $this->wrapConditionsForWhere( $table, $conds ); } + return parent::delete( $table, $conds, $fname ); } function update( $table, $values, $conds, $fname = 'DatabaseOracle::update', $options = array() ) { @@ -1262,6 +1267,7 @@ class DatabaseOracle extends DatabaseBase { } if ( $conds != '*' ) { + $conds = $this->wrapConditionsForWhere( $table, $conds ); $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND ); } diff --git a/includes/filerepo/ForeignDBRepo.php b/includes/filerepo/ForeignDBRepo.php index 590350b4..a756703f 100644 --- a/includes/filerepo/ForeignDBRepo.php +++ b/includes/filerepo/ForeignDBRepo.php @@ -37,7 +37,7 @@ class ForeignDBRepo extends LocalRepo { if ( !isset( $this->dbConn ) ) { $this->dbConn = DatabaseBase::newFromType( $this->dbType, array( - 'server' => $this->dbServer, + 'host' => $this->dbServer, 'user' => $this->dbUser, 'password' => $this->dbPassword, 'dbname' => $this->dbName, diff --git a/includes/installer/DatabaseUpdater.php b/includes/installer/DatabaseUpdater.php index 79928d1f..57d82ea3 100644 --- a/includes/installer/DatabaseUpdater.php +++ b/includes/installer/DatabaseUpdater.php @@ -99,7 +99,7 @@ abstract class DatabaseUpdater { if ( !$vars ) { return; // no LocalSettings found } - if ( !isset( $vars['wgHooks'] ) && !isset( $vars['wgHooks']['LoadExtensionSchemaUpdates'] ) ) { + if ( !isset( $vars['wgHooks'] ) || !isset( $vars['wgHooks']['LoadExtensionSchemaUpdates'] ) ) { return; } global $wgHooks, $wgAutoloadClasses; diff --git a/includes/installer/Installer.i18n.php b/includes/installer/Installer.i18n.php index d6a8a757..dc3147a7 100644 --- a/includes/installer/Installer.i18n.php +++ b/includes/installer/Installer.i18n.php @@ -503,6 +503,7 @@ Skipping default list.", 'config-insecure-keys' => "'''Warning:''' {{PLURAL:$2|A secure key|Secure keys}} ($1) generated during installation {{PLURAL:$2|is|are}} not completely safe. Consider changing {{PLURAL:$2|it|them}} manually.", 'config-install-sysop' => 'Creating administrator user account', 'config-install-subscribe-fail' => 'Unable to subscribe to mediawiki-announce: $1', + 'config-install-subscribe-notpossible' => 'cURL is not installed and allow_url_fopen is not available.', 'config-install-mainpage' => 'Creating main page with default content', 'config-install-extension-tables' => 'Creating tables for enabled extensions', 'config-install-mainpage-failed' => 'Could not insert main page: $1', diff --git a/includes/installer/Installer.php b/includes/installer/Installer.php index 6da4f100..9ae5e3f3 100644 --- a/includes/installer/Installer.php +++ b/includes/installer/Installer.php @@ -643,7 +643,7 @@ abstract class Installer { * Environment check for register_globals. */ protected function envCheckRegisterGlobals() { - if( wfIniGetBool( "magic_quotes_runtime" ) ) { + if( wfIniGetBool( 'register_globals' ) ) { $this->showMessage( 'config-register-globals' ); } } @@ -782,6 +782,9 @@ abstract class Installer { $caches = array(); foreach ( $this->objectCaches as $name => $function ) { if ( function_exists( $function ) ) { + if ( $name == 'xcache' && !wfIniGetBool( 'xcache.var_size' ) ) { + continue; + } $caches[$name] = true; } } @@ -1441,10 +1444,14 @@ abstract class Installer { $params['language'] = $myLang; } - $res = MWHttpRequest::factory( $this->mediaWikiAnnounceUrl, - array( 'method' => 'POST', 'postData' => $params ) )->execute(); - if( !$res->isOK() ) { - $s->warning( 'config-install-subscribe-fail', $res->getMessage() ); + if( MWHttpRequest::canMakeRequests() ) { + $res = MWHttpRequest::factory( $this->mediaWikiAnnounceUrl, + array( 'method' => 'POST', 'postData' => $params ) )->execute(); + if( !$res->isOK() ) { + $s->warning( 'config-install-subscribe-fail', $res->getMessage() ); + } + } else { + $s->warning( 'config-install-subscribe-notpossible' ); } } diff --git a/includes/installer/LocalSettingsGenerator.php b/includes/installer/LocalSettingsGenerator.php index 04926c9b..2d7fd252 100644 --- a/includes/installer/LocalSettingsGenerator.php +++ b/includes/installer/LocalSettingsGenerator.php @@ -129,7 +129,7 @@ class LocalSettingsGenerator { foreach( $this->extensions as $extName ) { $encExtName = self::escapePhpString( $extName ); - $localSettings .= "require( \"extensions/$encExtName/$encExtName.php\" );\n"; + $localSettings .= "require_once( \"extensions/$encExtName/$encExtName.php\" );\n"; } } diff --git a/includes/installer/OracleUpdater.php b/includes/installer/OracleUpdater.php index 4d85924e..7664a418 100644 --- a/includes/installer/OracleUpdater.php +++ b/includes/installer/OracleUpdater.php @@ -21,6 +21,7 @@ class OracleUpdater extends DatabaseUpdater { array( 'doFunctions17' ), array( 'doSchemaUpgrade17' ), array( 'doInsertPage0' ), + array( 'doRemoveNotNullEmptyDefaults' ), ); } @@ -103,6 +104,21 @@ class OracleUpdater extends DatabaseUpdater { } /** + * Remove DEFAULT '' NOT NULL constraints from fields as '' is internally + * converted to NULL in Oracle + */ + protected function doRemoveNotNullEmptyDefaults() { + $this->output( "Removing not null empty constraints ... " ); + $meta = $this->db->fieldInfo( 'categorylinks' , 'cl_sortkey_prefix' ); + if ( $meta->isNullable() ) { + $this->output( "constraints seem to be removed\n" ); + return; + } + $this->applyPatch( 'patch_remove_not_null_empty_defs.sql', false ); + $this->output( "ok\n" ); + } + + /** * Overload: after this action field info table has to be rebuilt */ public function doUpdates( $what = array( 'core', 'extensions', 'purge' ) ) { diff --git a/includes/media/SVG.php b/includes/media/SVG.php index 9a8484f1..a78be952 100644 --- a/includes/media/SVG.php +++ b/includes/media/SVG.php @@ -49,14 +49,23 @@ class SvgHandler extends ImageHandler { if ( !parent::normaliseParams( $image, $params ) ) { return false; } - # Don't make an image bigger than wgMaxSVGSize + # Don't make an image bigger than wgMaxSVGSize on the smaller side $params['physicalWidth'] = $params['width']; $params['physicalHeight'] = $params['height']; - if ( $params['physicalWidth'] > $wgSVGMaxSize ) { - $srcWidth = $image->getWidth( $params['page'] ); - $srcHeight = $image->getHeight( $params['page'] ); - $params['physicalWidth'] = $wgSVGMaxSize; - $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, $wgSVGMaxSize ); + if ( $params['physicalWidth'] <= $params['physicalHeight'] ) { + if ( $params['physicalWidth'] > $wgSVGMaxSize ) { + $srcWidth = $image->getWidth( $params['page'] ); + $srcHeight = $image->getHeight( $params['page'] ); + $params['physicalWidth'] = $wgSVGMaxSize; + $params['physicalHeight'] = File::scaleHeight( $srcWidth, $srcHeight, $wgSVGMaxSize ); + } + } else { + if ( $params['physicalHeight'] > $wgSVGMaxSize ) { + $srcWidth = $image->getWidth( $params['page'] ); + $srcHeight = $image->getHeight( $params['page'] ); + $params['physicalWidth'] = File::scaleHeight( $srcHeight, $srcWidth, $wgSVGMaxSize ); + $params['physicalHeight'] = $wgSVGMaxSize; + } } return true; } diff --git a/includes/parser/ParserOptions.php b/includes/parser/ParserOptions.php index 9d8b3e4f..1bda0792 100644 --- a/includes/parser/ParserOptions.php +++ b/includes/parser/ParserOptions.php @@ -125,7 +125,7 @@ class ParserOptions { function setTidy( $x ) { return wfSetVar( $this->mTidy, $x); } function setSkin( $x ) { $this->mSkin = $x; } function setInterfaceMessage( $x ) { return wfSetVar( $this->mInterfaceMessage, $x); } - function setTargetLanguage( $x ) { return wfSetVar( $this->mTargetLanguage, $x); } + function setTargetLanguage( $x ) { return wfSetVar( $this->mTargetLanguage, $x, true ); } function setMaxIncludeSize( $x ) { return wfSetVar( $this->mMaxIncludeSize, $x ); } function setMaxPPNodeCount( $x ) { return wfSetVar( $this->mMaxPPNodeCount, $x ); } function setMaxTemplateDepth( $x ) { return wfSetVar( $this->mMaxTemplateDepth, $x ); } diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index c18022a4..191bc9f0 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -96,7 +96,8 @@ class ResourceLoader { ), __METHOD__ ); foreach ( $res as $row ) { - $this->getModule( $row->mr_resource )->setMsgBlobMtime( $lang, $row->mr_timestamp ); + $this->getModule( $row->mr_resource )->setMsgBlobMtime( $lang, + wfTimestamp( TS_UNIX, $row->mr_timestamp ) ); unset( $modulesWithoutMessages[$row->mr_resource] ); } } diff --git a/includes/resourceloader/ResourceLoaderFileModule.php b/includes/resourceloader/ResourceLoaderFileModule.php index 44967a2e..1c37eb07 100644 --- a/includes/resourceloader/ResourceLoaderFileModule.php +++ b/includes/resourceloader/ResourceLoaderFileModule.php @@ -360,7 +360,7 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { } wfProfileIn( __METHOD__.'-filemtime' ); - $filesMtime = max( array_map( 'filemtime', $files ) ); + $filesMtime = max( array_map( array( __CLASS__, 'safeFilemtime' ), $files ) ); wfProfileOut( __METHOD__.'-filemtime' ); $this->modifiedTime[$context->getHash()] = max( $filesMtime, @@ -441,13 +441,20 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { if ( empty( $scripts ) ) { return ''; } + global $wgResourceLoaderValidateStaticJS; $js = ''; foreach ( array_unique( $scripts ) as $fileName ) { $localPath = $this->getLocalPath( $fileName ); - $contents = file_get_contents( $localPath ); - if ( $contents === false ) { + if ( !file_exists( $localPath ) ) { throw new MWException( __METHOD__.": script file not found: \"$localPath\"" ); } + $contents = file_get_contents( $localPath ); + if ( $wgResourceLoaderValidateStaticJS ) { + // Static files don't really need to be checked as often; unlike + // on-wiki module they shouldn't change unexpectedly without + // admin interference. + $contents = $this->validateScriptFile( $fileName, $contents ); + } $js .= $contents . "\n"; } return $js; @@ -484,15 +491,16 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { * * This method can be used as a callback for array_map() * - * @param $path String: File path of script file to read + * @param $path String: File path of style file to read * @return String: CSS data in script file + * @throws MWException if the file doesn't exist */ protected function readStyleFile( $path, $flip ) { $localPath = $this->getLocalPath( $path ); - $style = file_get_contents( $localPath ); - if ( $style === false ) { + if ( !file_exists( $localPath ) ) { throw new MWException( __METHOD__.": style file not found: \"$localPath\"" ); } + $style = file_get_contents( $localPath ); if ( $flip ) { $style = CSSJanus::transform( $style, true, false ); } @@ -506,4 +514,30 @@ class ResourceLoaderFileModule extends ResourceLoaderModule { $style, $dir, $remoteDir, true ); } + + /** + * Safe version of filemtime(), which doesn't throw a PHP warning if the file doesn't exist + * but returns 1 instead. + * @param $filename string File name + * @return int UNIX timestamp, or 1 if the file doesn't exist + */ + protected static function safeFilemtime( $filename ) { + if ( file_exists( $filename ) ) { + return filemtime( $filename ); + } else { + // We only ever map this function on an array if we're gonna call max() after, + // so return our standard minimum timestamps here. This is 1, not 0, because + // wfTimestamp(0) == NOW + return 1; + } + } + + /** + * Get whether CSS for this module should be flipped + * @param $context ResourceLoaderContext + * @return bool + */ + public function getFlip( $context ) { + return $context->getDirection() === 'rtl'; + } } diff --git a/includes/resourceloader/ResourceLoaderStartUpModule.php b/includes/resourceloader/ResourceLoaderStartUpModule.php index 2a3ba343..f3117378 100644 --- a/includes/resourceloader/ResourceLoaderStartUpModule.php +++ b/includes/resourceloader/ResourceLoaderStartUpModule.php @@ -119,7 +119,10 @@ class ResourceLoaderStartUpModule extends ResourceLoaderModule { } // Automatically register module else { - $mtime = max( $module->getModifiedTime( $context ), wfTimestamp( TS_UNIX, $wgCacheEpoch ) ); + // getModifiedTime() is supposed to return a UNIX timestamp, but it doesn't always + // seem to do that, and custom implementations might forget. Coerce it to TS_UNIX + $moduleMtime = wfTimestamp( TS_UNIX, $module->getModifiedTime( $context ) ); + $mtime = max( $moduleMtime, wfTimestamp( TS_UNIX, $wgCacheEpoch ) ); // Modules without dependencies or a group pass two arguments (name, timestamp) to // mediaWiki.loader.register() if ( !count( $module->getDependencies() && $module->getGroup() === null ) ) { diff --git a/includes/resourceloader/ResourceLoaderUserOptionsModule.php b/includes/resourceloader/ResourceLoaderUserOptionsModule.php index ae654b8f..61c76940 100644 --- a/includes/resourceloader/ResourceLoaderUserOptionsModule.php +++ b/includes/resourceloader/ResourceLoaderUserOptionsModule.php @@ -40,7 +40,7 @@ class ResourceLoaderUserOptionsModule extends ResourceLoaderModule { global $wgUser; if ( $context->getUser() === $wgUser->getName() ) { - return $this->modifiedTime[$hash] = $wgUser->getTouched(); + return $this->modifiedTime[$hash] = wfTimestamp( TS_UNIX, $wgUser->getTouched() ); } else { return 1; } diff --git a/includes/specials/SpecialUnusedcategories.php b/includes/specials/SpecialUnusedcategories.php index a20efe09..ff2a66e1 100644 --- a/includes/specials/SpecialUnusedcategories.php +++ b/includes/specials/SpecialUnusedcategories.php @@ -49,6 +49,13 @@ class UnusedCategoriesPage extends QueryPage { AND page_is_redirect = 0"; } + /** + * A should come before Z (bug 30907) + */ + function sortDescending() { + return false; + } + function formatResult( $skin, $result ) { $title = Title::makeTitle( NS_CATEGORY, $result->title ); return $skin->link( $title, $title->getText() ); diff --git a/includes/templates/NoLocalSettings.php b/includes/templates/NoLocalSettings.php index 9001e3ba..facb6167 100644 --- a/includes/templates/NoLocalSettings.php +++ b/includes/templates/NoLocalSettings.php @@ -9,10 +9,17 @@ if ( !isset( $wgVersion ) ) { $wgVersion = 'VERSION'; } -$script = $_SERVER['SCRIPT_NAME']; -$path = pathinfo( $script, PATHINFO_DIRNAME ) . '/'; -$path = str_replace( '//', '/', $path ); -$ext = pathinfo( $script, PATHINFO_EXTENSION ); + +$matches = array(); +$ext = 'php'; +$path = '/'; +foreach( array_filter( explode( '/', $_SERVER['PHP_SELF'] ) ) as $part ) { + if( !preg_match( '/\.(php5?)$/', $part, $matches ) ) { + $path .= "$part/"; + } else { + $ext = $matches[1] == 'php5' ? 'php5' : 'php'; + } +} # Check to see if the installer is running if ( !function_exists( 'session_name' ) ) { |