Minor whitespace change.
[lhc/web/wiklou.git] / includes / User.php
index 9c2a078..63b1a6a 100644 (file)
@@ -41,56 +41,13 @@ class PasswordError extends MWException {
  * of the database.
  */
 class User {
-
        /**
-        * \type{\arrayof{\string}} A list of default user toggles, i.e., boolean user
-        * preferences that are displayed by Special:Preferences as checkboxes.
-        * This list can be extended via the UserToggles hook or by
-        * $wgContLang::getExtraUserToggles().
-        * @showinitializer
+        * Global constants made accessible as class constants so that autoloader
+        * magic can be used.
         */
-       public static $mToggles = array(
-               'highlightbroken',
-               'justify',
-               'hideminor',
-               'extendwatchlist',
-               'usenewrc',
-               'numberheadings',
-               'showtoolbar',
-               'editondblclick',
-               'editsection',
-               'editsectiononrightclick',
-               'showtoc',
-               'rememberpassword',
-               'watchcreations',
-               'watchdefault',
-               'watchmoves',
-               'watchdeletion',
-               'previewontop',
-               'previewonfirst',
-               'nocache',
-               'enotifwatchlistpages',
-               'enotifusertalkpages',
-               'enotifminoredits',
-               'enotifrevealaddr',
-               'shownumberswatching',
-               'fancysig',
-               'externaleditor',
-               'externaldiff',
-               'showjumplinks',
-               'uselivepreview',
-               'forceeditsummary',
-               'watchlisthideminor',
-               'watchlisthidebots',
-               'watchlisthideown',
-               'watchlisthideanons',
-               'watchlisthideliu',
-               'ccmeonemails',
-               'diffonly',
-               'showhiddencats',
-               'noconvertlink',
-               'norollbackdiff',
-       );
+       const USER_TOKEN_LENGTH = USER_TOKEN_LENGTH;
+       const MW_USER_VERSION = MW_USER_VERSION;
+       const EDIT_TOKEN_SUFFIX = EDIT_TOKEN_SUFFIX;
 
        /**
         * \type{\arrayof{\string}} List of member variables which are saved to the
@@ -228,7 +185,7 @@ class User {
         * @see newFromSession()
         * @see newFromRow()
         */
-       function User() {
+       function __construct() {
                $this->clearInstanceCache( 'defaults' );
        }
 
@@ -291,7 +248,7 @@ class User {
                }
 
                if ( !$data ) {
-                       wfDebug( "Cache miss for user {$this->mId}\n" );
+                       wfDebug( "User: cache miss for user {$this->mId}\n" );
                        # Load from DB
                        if ( !$this->loadFromDatabase() ) {
                                # Can't load from ID, user is anonymous
@@ -299,7 +256,7 @@ class User {
                        }
                        $this->saveToCache();
                } else {
-                       wfDebug( "Got user {$this->mId} from cache\n" );
+                       wfDebug( "User: got user {$this->mId} from cache\n" );
                        # Restore from cache
                        foreach ( self::$mCacheVars as $name ) {
                                $this->$name = $data[$name];
@@ -644,18 +601,22 @@ class User {
         * @return mixed: true on success, string of error message on failure
         */
        function getPasswordValidity( $password ) {
-               global $wgMinimalPasswordLength, $wgContLang;
+               global $wgMinimalPasswordLength, $wgWeakPasswords, $wgContLang;
 
                $result = false; //init $result to false for the internal checks
 
                if( !wfRunHooks( 'isValidPassword', array( $password, &$result, $this ) ) )
                        return $result;
 
+               $lcPassword = $wgContLang->lc( $password );
+
                if ( $result === false ) {
                        if( strlen( $password ) < $wgMinimalPasswordLength ) {
                                return 'passwordtooshort';
-                       } elseif ( $wgContLang->lc( $password ) == $wgContLang->lc( $this->mName ) ) {
+                       } elseif ( $lcPassword == $wgContLang->lc( $this->mName ) ) {
                                return 'password-name-match';
+                       } elseif ( in_array( $lcPassword, $wgWeakPasswords ) ) {                        
+                               return 'password-too-weak';
                        } else {
                                //it seems weird returning true here, but this is because of the
                                //initialization of $result to false above. If the hook is never run or it
@@ -687,8 +648,19 @@ class User {
                if( !wfRunHooks( 'isValidEmailAddr', array( $addr, &$result ) ) ) {
                        return $result;
                }
+               $rfc5322_atext   = "a-z0-9!#$%&'*+-\/=?^_`{|}—~" ;
+               $rfc1034_ldh_str = "a-z0-9-" ;
+
+               $HTML5_email_regexp = "/
+               ^                      # start of string
+               [$rfc5322_atext\\.]+    # user part which is liberal :p
+               @                      # 'apostrophe'
+               [$rfc1034_ldh_str]+       # First domain part
+               (\\.[$rfc1034_ldh_str]+)+  # Following part prefixed with a dot
+               $                      # End of string
+               /ix" ; // case Insensitive, eXtended 
 
-               return strpos( $addr, '@' ) !== false;
+               return (bool) preg_match( $HTML5_email_regexp, $addr );
        }
 
        /**
@@ -721,7 +693,6 @@ class User {
                }
 
                # Reject various classes of invalid names
-               $name = $t->getText();
                global $wgAuth;
                $name = $wgAuth->getCanonicalName( $t->getText() );
 
@@ -816,7 +787,7 @@ class User {
        function loadDefaults( $name = false ) {
                wfProfileIn( __METHOD__ );
 
-               global $wgCookiePrefix;
+               global $wgRequest;
 
                $this->mId = 0;
                $this->mName = $name;
@@ -827,8 +798,8 @@ class User {
                $this->mOptionOverrides = null;
                $this->mOptionsLoaded = false;
 
-               if ( isset( $_COOKIE[$wgCookiePrefix.'LoggedOut'] ) ) {
-                       $this->mTouched = wfTimestamp( TS_MW, $_COOKIE[$wgCookiePrefix.'LoggedOut'] );
+               if( $wgRequest->getCookie( 'LoggedOut' ) !== null ) {
+                       $this->mTouched = wfTimestamp( TS_MW, $wgRequest->getCookie( 'LoggedOut' ) );
                } else {
                        $this->mTouched = '0'; # Allow any pages to be cached
                }
@@ -859,7 +830,7 @@ class User {
         * @return \bool True if the user is logged in, false otherwise.
         */
        private function loadFromSession() {
-               global $wgCookiePrefix, $wgExternalAuthType, $wgAutocreatePolicy;
+               global $wgRequest, $wgExternalAuthType, $wgAutocreatePolicy;
 
                $result = null;
                wfRunHooks( 'UserLoadFromSession', array( $this, &$result ) );
@@ -875,8 +846,8 @@ class User {
                        }
                }
 
-               if ( isset( $_COOKIE["{$wgCookiePrefix}UserID"] ) ) {
-                       $sId = intval( $_COOKIE["{$wgCookiePrefix}UserID"] );
+               if ( $wgRequest->getCookie( 'UserID' ) !== null ) {
+                       $sId = intval( $wgRequest->getCookie( 'UserID' ) );
                        if( isset( $_SESSION['wsUserID'] ) && $sId != $_SESSION['wsUserID'] ) {
                                $this->loadDefaults(); // Possible collision!
                                wfDebugLog( 'loginSessions', "Session user ID ({$_SESSION['wsUserID']}) and
@@ -898,15 +869,14 @@ class User {
 
                if ( isset( $_SESSION['wsUserName'] ) ) {
                        $sName = $_SESSION['wsUserName'];
-               } else if ( isset( $_COOKIE["{$wgCookiePrefix}UserName"] ) ) {
-                       $sName = $_COOKIE["{$wgCookiePrefix}UserName"];
+               } else if ( $wgRequest->getCookie('UserName') !== null ) {
+                       $sName = $wgRequest->getCookie('UserName');
                        $_SESSION['wsUserName'] = $sName;
                } else {
                        $this->loadDefaults();
                        return false;
                }
 
-               $passwordCorrect = FALSE;
                $this->mId = $sId;
                if ( !$this->loadFromId() ) {
                        # Not a valid ID, loadFromId has switched the object to anon for us
@@ -923,8 +893,8 @@ class User {
                if ( isset( $_SESSION['wsToken'] ) ) {
                        $passwordCorrect = $_SESSION['wsToken'] == $this->mToken;
                        $from = 'session';
-               } else if ( isset( $_COOKIE["{$wgCookiePrefix}Token"] ) ) {
-                       $passwordCorrect = $this->mToken == $_COOKIE["{$wgCookiePrefix}Token"];
+               } else if ( $wgRequest->getCookie( 'Token' ) !== null ) {
+                       $passwordCorrect = $this->mToken == $wgRequest->getCookie( 'Token' );
                        $from = 'cookie';
                } else {
                        # No session or persistent login cookie
@@ -934,11 +904,11 @@ class User {
 
                if ( ( $sName == $this->mName ) && $passwordCorrect ) {
                        $_SESSION['wsToken'] = $this->mToken;
-                       wfDebug( "Logged in from $from\n" );
+                       wfDebug( "User: logged in from $from\n" );
                        return true;
                } else {
                        # Invalid credentials
-                       wfDebug( "Can't log in from $from, invalid credentials\n" );
+                       wfDebug( "User: can't log in from $from, invalid credentials\n" );
                        $this->loadDefaults();
                        return false;
                }
@@ -1019,7 +989,7 @@ class User {
                                array( 'ug_user' => $this->mId ),
                                __METHOD__ );
                        $this->mGroups = array();
-                       while( $row = $dbr->fetchObject( $res ) ) {
+                       foreach ( $res as $row ) {
                                $this->mGroups[] = $row->ug_group;
                        }
                }
@@ -1064,7 +1034,7 @@ class User {
                /**
                 * default language setting
                 */
-               $variant = $wgContLang->getPreferredVariant( false );
+               $variant = $wgContLang->getDefaultVariant();
                $defOpt['variant'] = $variant;
                $defOpt['language'] = $variant;
                foreach( SearchEngine::searchableNamespaces() as $nsnum => $nsname ) {
@@ -1090,22 +1060,6 @@ class User {
                }
        }
 
-       /**
-        * Get a list of user toggle names
-        * @return \type{\arrayof{\string}} Array of user toggle names
-        */
-       static function getToggles() {
-               global $wgContLang, $wgUseRCPatrol;
-               $extraToggles = array();
-               wfRunHooks( 'UserToggles', array( &$extraToggles ) );
-               if( $wgUseRCPatrol ) {
-                       $extraToggles[] = 'hidepatrolled';
-                       $extraToggles[] = 'newpageshidepatrolled';
-                       $extraToggles[] = 'watchlisthidepatrolled';
-               }
-               return array_merge( self::$mToggles, $extraToggles, $wgContLang->getExtraUserToggles() );
-       }
-
 
        /**
         * Get blocking information
@@ -1232,7 +1186,6 @@ class User {
                wfProfileIn( __METHOD__ );
 
                $found = false;
-               $host = '';
                // FIXME: IPv6 ???  (http://bugs.php.net/bug.php?id=33170)
                if( IP::isIPv4( $ip ) ) {
                        # Reverse IP, bug 21255
@@ -1271,10 +1224,34 @@ class User {
                        // Deprecated, but kept for backwards-compatibility config
                        return false;
                }
-               if( in_array( wfGetIP(), $wgRateLimitsExcludedIPs ) ) {
+
+               wfDebug( "Checking the list of IP addresses excluded from rate limit..\n" );
+
+               // Read list of IP addresses from MediaWiki namespace
+               $message = wfMsgForContentNoTrans( 'ratelimit-excluded-ips' );
+               $lines = explode( "\n", $message );
+               foreach( $lines as $line ) {
+                       // Remove comment lines
+                       $comment = substr( trim( $line ), 0, 1 );
+                       if ( $comment == '#' || $comment == '' ) {
+                               continue;
+                       }
+                       // Remove additional comments after an IP address
+                       $comment = strpos( $line, '#' );
+                       if ( $comment > 0 ) {
+                               $line = trim( substr( $line, 0, $comment-1 ) );
+                               if ( IP::isValid( $line ) ) {
+                                       $wgRateLimitsExcludedIPs[] = IP::sanitizeIP( $line );
+                               }
+                       }
+               }
+
+               $ip = IP::sanitizeIP( wfGetIP() );
+               if( in_array( $ip, $wgRateLimitsExcludedIPs ) ) {
                        // No other good way currently to disable rate limits
                        // for specific IPs. :P
                        // But this is a crappy hack and should die.
+                       wfDebug( "IP $ip matches the list of rate limit excluded IPs\n" );
                        return false;
                }
                return !$this->isAllowed('noratelimit');
@@ -2041,7 +2018,7 @@ class User {
 
                if ( $oname == 'skin' ) {
                        # Clear cached skin, so the new one displays immediately in Special:Preferences
-                       unset( $this->mSkin );
+                       $this->mSkin = null;
                }
 
                // Explicitly NULL values should refer to defaults
@@ -2078,6 +2055,20 @@ class User {
                return $this->mDatePreference;
        }
 
+       /**
+        * Get the user preferred stub threshold
+        */
+       function getStubThreshold() {
+               global $wgMaxArticleSize; # Maximum article size, in Kb
+               $threshold = intval( $this->getOption( 'stubthreshold' ) );
+               if ( $threshold > $wgMaxArticleSize * 1024 ) {
+                       # If they have set an impossible value, disable the preference 
+                       # so we can use the parser cache again.
+                       $threshold = 0;
+               }
+               return $threshold;
+       }
+
        /**
         * Get the permissions this user has.
         * @return \type{\arrayof{\string}} Array of permission names
@@ -2261,33 +2252,46 @@ class User {
         * @return Skin The current skin
         * @todo FIXME : need to check the old failback system [AV]
         */
-       function &getSkin( $t = null ) {
-               if ( !isset( $this->mSkin ) ) {
-                       wfProfileIn( __METHOD__ );
-
-                       global $wgHiddenPrefs;
-                       if( !in_array( 'skin', $wgHiddenPrefs ) ) {
-                               # get the user skin
-                               global $wgRequest;
-                               $userSkin = $this->getOption( 'skin' );
-                               $userSkin = $wgRequest->getVal( 'useskin', $userSkin );
-                       } else {
-                               # if we're not allowing users to override, then use the default
-                               global $wgDefaultSkin;
-                               $userSkin = $wgDefaultSkin;
+       function getSkin( $t = null ) {
+               if ( $t ) {
+                       $skin = $this->createSkinObject();
+                       $skin->setTitle( $t );
+                       return $skin;
+               } else {
+                       if ( !$this->mSkin ) {
+                               $this->mSkin = $this->createSkinObject();
                        }
 
-                       $this->mSkin = Skin::newFromKey( $userSkin );
-                       wfProfileOut( __METHOD__ );
-               }
-               if( $t || !$this->mSkin->getTitle() ) {
-                       if ( !$t ) {
+                       if ( !$this->mSkin->getTitle() ) {
                                global $wgOut;
                                $t = $wgOut->getTitle();
+                               $this->mSkin->setTitle($t);
                        }
-                       $this->mSkin->setTitle( $t );
+
+                       return $this->mSkin;
                }
-               return $this->mSkin;
+       }
+       
+       // Creates a Skin object, for getSkin()
+       private function createSkinObject() {
+               wfProfileIn( __METHOD__ );
+
+               global $wgHiddenPrefs;
+               if( !in_array( 'skin', $wgHiddenPrefs ) ) {
+                       global $wgRequest;
+                       # get the user skin
+                       $userSkin = $this->getOption( 'skin' );
+                       $userSkin = $wgRequest->getVal( 'useskin', $userSkin );
+               } else {
+                       # if we're not allowing users to override, then use the default
+                       global $wgDefaultSkin;
+                       $userSkin = $wgDefaultSkin;
+               }
+
+               $skin = Skin::newFromKey( $userSkin );
+               wfProfileOut( __METHOD__ );
+               
+               return $skin;
        }
 
        /**
@@ -2419,7 +2423,9 @@ class User {
                $this->mOptionsLoaded = true;
                $this->mOptionOverrides = array();
 
-               $this->mOptions = array();
+               // If an option is not set in $str, use the default value
+               $this->mOptions = self::getDefaultOptions();
+               
                $a = explode( "\n", $str );
                foreach ( $a as $s ) {
                        $m = array();
@@ -2677,6 +2683,7 @@ class User {
         * which will give them a chance to modify this key based on their own
         * settings.
         *
+        * @deprecated use the ParserOptions object to get the relevant options
         * @return \string Page rendering hash
         */
        function getPageRenderingHash() {
@@ -2684,13 +2691,15 @@ class User {
                if( $this->mHash ){
                        return $this->mHash;
                }
+               wfDeprecated( __METHOD__ );
 
                // stubthreshold is only included below for completeness,
-               // it will always be 0 when this function is called by parsercache.
+               // since it disables the parser cache, its value will always 
+               // be 0 when this function is called by parsercache.
 
                $confstr =        $this->getOption( 'math' );
-               $confstr .= '!' . $this->getOption( 'stubthreshold' );
-               if ( $wgUseDynamicDates ) {
+               $confstr .= '!' . $this->getStubThreshold();
+               if ( $wgUseDynamicDates ) { # This is wrong (bug 24714)
                        $confstr .= '!' . $this->getDatePreference();
                }
                $confstr .= '!' . ( $this->getOption( 'numberheadings' ) ? '1' : '' );
@@ -2700,6 +2709,9 @@ class User {
                $extra = $wgContLang->getExtraHashOptions();
                $confstr .= $extra;
 
+               // Since the skin could be overloading link(), it should be
+               // included here but in practice, none of our skins do that.
+
                $confstr .= $wgRenderHashAppend;
 
                // Give a chance for extensions to modify the hash, if they have
@@ -2765,9 +2777,9 @@ class User {
        function getMaxID() {
                static $res; // cache
 
-               if ( isset( $res ) )
+               if ( isset( $res ) ) {
                        return $res;
-               else {
+               else {
                        $dbr = wfGetDB( DB_SLAVE );
                        return $res = $dbr->selectField( 'user', 'max(user_id)', false, __METHOD__ );
                }
@@ -2945,12 +2957,13 @@ class User {
         */
        function sendMail( $subject, $body, $from = null, $replyto = null ) {
                if( is_null( $from ) ) {
-                       global $wgPasswordSender;
-                       $from = $wgPasswordSender;
+                       global $wgPasswordSender, $wgPasswordSenderName;
+                       $sender = new MailAddress( $wgPasswordSender, $wgPasswordSenderName );
+               } else {
+                       $sender = new MailAddress( $from );
                }
 
                $to = new MailAddress( $this );
-               $sender = new MailAddress( $from );
                return UserMailer::send( $to, $sender, $subject, $body, $replyto );
        }
 
@@ -3200,8 +3213,6 @@ class User {
         * @return \string Localized descriptive group name
         */
        static function getGroupName( $group ) {
-               global $wgMessageCache;
-               $wgMessageCache->loadAllMessages();
                $key = "group-$group";
                $name = wfMsg( $key );
                return $name == '' || wfEmptyMsg( $key, $name )
@@ -3216,8 +3227,6 @@ class User {
         * @return \string Localized name for group member
         */
        static function getGroupMember( $group ) {
-               global $wgMessageCache;
-               $wgMessageCache->loadAllMessages();
                $key = "group-$group-member";
                $name = wfMsg( $key );
                return $name == '' || wfEmptyMsg( $key, $name )
@@ -3274,8 +3283,6 @@ class User {
         * @return \types{\type{Title},\bool} Title of the page if it exists, false otherwise
         */
        static function getGroupPage( $group ) {
-               global $wgMessageCache;
-               $wgMessageCache->loadAllMessages();
                $page = wfMsgForContent( 'grouppage-' . $group );
                if( !wfEmptyMsg( 'grouppage-' . $group, $page ) ) {
                        $title = Title::newFromText( $page );
@@ -3488,8 +3495,6 @@ class User {
         * @return \string Localized description of the right
         */
        static function getRightDescription( $right ) {
-               global $wgMessageCache;
-               $wgMessageCache->loadAllMessages();
                $key = "right-$right";
                $name = wfMsg( $key );
                return $name == '' || wfEmptyMsg( $key, $name )
@@ -3627,12 +3632,12 @@ class User {
 
                // Maybe load from the object
                if ( !is_null( $this->mOptionOverrides ) ) {
-                       wfDebug( "Loading options for user " . $this->getId() . " from override cache.\n" );
+                       wfDebug( "User: loading options for user " . $this->getId() . " from override cache.\n" );
                        foreach( $this->mOptionOverrides as $key => $value ) {
                                $this->mOptions[$key] = $value;
                        }
                } else {
-                       wfDebug( "Loading options for user " . $this->getId() . " from database.\n" );
+                       wfDebug( "User: loading options for user " . $this->getId() . " from database.\n" );
                        // Load from database
                        $dbr = wfGetDB( DB_SLAVE );
 
@@ -3643,7 +3648,7 @@ class User {
                                __METHOD__
                        );
 
-                       while( $row = $dbr->fetchObject( $res ) ) {
+                       foreach ( $res as $row ) {
                                $this->mOptionOverrides[$row->up_property] = $row->up_value;
                                $this->mOptions[$row->up_property] = $row->up_value;
                        }