Remove a few unused globals.
[lhc/web/wiklou.git] / includes / Title.php
index dad2bc4..55d8461 100644 (file)
@@ -4,21 +4,22 @@
  * @file
  */
 
-/** */
 if ( !class_exists( 'UtfNormal' ) ) {
        require_once( dirname(__FILE__) . '/normal/UtfNormal.php' );
 }
 
 define ( 'GAID_FOR_UPDATE', 1 );
 
-# Title::newFromTitle maintains a cache to avoid
-# expensive re-normalization of commonly used titles.
-# On a batch operation this can become a memory leak
-# if not bounded. After hitting this many titles,
-# reset the cache.
+/**
+ * Title::newFromText maintains a cache to avoid expensive re-normalization of
+ * commonly used titles. On a batch operation this can become a memory leak
+ * if not bounded. After hitting this many titles reset the cache.
+ */
 define( 'MW_TITLECACHE_MAX', 1000 );
 
-# Constants for pr_cascade bitfield
+/**
+ * Constants for pr_cascade bitfield
+ */
 define( 'CASCADE', 1 );
 
 /**
@@ -44,27 +45,30 @@ class Title {
         * @private
         */
 
-       var $mTextform;                 # Text form (spaces not underscores) of the main part
-       var $mUrlform;                  # URL-encoded form of the main part
-       var $mDbkeyform;                # Main part with underscores
-       var $mUserCaseDBKey;        # DB key with the initial letter in the case specified by the user
-       var $mNamespace;                # Namespace index, i.e. one of the NS_xxxx constants
-       var $mInterwiki;                # Interwiki prefix (or null string)
-       var $mFragment;                 # Title fragment (i.e. the bit after the #)
-       var $mArticleID;                # Article ID, fetched from the link cache on demand
-       var $mLatestID;                 # ID of most recent revision
-       var $mRestrictions;             # Array of groups allowed to edit this article
-       var $mCascadeRestriction;       # Cascade restrictions on this page to included templates and images?
-       var $mRestrictionsExpiry;       # When do the restrictions on this page expire?
-       var $mHasCascadingRestrictions; # Are cascading restrictions in effect on this page?
-       var $mCascadeRestrictionSources;# Where are the cascading restrictions coming from on this page?
-       var $mRestrictionsLoaded;       # Boolean for initialisation on demand
-       var $mPrefixedText;             # Text form including namespace/interwiki, initialised on demand
-       var $mDefaultNamespace;         # Namespace index when there is no namespace
-                                       # Zero except in {{transclusion}} tags
-       var $mWatched;                  # Is $wgUser watching this page? NULL if unfilled, accessed through userIsWatching()
-       var $mLength;              # The page length, 0 for special pages
-       var $mRedirect;            # Is the article at this title a redirect?
+       var $mTextform = '';              # Text form (spaces not underscores) of the main part
+       var $mUrlform = '';               # URL-encoded form of the main part
+       var $mDbkeyform = '';             # Main part with underscores
+       var $mUserCaseDBKey;              # DB key with the initial letter in the case specified by the user
+       var $mNamespace = NS_MAIN;        # Namespace index, i.e. one of the NS_xxxx constants
+       var $mInterwiki = '';             # Interwiki prefix (or null string)
+       var $mFragment;                       # Title fragment (i.e. the bit after the #)
+       var $mArticleID = -1;             # Article ID, fetched from the link cache on demand
+       var $mLatestID = false;           # ID of most recent revision
+       var $mRestrictions = array();     # Array of groups allowed to edit this article
+       var $mOldRestrictions = false;
+       var $mCascadeRestriction;             # Cascade restrictions on this page to included templates and images?
+       var $mRestrictionsExpiry;             # When do the restrictions on this page expire?
+       var $mHasCascadingRestrictions;   # Are cascading restrictions in effect on this page?
+       var $mCascadeRestrictionSources;  # Where are the cascading restrictions coming from on this page?
+       var $mRestrictionsLoaded = false; # Boolean for initialisation on demand
+       var $mPrefixedText;                   # Text form including namespace/interwiki, initialised on demand
+       # Don't change the following default, NS_MAIN is hardcoded in several
+       # places.  See bug 696.
+       var $mDefaultNamespace = NS_MAIN; # Namespace index when there is no namespace
+                                             # Zero except in {{transclusion}} tags
+       var $mWatched = null;                     # Is $wgUser watching this page? null if unfilled, accessed through userIsWatching()
+       var $mLength = -1;                # The page length, 0 for special pages
+       var $mRedirect = null;            # Is the article at this title a redirect?
        /**#@-*/
 
 
@@ -72,22 +76,7 @@ class Title {
         * Constructor
         * @private
         */
-       /* private */ function __construct() {
-               $this->mInterwiki = $this->mUrlform =
-               $this->mTextform = $this->mDbkeyform = '';
-               $this->mArticleID = -1;
-               $this->mNamespace = NS_MAIN;
-               $this->mRestrictionsLoaded = false;
-               $this->mRestrictions = array();
-               # Dont change the following, NS_MAIN is hardcoded in several place
-               # See bug #696
-               $this->mDefaultNamespace = NS_MAIN;
-               $this->mWatched = NULL;
-               $this->mLatestID = false;
-               $this->mOldRestrictions = false;
-               $this->mLength = -1;
-               $this->mRedirect = NULL;
-       }
+       /* private */ function __construct() {}
 
        /**
         * Create a new Title from a prefixed DB key
@@ -220,7 +209,7 @@ class Title {
                        'page_id IN (' . $dbr->makeList( $ids ) . ')', __METHOD__ );
 
                $titles = array();
-               while ( $row = $dbr->fetchObject( $res ) ) {
+               foreach( $res as $row ) {
                        $titles[] = Title::makeTitle( $row->page_namespace, $row->page_title );
                }
                return $titles;
@@ -250,12 +239,13 @@ class Title {
         *
         * @param int $ns the namespace of the article
         * @param string $title the unprefixed database key form
+        * @param string $fragment The link fragment (after the "#")
         * @return Title the new object
         */
-       public static function &makeTitle( $ns, $title ) {
+       public static function &makeTitle( $ns, $title, $fragment = '' ) {
                $t = new Title();
                $t->mInterwiki = '';
-               $t->mFragment = '';
+               $t->mFragment = $fragment;
                $t->mNamespace = $ns = intval( $ns );
                $t->mDbkeyform = str_replace( ' ', '_', $title );
                $t->mArticleID = ( $ns >= 0 ) ? -1 : 0;
@@ -271,11 +261,12 @@ class Title {
         *
         * @param int $ns the namespace of the article
         * @param string $title the database key form
+        * @param string $fragment The link fragment (after the "#")
         * @return Title the new object, or NULL on an error
         */
-       public static function makeTitleSafe( $ns, $title ) {
+       public static function makeTitleSafe( $ns, $title, $fragment = '' ) {
                $t = new Title();
-               $t->mDbkeyform = Title::makeName( $ns, $title );
+               $t->mDbkeyform = Title::makeName( $ns, $title, $fragment );
                if( $t->secureAndSplit() ) {
                        return $t;
                } else {
@@ -335,17 +326,14 @@ class Title {
         * @param int $id the page_id of the article
         * @return Title an object representing the article, or NULL
         *      if no such article was found
-        * @static
-        * @access public
         */
-       function nameOf( $id ) {
-               $fname = 'Title::nameOf';
+       public static function nameOf( $id ) {
                $dbr = wfGetDB( DB_SLAVE );
 
-               $s = $dbr->selectRow( 'page', array( 'page_namespace','page_title' ),  array( 'page_id' => $id ), $fname );
+               $s = $dbr->selectRow( 'page', array( 'page_namespace','page_title' ),  array( 'page_id' => $id ), __METHOD__ );
                if ( $s === false ) { return NULL; }
 
-               $n = Title::makeName( $s->page_namespace, $s->page_title );
+               $n = self::makeName( $s->page_namespace, $s->page_title );
                return $n;
        }
 
@@ -391,13 +379,18 @@ class Title {
         * Make a prefixed DB key from a DB key and a namespace index
         * @param int $ns numerical representation of the namespace
         * @param string $title the DB key form the title
+        * @param string $fragment The link fragment (after the "#")
         * @return string the prefixed form of the title
         */
-       public static function makeName( $ns, $title ) {
+       public static function makeName( $ns, $title, $fragment = '' ) {
                global $wgContLang;
 
-               $n = $wgContLang->getNsText( $ns );
-               return $n == '' ? $title : "$n:$title";
+               $namespace = $wgContLang->getNsText( $ns );
+               $name = $namespace == '' ? $title : "$namespace:$title";
+               if ( strval( $fragment ) != '' ) {
+                       $name .= '#' . $fragment;
+               }
+               return $name;
        }
 
        /**
@@ -752,14 +745,19 @@ class Title {
         * Get a real URL referring to this title, with interwiki link and
         * fragment
         *
-        * @param string $query an optional query string, not used
-        *      for interwiki links
+        * @param array $query an optional query string, not used for interwiki
+        *   links. Can be specified as an associative array as well, e.g.,
+        *   array( 'action' => 'edit' ) (keys and values will be URL-escaped).
         * @param string $variant language variant of url (for sr, zh..)
         * @return string the URL
         */
        public function getFullURL( $query = '', $variant = false ) {
                global $wgContLang, $wgServer, $wgRequest;
 
+               if( is_array( $query ) ) {
+                       $query = wfArrayToCGI( $query );
+               }
+
                if ( '' == $this->mInterwiki ) {
                        $url = $this->getLocalUrl( $query, $variant );
 
@@ -791,8 +789,10 @@ class Title {
        /**
         * Get a URL with no fragment or server name.  If this page is generated
         * with action=render, $wgServer is prepended.
-        * @param string $query an optional query string; if not specified,
-        *      $wgArticlePath will be used.
+        * @param mixed $query an optional query string; if not specified,
+        *       $wgArticlePath will be used.  Can be specified as an associative array
+        *   as well, e.g., array( 'action' => 'edit' ) (keys and values will be
+        *   URL-escaped).
         * @param string $variant language variant of url (for sr, zh..)
         * @return string the URL
         */
@@ -800,6 +800,10 @@ class Title {
                global $wgArticlePath, $wgScript, $wgServer, $wgRequest;
                global $wgVariantArticlePath, $wgContLang, $wgUser;
 
+               if( is_array( $query ) ) {
+                       $query = wfArrayToCGI( $query );
+               }
+
                // internal links should point to same variant as current page (only anonymous users)
                if($variant == false && $wgContLang->hasVariants() && !$wgUser->isLoggedIn()){
                        $pref = $wgContLang->getPreferredVariant(false);
@@ -863,6 +867,36 @@ class Title {
                return $url;
        }
 
+       /**
+        * Get a URL that's the simplest URL that will be valid to link, locally,
+        * to the current Title.  It includes the fragment, but does not include
+        * the server unless action=render is used (or the link is external).  If
+        * there's a fragment but the prefixed text is empty, we just return a link
+        * to the fragment.
+        *
+        * @param array $query An associative array of key => value pairs for the
+        *   query string.  Keys and values will be escaped.
+        * @param string $variant Language variant of URL (for sr, zh..).  Ignored
+        *   for external links.  Default is "false" (same variant as current page,
+        *   for anonymous users).
+        * @return string the URL
+        */
+       public function getLinkUrl( $query = array(), $variant = false ) {
+               if( !is_array( $query ) ) {
+                       throw new MWException( 'Title::getLinkUrl passed a non-array for '.
+                       '$query' );
+               }
+               if( $this->isExternal() ) {
+                       return $this->getFullURL( $query );
+               } elseif( $this->getPrefixedText() === ''
+               and $this->getFragment() !== '' ) {
+                       return $this->getFragmentForURL();
+               } else {
+                       return $this->getLocalURL( $query, $variant )
+                               . $this->getFragmentForURL();
+               }
+       }
+
        /**
         * Get an HTML-escaped version of the URL form, suitable for
         * using in a link, without a server name or fragment
@@ -1049,9 +1083,10 @@ class Title {
         * @param string $action action that permission needs to be checked for
         * @param User $user user to check
         * @param bool $doExpensiveQueries Set this to false to avoid doing unnecessary queries.
+        * @param array $ignoreErrors Set this to a list of message keys whose corresponding errors may be ignored.
         * @return array Array of arrays of the arguments to wfMsg to explain permissions problems.
         */
-       public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true ) {
+       public function getUserPermissionsErrors( $action, $user, $doExpensiveQueries = true, $ignoreErrors = array() ) {
                if( !StubObject::isRealObject( $user ) ) {
                        //Since StubObject is always used on globals, we can unstub $wgUser here and set $user = $wgUser
                        global $wgUser;
@@ -1068,7 +1103,7 @@ class Title {
                        $errors[] = array( 'confirmedittext' );
                }
 
-               if ( $user->isBlockedFrom( $this ) ) {
+               if ( $user->isBlockedFrom( $this ) && $action != 'createaccount' ) {
                        $block = $user->mBlock;
 
                        // This is from OutputPage::blockedPage
@@ -1116,6 +1151,16 @@ class Title {
                        $errors[] = array( ($block->mAuto ? 'autoblockedtext' : 'blockedtext'), $link, $reason, $ip, $name, 
                                $blockid, $blockExpiry, $intended, $blockTimestamp );
                }
+               
+               // Remove the errors being ignored.
+               
+               foreach( $errors as $index => $error ) {
+                       $error_key = is_array($error) ? $error[0] : $error;
+                       
+                       if (in_array( $error_key, $ignoreErrors )) {
+                               unset($errors[$index]);
+                       }
+               }
 
                return $errors;
        }
@@ -1262,29 +1307,16 @@ class Title {
                        $errors[] = $user->isAnon() ? array ( 'movenologintext' ) : array ('movenotallowed');
                } elseif ( !$user->isAllowed( $action ) ) {
                        $return = null;
-                       $groups = array();
-                       global $wgGroupPermissions;
-                       foreach( $wgGroupPermissions as $key => $value ) {
-                               if( isset( $value[$action] ) && $value[$action] == true ) {
-                                       $groupName = User::getGroupName( $key );
-                                       $groupPage = User::getGroupPage( $key );
-                                       if( $groupPage ) {
-                                               $groups[] = '[['.$groupPage->getPrefixedText().'|'.$groupName.']]';
-                                       } else {
-                                               $groups[] = $groupName;
-                                       }
-                               }
+                       $groups = array_map( array( 'User', 'makeGroupLinkWiki' ),
+                               User::getGroupsWithPermission( $action ) );
+                       if ( $groups ) {
+                               $return = array( 'badaccess-groups',
+                                       array(
+                                               implode( ', ', $groups ),
+                                               count( $groups ) ) );
                        }
-                       $n = count( $groups );
-                       $groups = implode( ', ', $groups );
-                       switch( $n ) {
-                               case 0:
-                               case 1:
-                               case 2:
-                                       $return = array( "badaccess-group$n", $groups );
-                                       break;
-                               default:
-                                       $return = array( 'badaccess-groups', $groups );
+                       else {
+                               $return = array( "badaccess-group0" );
                        }
                        $errors[] = $return;
                }
@@ -1316,7 +1348,7 @@ class Title {
        }
 
        public function updateTitleProtection( $create_perm, $reason, $expiry ) {
-               global $wgGroupPermissions,$wgUser,$wgContLang;
+               global $wgUser,$wgContLang;
 
                if ($create_perm == implode(',',$this->getRestrictions('create'))
                        && $expiry == $this->mRestrictionsExpiry) {
@@ -1657,7 +1689,7 @@ class Title {
                $now = wfTimestampNow();
                $purgeExpired = false;
 
-               while( $row = $dbr->fetchObject( $res ) ) {
+               foreach( $res as $row ) {
                        $expiry = Block::decodeExpiry( $row->pr_expiry );
                        if( $expiry > $now ) {
                                if ($get_pages) {
@@ -1746,7 +1778,7 @@ class Title {
                        $now = wfTimestampNow();
                        $purgeExpired = false;
 
-                       while ($row = $dbr->fetchObject( $res ) ) {
+                       foreach( $res as $row ) {
                                # Cycle through all the restrictions.
 
                                // Don't take care of restrictions types that aren't in $wgRestrictionTypes
@@ -1802,6 +1834,8 @@ class Title {
                                        } else { // Get rid of the old restrictions
                                                Title::purgeExpiredRestrictions();
                                        }
+                               } else {
+                                       $this->mRestrictionsExpiry = Block::decodeExpiry('');
                                }
                                $this->mRestrictionsLoaded = true;
                        }
@@ -2134,9 +2168,9 @@ class Title {
                }
 
                /**
-                * Pages with "/./" or "/../" appearing in the URLs will
-                * often be unreachable due to the way web browsers deal
-                * with 'relative' URLs. Forbid them explicitly.
+                * Pages with "/./" or "/../" appearing in the URLs will often be un-
+                * reachable due to the way web browsers deal with 'relative' URLs.
+                * Also, they conflict with subpage syntax.  Forbid them explicitly.
                 */
                if ( strpos( $dbkey, '.' ) !== false &&
                     ( $dbkey === '.' || $dbkey === '..' ||
@@ -2271,12 +2305,12 @@ class Title {
                                "{$prefix}_from=page_id",
                                "{$prefix}_namespace" => $this->getNamespace(),
                                "{$prefix}_title"     => $this->getDBkey() ),
-                       'Title::getLinksTo',
+                       __METHOD__,
                        $options );
 
                $retVal = array();
                if ( $db->numRows( $res ) ) {
-                       while ( $row = $db->fetchObject( $res ) ) {
+                       foreach( $res as $row ) {
                                if ( $titleObj = Title::makeTitle( $row->page_namespace, $row->page_title ) ) {
                                        $linkCache->addGoodLinkObj( $row->page_id, $titleObj, $row->page_len, $row->page_is_redirect );
                                        $retVal[] = $titleObj;
@@ -2336,7 +2370,7 @@ class Title {
 
                $retVal = array();
                if ( $db->numRows( $res ) ) {
-                       while ( $row = $db->fetchObject( $res ) ) {
+                       foreach( $res as $row ) {
                                $retVal[] = Title::makeTitle( $row->pl_namespace, $row->pl_title );
                        }
                }
@@ -2394,9 +2428,10 @@ class Title {
         * @param Title &$nt the new title
         * @param bool $auth indicates whether $wgUser's permissions
         *      should be checked
+        * @param string $reason is the log summary of the move, used for spam checking
         * @return mixed True on success, getUserPermissionsErrors()-like array on failure
         */
-       public function isValidMoveOperation( &$nt, $auth = true ) {
+       public function isValidMoveOperation( &$nt, $auth = true, $reason = '' ) {
                $errors = array();      
                if( !$nt ) {
                        // Normally we'd add this to $errors, but we'll get
@@ -2429,6 +2464,9 @@ class Title {
                                if( $nt->getNamespace() != NS_IMAGE ) {
                                        $errors[] = array('imagenocrossnamespace');
                                }
+                               if( $nt->getText() != wfStripIllegalFilenameChars( $nt->getText() ) ) {
+                                       $errors[] = array('imageinvalidfilename');
+                               }
                                if( !File::checkExtensionCompatibility( $file, $nt->getDbKey() ) ) {
                                        $errors[] = array('imagetypemismatch');
                                }
@@ -2446,7 +2484,7 @@ class Title {
 
                global $wgUser;
                $err = null;
-               if( !wfRunHooks( 'AbortMove', array( $this, $nt, $wgUser, &$err ) ) ) {
+               if( !wfRunHooks( 'AbortMove', array( $this, $nt, $wgUser, &$err, $reason ) ) ) {
                        $errors[] = array('hookaborted', $err);
                }
 
@@ -2481,7 +2519,7 @@ class Title {
         * @return mixed true on success, getUserPermissionsErrors()-like array on failure
         */
        public function moveTo( &$nt, $auth = true, $reason = '', $createRedirect = true ) {
-               $err = $this->isValidMoveOperation( $nt, $auth );
+               $err = $this->isValidMoveOperation( $nt, $auth, $reason );
                if( is_array( $err ) ) {
                        return $err;
                }
@@ -2592,6 +2630,7 @@ class Title {
                $now = wfTimestampNow();
                $newid = $nt->getArticleID();
                $oldid = $this->getArticleID();
+               $latest = $this->getLatestRevID();
 
                $dbw = wfGetDB( DB_MASTER );
                $dbw->begin();
@@ -2620,7 +2659,7 @@ class Title {
                $nullRevId = $nullRevision->insertOn( $dbw );
                
                $article = new Article( $this );
-               wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, false) );
+               wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, $latest) );
 
                # Change the name of the target page:
                $dbw->update( 'page',
@@ -2706,6 +2745,7 @@ class Title {
 
                $newid = $nt->getArticleID();
                $oldid = $this->getArticleID();
+               $latest = $this->getLatestRevId();
                
                $dbw = wfGetDB( DB_MASTER );
                $dbw->begin();
@@ -2716,7 +2756,7 @@ class Title {
                $nullRevId = $nullRevision->insertOn( $dbw );
                
                $article = new Article( $this );
-               wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, false) );
+               wfRunHooks( 'NewRevisionFromEditComplete', array($article, $nullRevision, $latest) );
 
                # Rename page entry
                $dbw->update( 'page',
@@ -2877,13 +2917,13 @@ class Title {
                         ." AND cl_from <> '0'"
                         ." ORDER BY cl_sortkey";
 
-               $res = $dbr->query ( $sql ) ;
+               $res = $dbr->query( $sql );
 
-               if($dbr->numRows($res) > 0) {
-                       while ( $x = $dbr->fetchObject ( $res ) )
-                               //$data[] = Title::newFromText($wgContLang->getNSText ( NS_CATEGORY ).':'.$x->cl_to);
-                               $data[$wgContLang->getNSText ( NS_CATEGORY ).':'.$x->cl_to] = $this->getFullText();
-                       $dbr->freeResult ( $res ) ;
+               if( $dbr->numRows( $res ) > 0 ) {
+                       foreach( $res as $row )
+                               //$data[] = Title::newFromText($wgContLang->getNSText ( NS_CATEGORY ).':'.$row->cl_to);
+                               $data[$wgContLang->getNSText( NS_CATEGORY ).':'.$row->cl_to] = $this->getFullText();
+                       $dbr->freeResult( $res );
                } else {
                        $data = array();
                }
@@ -2900,7 +2940,7 @@ class Title {
                $parents = $this->getParentCategories();
 
                if( $parents ) {
-                       foreach($parents as $parent => $current) {
+                       foreach( $parents as $parent => $current ) {
                                if ( array_key_exists( $parent, $children ) ) {
                                        # Circular reference
                                        $stack[$parent] = array();
@@ -2931,16 +2971,16 @@ class Title {
        /**
         * Get the revision ID of the previous revision
         *
-        * @param integer $revision  Revision ID. Get the revision that was before this one.
+        * @param integer $revId Revision ID. Get the revision that was before this one.
         * @param integer $flags, GAID_FOR_UPDATE
         * @return integer $oldrevision|false
         */
-       public function getPreviousRevisionID( $revision, $flags=0 ) {
+       public function getPreviousRevisionID( $revId, $flags=0 ) {
                $db = ($flags & GAID_FOR_UPDATE) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
                return $db->selectField( 'revision', 'rev_id',
                        array(
                                'rev_page' => $this->getArticleId($flags),
-                               'rev_id < ' . intval( $revision )
+                               'rev_id < ' . intval( $revId )
                        ),
                        __METHOD__,
                        array( 'ORDER BY' => 'rev_id DESC' )
@@ -2950,16 +2990,16 @@ class Title {
        /**
         * Get the revision ID of the next revision
         *
-        * @param integer $revision  Revision ID. Get the revision that was after this one.
+        * @param integer $revId Revision ID. Get the revision that was after this one.
         * @param integer $flags, GAID_FOR_UPDATE
         * @return integer $oldrevision|false
         */
-       public function getNextRevisionID( $revision, $flags=0 ) {
+       public function getNextRevisionID( $revId, $flags=0 ) {
                $db = ($flags & GAID_FOR_UPDATE) ? wfGetDB( DB_MASTER ) : wfGetDB( DB_SLAVE );
                return $db->selectField( 'revision', 'rev_id',
                        array(
                                'rev_page' => $this->getArticleId($flags),
-                               'rev_id > ' . intval( $revision )
+                               'rev_id > ' . intval( $revId )
                        ),
                        __METHOD__,
                        array( 'ORDER BY' => 'rev_id' )
@@ -2990,7 +3030,7 @@ class Title {
         * @param Title $title
         * @return bool
         */
-       public function equals( $title ) {
+       public function equals( Title $title ) {
                // Note: === is necessary for proper matching of number-like titles.
                return $this->getInterwiki() === $title->getInterwiki()
                        && $this->getNamespace() == $title->getNamespace()
@@ -3195,7 +3235,7 @@ class Title {
                );
                if ( !is_null($ns) ) $where['page_namespace'] = $ns;
                
-               $result = $dbr->select(
+               $res = $dbr->select(
                        array( 'redirect', 'page' ),
                        array( 'page_namespace', 'page_title' ),
                        $where,
@@ -3203,7 +3243,7 @@ class Title {
                );
 
 
-               while( $row = $dbr->fetchObject( $result ) ) {
+               foreach( $res as $row ) {
                        $redirs[] = self::newFromRow( $row );
                }
                return $redirs;