Followup for r81340:
authorTim Starling <tstarling@users.mediawiki.org>
Mon, 28 Feb 2011 03:15:39 +0000 (03:15 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Mon, 28 Feb 2011 03:15:39 +0000 (03:15 +0000)
* Allow any language code which consists entirely of valid title characters, and does not contain any path-traversal characters, to be customised via the uselang parameter. Language::isValidCode() represents this concept.
* Add some shortcuts preventing Language and LocalisationCache from looking for localisation files for a language code which does not follow the usual form of language codes in MediaWiki, i.e. /[a-z-]*/. This concept is represented by Language::isValidBuiltInCode().
* Do not allow colon characters in file names, per Platonides' suggestion on CR.

includes/LocalisationCache.php
languages/Language.php

index 888722a..e987104 100644 (file)
@@ -343,6 +343,12 @@ class LocalisationCache {
                }
                $this->initialisedLangs[$code] = true;
 
+               # If the code is of the wrong form for a Messages*.php file, do a shallow fallback
+               if ( !Language::isValidBuiltInCode( $code ) ) {
+                       $this->initShallowFallback( $code, 'en' );
+                       return;
+               }
+
                # Recache the data if necessary
                if ( !$this->manualRecache && $this->isExpired( $code ) ) {
                        if ( file_exists( Language::getMessagesFileName( $code ) ) ) {
index 3501bd5..3fa1032 100644 (file)
@@ -157,11 +157,19 @@ class Language {
 
                // Protect against path traversal below
                if ( !Language::isValidCode( $code ) 
-                       || strcspn( $code, "/\\\000" ) !== strlen( $code ) ) 
+                       || strcspn( $code, ":/\\\000" ) !== strlen( $code ) ) 
                {
                        throw new MWException( "Invalid language code \"$code\"" );
                }
 
+               if ( !Language::isValidBuiltInCode( $code ) ) {
+                       // It's not possible to customise this code with class files, so 
+                       // just return a Language object. This is to support uselang= hacks.
+                       $lang = new Language;
+                       $lang->setCode( $code );
+                       return $lang;
+               }
+
                if ( $code == 'en' ) {
                        $class = 'Language';
                } else {
@@ -193,10 +201,21 @@ class Language {
 
        /**
         * Returns true if a language code string is of a valid form, whether or 
-        * not it exists.
+        * not it exists. This includes codes which are used solely for 
+        * customisation via the MediaWiki namespace.
         */
        public static function isValidCode( $code ) {
-               return strcspn( $code, "/\\\000" ) === strlen( $code );
+               return 
+                       strcspn( $code, ":/\\\000" ) === strlen( $code )
+                       && !preg_match( Title::getTitleInvalidRegex(), $code );
+       }
+
+       /**
+        * Returns true if a language code is of a valid form for the purposes of 
+        * internal customisation of MediaWiki, via Messages*.php.
+        */
+       public static function isValidBuiltInCode( $code ) {
+               return preg_match( '/^[a-z0-9-]*$/', $code );
        }
 
        /**
@@ -2859,7 +2878,7 @@ class Language {
        static function getFileName( $prefix = 'Language', $code, $suffix = '.php' ) {
                // Protect against path traversal
                if ( !Language::isValidCode( $code ) 
-                       || strcspn( $code, "/\\\000" ) !== strlen( $code ) ) 
+                       || strcspn( $code, ":/\\\000" ) !== strlen( $code ) ) 
                {
                        throw new MWException( "Invalid language code \"$code\"" );
                }