Make Title::makeTitleSafe() not need user variant
authorBrad Jorsch <bjorsch@wikimedia.org>
Wed, 19 Nov 2014 17:51:27 +0000 (12:51 -0500)
committerAnomie <bjorsch@wikimedia.org>
Wed, 19 Nov 2014 18:22:32 +0000 (18:22 +0000)
In trying to avoid hitting RequestContext::getLanguage() from a call to
User::idFromName(), I05aacd30 made it no longer safe for user input.

A closer analysis of the call stack involved reveals that
Title::makeTitleSafe() is constructing a prefixed dbkey using the
localized name for NS_USER, and then Language::getNsIndex() is needing
to get the variant in order to handle that localized name. But if we use
the canonical name for NS_USER, Language::getNsIndex() short-circuits
and skips the problematic code path.

And it turns out that it doesn't actually matter which prefix
Title::makeTitleSafe() uses, since the prefix doesn't make it anywhere
into the resulting Title object. So let's revert I05aacd30 and Ibeef0409
and just do that instead.

Change-Id: Ib902573996c69d1e77527cc7b2faf4e7fa5d3daf

includes/Title.php
includes/User.php

index b97d36a..f913859 100644 (file)
@@ -503,7 +503,7 @@ class Title {
                }
 
                $t = new Title();
-               $t->mDbkeyform = Title::makeName( $ns, $title, $fragment, $interwiki );
+               $t->mDbkeyform = Title::makeName( $ns, $title, $fragment, $interwiki, true );
                if ( $t->secureAndSplit() ) {
                        return $t;
                } else {
@@ -747,12 +747,20 @@ class Title {
         * @param string $title The DB key form the title
         * @param string $fragment The link fragment (after the "#")
         * @param string $interwiki The interwiki prefix
+        * @param boolean $canoncialNamespace If true, use the canonical name for
+        *   $ns instead of the localized version.
         * @return string The prefixed form of the title
         */
-       public static function makeName( $ns, $title, $fragment = '', $interwiki = '' ) {
+       public static function makeName( $ns, $title, $fragment = '', $interwiki = '',
+               $canoncialNamespace = false
+       ) {
                global $wgContLang;
 
-               $namespace = $wgContLang->getNsText( $ns );
+               if ( $canoncialNamespace ) {
+                       $namespace = MWNamespace::getCanonicalName( $ns );
+               } else {
+                       $namespace = $wgContLang->getNsText( $ns );
+               }
                $name = $namespace == '' ? $title : "$namespace:$title";
                if ( strval( $interwiki ) != '' ) {
                        $name = "$interwiki:$name";
index feaf364..8fcdab2 100644 (file)
@@ -565,15 +565,16 @@ class User implements IDBAccessObject {
         * @return int|null The corresponding user's ID, or null if user is nonexistent
         */
        public static function idFromName( $name ) {
+               $nt = Title::makeTitleSafe( NS_USER, $name );
+               if ( is_null( $nt ) ) {
+                       // Illegal name
+                       return null;
+               }
+
                if ( isset( self::$idCacheByName[$name] ) ) {
                        return self::$idCacheByName[$name];
                }
 
-               // We don't want to call Title::makeTitleSafe yet, since that call path
-               // ends up needing the user language, which ends up trying to load the
-               // user object, which ends up back here (bug 54193).
-               $nt = Title::makeTitle( NS_USER, Title::capitalize( $name, NS_USER ) );
-
                $dbr = wfGetDB( DB_SLAVE );
                $s = $dbr->selectRow(
                        'user',