X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FUser.php;h=8e3c776a2fbb9323ff17fa4baa430e75f56a9bd4;hb=c07e337da68a87e7e877c65194778f4b098bf7c2;hp=2da396840cc4a8b58aba957720dff3a7bf02e5e6;hpb=6ca0d3f32d0fb0fb9ce7e01e006509dc3b950769;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/User.php b/includes/User.php index 2da396840c..8e3c776a2f 100644 --- a/includes/User.php +++ b/includes/User.php @@ -11,19 +11,25 @@ define( 'USER_TOKEN_LENGTH', 32 ); define( 'MW_USER_VERSION', 5 ); # Some punctuation to prevent editing from broken text-mangling proxies. -# FIXME: this is embedded unescaped into HTML attributes in various -# places, so we can't safely include ' or " even though we really should. -define( 'EDIT_TOKEN_SUFFIX', '\\' ); +define( 'EDIT_TOKEN_SUFFIX', '+\\' ); /** * Thrown by User::setPassword() on error + * @addtogroup Exception */ class PasswordError extends MWException { // NOP } /** - * + * The User object encapsulates all of the user-specific settings (user_id, + * name, rights, password, email address, options, last login time). Client + * classes use the getXXX() functions to access these fields. These functions + * do all the work of determining whether the user is logged in, + * whether the requested option can be satisfied from cookies or + * whether a database query is needed. Most of the settings needed + * for rendering normal pages are set in the cookie to minimize use + * of the database. */ class User { @@ -200,13 +206,7 @@ class User { return false; } - # Save to cache - $data = array(); - foreach ( self::$mCacheVars as $name ) { - $data[$name] = $this->$name; - } - $data['mVersion'] = MW_USER_VERSION; - $wgMemc->set( $key, $data ); + $this->saveToCache(); } else { wfDebug( "Got user {$this->mId} from cache\n" ); # Restore from cache @@ -217,6 +217,25 @@ class User { return true; } + /** + * Save user data to the shared cache + */ + function saveToCache() { + $this->load(); + if ( $this->isAnon() ) { + // Anonymous users are uncached + return; + } + $data = array(); + foreach ( self::$mCacheVars as $name ) { + $data[$name] = $this->$name; + } + $data['mVersion'] = MW_USER_VERSION; + $key = wfMemcKey( 'user', 'id', $this->mId ); + global $wgMemc; + $wgMemc->set( $key, $data ); + } + /** * Static factory method for creation from username. * @@ -305,14 +324,14 @@ class User { } /** - * Get real username given an id. - * @param integer $id Database user id - * @return string Realname of a user - * @static + * Get the real name of a user given their identifier + * + * @param int $id Database user id + * @return string Real name of a user */ static function whoIsReal( $id ) { $dbr = wfGetDB( DB_SLAVE ); - return $dbr->selectField( 'user', 'user_real_name', array( 'user_id' => $id ), 'User::whoIsReal' ); + return $dbr->selectField( 'user', 'user_real_name', array( 'user_id' => $id ), __METHOD__ ); } /** @@ -350,14 +369,12 @@ class User { * addresses like this, if we allowed accounts like this to be created * new users could get the old edits of these anonymous users. * - * @bug 3631 - * * @static * @param string $name Nickname of a user * @return bool */ static function isIP( $name ) { - return preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/',$name); + return preg_match('/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/',$name) || User::isIPv6($name); /*return preg_match("/^ (?:[01]?\d{1,2}|2(:?[0-4]\d|5[0-5]))\. (?:[01]?\d{1,2}|2(:?[0-4]\d|5[0-5]))\. @@ -366,6 +383,27 @@ class User { $/x", $name);*/ } + /** + * Check if $name is an IPv6 IP. + */ + static function isIPv6($name) { + /* + * if it has any non-valid characters, it can't be a valid IPv6 + * address. + */ + if (preg_match("/[^:a-fA-F0-9]/", $name)) + return false; + + $parts = explode(":", $name); + if (count($parts) < 3) + return false; + foreach ($parts as $part) { + if (!preg_match("/^[0-9a-fA-F]{0,4}$/", $part)) + return false; + } + return true; + } + /** * Is the input a valid username? * @@ -427,7 +465,7 @@ class User { static function isUsableName( $name ) { global $wgReservedUsernames; return - // Must be a usable username, obviously ;) + // Must be a valid username, obviously ;) self::isValidUserName( $name ) && // Certain names may be reserved for batch processes. @@ -456,43 +494,44 @@ class User { } /** - * Is the input a valid password? + * Is the input a valid password for this user? * - * @param string $password + * @param string $password Desired password * @return bool - * @static */ - static function isValidPassword( $password ) { - global $wgMinimalPasswordLength; + function isValidPassword( $password ) { + global $wgMinimalPasswordLength, $wgContLang; $result = null; - if( !wfRunHooks( 'isValidPassword', array( $password, &$result ) ) ) return $result; - if ($result === false) return false; - if (strlen( $password ) >= $wgMinimalPasswordLength) { - return true; - } - else { + if( !wfRunHooks( 'isValidPassword', array( $password, &$result, $this ) ) ) + return $result; + if( $result === false ) return false; - } + + // Password needs to be long enough, and can't be the same as the username + return strlen( $password ) >= $wgMinimalPasswordLength + && $wgContLang->lc( $password ) !== $wgContLang->lc( $this->mName ); } /** - * Does the string match roughly an email address ? + * Does a string look like an email address? * * There used to be a regular expression here, it got removed because it * rejected valid addresses. Actually just check if there is '@' somewhere * in the given address. * - * @todo Check for RFC 2822 compilance - * @bug 959 + * @todo Check for RFC 2822 compilance (bug 959) * * @param string $addr email address - * @static * @return bool */ - static function isValidEmailAddr ( $addr ) { - return ( trim( $addr ) != '' ) && - (false !== strpos( $addr, '@' ) ); + public static function isValidEmailAddr( $addr ) { + $result = null; + if( !wfRunHooks( 'isValidEmailAddr', array( $addr, &$result ) ) ) { + return $result; + } + + return strpos( $addr, '@' ) !== false; } /** @@ -510,6 +549,12 @@ class User { global $wgContLang; $name = $wgContLang->ucfirst( $name ); + # Reject names containing '#'; these will be cleaned up + # with title normalisation, but then it's too late to + # check elsewhere + if( strpos( $name, '#' ) !== false ) + return false; + # Clean up name according to title rules $t = Title::newFromText( $name ); if( is_null( $t ) ) { @@ -565,7 +610,7 @@ class User { ); if( $field === null ) { // it has not been initialized. do so. - $dbw = wfGetDb( DB_MASTER ); + $dbw = wfGetDB( DB_MASTER ); $count = $dbr->selectField( 'revision', 'count(*)', array( 'rev_user' => $uid ), @@ -586,7 +631,7 @@ class User { /** * Return a random password. Sourced from mt_rand, so it's not particularly secure. - * @todo: hash random numbers to improve security, like generateToken() + * @todo hash random numbers to improve security, like generateToken() * * @return string * @static @@ -652,10 +697,8 @@ class User { * Load user data from the session or login cookie. If there are no valid * credentials, initialises the user as an anon. * @return true if the user is logged in, false otherwise - * - * @private */ - function loadFromSession() { + private function loadFromSession() { global $wgMemc, $wgCookiePrefix; if ( isset( $_SESSION['wsUserID'] ) ) { @@ -702,6 +745,7 @@ class User { } if ( ( $sName == $this->mName ) && $passwordCorrect ) { + $_SESSION['wsToken'] = $this->mToken; wfDebug( "Logged in from $from\n" ); return true; } else { @@ -865,7 +909,8 @@ class User { wfProfileIn( __METHOD__ ); wfDebug( __METHOD__.": checking...\n" ); - $this->mBlockedby = 0; + $this->mBlockedby = 0; + $this->mHideName = 0; $ip = wfGetIP(); if ($this->isAllowed( 'ipblock-exempt' ) ) { @@ -880,6 +925,7 @@ class User { wfDebug( __METHOD__.": Found block.\n" ); $this->mBlockedby = $this->mBlock->mBy; $this->mBlockreason = $this->mBlock->mReason; + $this->mHideName = $this->mBlock->mHideName; if ( $this->isLoggedIn() ) { $this->spreadBlock(); } @@ -954,7 +1000,8 @@ class User { * @return bool */ public function isPingLimitable() { - return array_intersect($this->getEffectiveGroups(), $wgRateLimitsExcludedGroups) != array(); + global $wgRateLimitsExcludedGroups; + return array_intersect($this->getEffectiveGroups(), $wgRateLimitsExcludedGroups) == array(); } /** @@ -968,22 +1015,22 @@ class User { * @public */ function pingLimiter( $action='edit' ) { - + # Call the 'PingLimiter' hook $result = false; if( !wfRunHooks( 'PingLimiter', array( &$this, $action, $result ) ) ) { return $result; } - - global $wgRateLimits, $wgRateLimitsExcludedGroups; + + global $wgRateLimits; if( !isset( $wgRateLimits[$action] ) ) { return false; } - + # Some groups shouldn't trigger the ping limiter, ever if( !$this->isPingLimitable() ) return false; - + global $wgMemc, $wgRateLimitLog; wfProfileIn( __METHOD__ ); @@ -1057,14 +1104,13 @@ class User { wfProfileIn( __METHOD__ ); wfDebug( __METHOD__.": enter\n" ); - if ( $wgBlockAllowsUTEdit && $title->getText() === $this->getName() && - $title->getNamespace() == NS_USER_TALK ) - { + wfDebug( __METHOD__.": asking isBlocked()\n" ); + $blocked = $this->isBlocked( $bFromSlave ); + # If a user's name is suppressed, they cannot make edits anywhere + if ( !$this->mHideName && $wgBlockAllowsUTEdit && $title->getText() === $this->getName() && + $title->getNamespace() == NS_USER_TALK ) { $blocked = false; wfDebug( __METHOD__.": self-talk page, ignoring any blocks\n" ); - } else { - wfDebug( __METHOD__.": asking isBlocked()\n" ); - $blocked = $this->isBlocked( $bFromSlave ); } wfProfileOut( __METHOD__ ); return $blocked; @@ -1091,9 +1137,16 @@ class User { /** * Get the user ID. Returns 0 if the user is anonymous or nonexistent. */ - function getID() { - $this->load(); - return $this->mId; + function getID() { + if( $this->mId === null and $this->mName !== null + and User::isIP( $this->mName ) ) { + // Special case, we know the user is anonymous + return 0; + } elseif( $this->mId === null ) { + // Don't load if this was initialized from an ID + $this->load(); + } + return $this->mId; } /** @@ -1115,7 +1168,8 @@ class User { } else { $this->load(); if ( $this->mName === false ) { - $this->mName = wfGetIP(); + # Clean up IPs + $this->mName = IP::sanitizeIP( wfGetIP() ); } return $this->mName; } @@ -1160,11 +1214,13 @@ class User { global $wgMemc; $key = wfMemcKey( 'newtalk', 'ip', $this->getName() ); $newtalk = $wgMemc->get( $key ); - if( $newtalk != "" ) { + if( strval( $newtalk ) !== '' ) { $this->mNewtalk = (bool)$newtalk; } else { - $this->mNewtalk = $this->checkNewtalk( 'user_ip', $this->getName() ); - $wgMemc->set( $key, (int)$this->mNewtalk, time() + 1800 ); + // Since we are caching this, make sure it is up to date by getting it + // from the master + $this->mNewtalk = $this->checkNewtalk( 'user_ip', $this->getName(), true ); + $wgMemc->set( $key, (int)$this->mNewtalk, 1800 ); } } else { $this->mNewtalk = $this->checkNewtalk( 'user_id', $this->mId ); @@ -1191,18 +1247,22 @@ class User { /** - * Perform a user_newtalk check on current slaves; if the memcached data - * is funky we don't want newtalk state to get stuck on save, as that's - * damn annoying. - * + * Perform a user_newtalk check, uncached. + * Use getNewtalk for a cached check. + * * @param string $field * @param mixed $id + * @param bool $fromMaster True to fetch from the master, false for a slave * @return bool * @private */ - function checkNewtalk( $field, $id ) { - $dbr = wfGetDB( DB_SLAVE ); - $ok = $dbr->selectField( 'user_newtalk', $field, + function checkNewtalk( $field, $id, $fromMaster = false ) { + if ( $fromMaster ) { + $db = wfGetDB( DB_MASTER ); + } else { + $db = wfGetDB( DB_SLAVE ); + } + $ok = $db->selectField( 'user_newtalk', $field, array( $field => $id ), __METHOD__ ); return $ok !== false; } @@ -1214,17 +1274,18 @@ class User { * @private */ function updateNewtalk( $field, $id ) { - if( $this->checkNewtalk( $field, $id ) ) { - wfDebug( __METHOD__." already set ($field, $id), ignoring\n" ); - return false; - } $dbw = wfGetDB( DB_MASTER ); $dbw->insert( 'user_newtalk', array( $field => $id ), __METHOD__, 'IGNORE' ); - wfDebug( __METHOD__.": set on ($field, $id)\n" ); - return true; + if ( $dbw->affectedRows() ) { + wfDebug( __METHOD__.": set on ($field, $id)\n" ); + return true; + } else { + wfDebug( __METHOD__." already set ($field, $id)\n" ); + return false; + } } /** @@ -1234,16 +1295,17 @@ class User { * @private */ function deleteNewtalk( $field, $id ) { - if( !$this->checkNewtalk( $field, $id ) ) { - wfDebug( __METHOD__.": already gone ($field, $id), ignoring\n" ); - return false; - } $dbw = wfGetDB( DB_MASTER ); $dbw->delete( 'user_newtalk', array( $field => $id ), __METHOD__ ); - wfDebug( __METHOD__.": killed on ($field, $id)\n" ); - return true; + if ( $dbw->affectedRows() ) { + wfDebug( __METHOD__.": killed on ($field, $id)\n" ); + return true; + } else { + wfDebug( __METHOD__.": already gone ($field, $id)\n" ); + return false; + } } /** @@ -1265,6 +1327,7 @@ class User { $field = 'user_id'; $id = $this->getId(); } + global $wgMemc; if( $val ) { $changed = $this->updateNewtalk( $field, $id ); @@ -1272,20 +1335,13 @@ class User { $changed = $this->deleteNewtalk( $field, $id ); } - if( $changed ) { - if( $this->isAnon() ) { - // Anons have a separate memcached space, since - // user records aren't kept for them. - global $wgMemc; - $key = wfMemcKey( 'newtalk', 'ip', $val ); - $wgMemc->set( $key, $val ? 1 : 0 ); - } else { - if( $val ) { - // Make sure the user page is watched, so a notification - // will be sent out if enabled. - $this->addWatch( $this->getTalkPage() ); - } - } + if( $this->isAnon() ) { + // Anons have a separate memcached space, since + // user records aren't kept for them. + $key = wfMemcKey( 'newtalk', 'ip', $id ); + $wgMemc->set( $key, $val ? 1 : 0, 1800 ); + } + if ( $changed ) { $this->invalidateCache(); } } @@ -1340,7 +1396,8 @@ class User { /** * Encrypt a password. - * It can eventuall salt a password @see User::addSalt() + * It can eventually salt a password. + * @see User::addSalt() * @param string $p clear Password. * @return string Encrypted password. */ @@ -1377,11 +1434,23 @@ class User { $wgMinimalPasswordLength ) ); } } - + if( !$wgAuth->setPassword( $this, $str ) ) { throw new PasswordError( wfMsg( 'externaldberror' ) ); } + $this->setInternalPassword( $str ); + + return true; + } + + /** + * Set the password and reset the random token no matter + * what. + * + * @param string $str + */ + function setInternalPassword( $str ) { $this->load(); $this->setToken(); @@ -1393,10 +1462,7 @@ class User { } $this->mNewpassword = ''; $this->mNewpassTime = null; - - return true; } - /** * Set the random token (used for persistent authentication) * Called from loadDefaults() among other places. @@ -1556,6 +1622,7 @@ class User { function getRights() { if ( is_null( $this->mRights ) ) { $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() ); + wfRunHooks( 'UserGetRights', array( $this, &$this->mRights ) ); } return $this->mRights; } @@ -1572,8 +1639,8 @@ class User { /** * Get the list of implicit group memberships this user has. - * This includes all explicit groups, plus 'user' if logged in - * and '*' for all accounts. + * This includes all explicit groups, plus 'user' if logged in, + * '*' for all accounts and autopromoted groups * @param boolean $recache Don't use the cache * @return array of strings */ @@ -1584,23 +1651,14 @@ class User { $this->mEffectiveGroups[] = '*'; if( $this->mId ) { $this->mEffectiveGroups[] = 'user'; - - global $wgAutoConfirmAge, $wgAutoConfirmCount; - $accountAge = time() - wfTimestampOrNull( TS_UNIX, $this->mRegistration ); - if( $accountAge >= $wgAutoConfirmAge && $this->getEditCount() >= $wgAutoConfirmCount ) { - $this->mEffectiveGroups[] = 'autoconfirmed'; - } - # Implicit group for users whose email addresses are confirmed - global $wgEmailAuthentication; - if( self::isValidEmailAddr( $this->mEmail ) ) { - if( $wgEmailAuthentication ) { - if( $this->mEmailAuthenticated ) - $this->mEffectiveGroups[] = 'emailconfirmed'; - } else { - $this->mEffectiveGroups[] = 'emailconfirmed'; - } - } + $this->mEffectiveGroups = array_unique( array_merge( + $this->mEffectiveGroups, + Autopromote::getAutopromoteGroups( $this ) + ) ); + + # Hook for additional groups + wfRunHooks( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) ); } } return $this->mEffectiveGroups; @@ -1623,7 +1681,7 @@ class User { /** * Add the user to the given group. * This takes immediate effect. - * @string $group + * @param string $group */ function addGroup( $group ) { $this->load(); @@ -1647,7 +1705,7 @@ class User { /** * Remove the user from the given group. * This takes immediate effect. - * @string $group + * @param string $group */ function removeGroup( $group ) { $this->load(); @@ -1673,7 +1731,7 @@ class User { * @return bool */ function isLoggedIn() { - return( $this->getID() != 0 ); + return $this->getID() != 0; } /** @@ -1840,7 +1898,7 @@ class User { 'wl_notificationtimestamp' => NULL ), array( /* WHERE */ 'wl_user' => $currentUser - ), 'UserMailer::clearAll' + ), __METHOD__ ); # we also need to clear here the "you have new message" notification for the own user_talk page @@ -1900,10 +1958,21 @@ class User { } /** - * Logout user - * Clears the cookies and session, resets the instance cache + * Logout user. */ function logout() { + global $wgUser; + if( wfRunHooks( 'UserLogout', array(&$this) ) ) { + $this->doLogout(); + wfRunHooks( 'UserLogoutComplete', array(&$wgUser) ); + } + } + + /** + * Really logout user + * Clears the cookies and session, resets the instance cache + */ + function doLogout() { global $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookiePrefix; $this->clearInstanceCache( 'defaults' ); @@ -1918,7 +1987,7 @@ class User { /** * Save object settings into database - * @fixme Only rarely do all these fields need to be set! + * @todo Only rarely do all these fields need to be set! */ function saveSettings() { $this->load(); @@ -1949,11 +2018,11 @@ class User { /** - * Checks if a user with the given name exists, returns the ID + * Checks if a user with the given name exists, returns the ID. */ function idForName() { $s = trim( $this->getName() ); - if ( 0 == strcmp( '', $s ) ) return 0; + if ( $s === '' ) return 0; $dbr = wfGetDB( DB_SLAVE ); $id = $dbr->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__ ); @@ -2101,6 +2170,8 @@ class User { // extra options or other effects on the parser cache. wfRunHooks( 'PageRenderingHash', array( &$confstr ) ); + // Make it a valid memcached key fragment + $confstr = str_replace( ' ', '_', $confstr ); $this->mHash = $confstr; return $confstr; } @@ -2110,6 +2181,17 @@ class User { return $this->mBlock && $this->mBlock->mCreateAccount; } + /** + * Determine if the user is blocked from using Special:Emailuser. + * + * @public + * @return boolean + */ + function isBlockedFromEmailuser() { + $this->getBlockedStatus(); + return $this->mBlock && $this->mBlock->mBlockEmail; + } + function isAllowedToCreateAccount() { return $this->isAllowed( 'createaccount' ) && !$this->isBlockedFromCreateAccount(); } @@ -2186,6 +2268,9 @@ class User { } elseif( $wgAuth->strict() ) { /* Auth plugin doesn't allow local authentication */ return false; + } elseif( $wgAuth->strictUserAuth( $this->getName() ) ) { + /* Auth plugin doesn't allow local authentication for this user name */ + return false; } $ep = $this->encryptPassword( $password ); if ( 0 == strcmp( $ep, $this->mPassword ) ) { @@ -2223,16 +2308,20 @@ class User { * @public */ function editToken( $salt = '' ) { - if( !isset( $_SESSION['wsEditToken'] ) ) { - $token = $this->generateToken(); - $_SESSION['wsEditToken'] = $token; + if ( $this->isAnon() ) { + return EDIT_TOKEN_SUFFIX; } else { - $token = $_SESSION['wsEditToken']; - } - if( is_array( $salt ) ) { - $salt = implode( '|', $salt ); + if( !isset( $_SESSION['wsEditToken'] ) ) { + $token = $this->generateToken(); + $_SESSION['wsEditToken'] = $token; + } else { + $token = $_SESSION['wsEditToken']; + } + if( is_array( $salt ) ) { + $salt = implode( '|', $salt ); + } + return md5( $token . $salt ) . EDIT_TOKEN_SUFFIX; } - return md5( $token . $salt ) . EDIT_TOKEN_SUFFIX; } /** @@ -2257,7 +2346,6 @@ class User { * @public */ function matchEditToken( $val, $salt = '' ) { - global $wgMemc; $sessionToken = $this->editToken( $salt ); if ( $val != $sessionToken ) { wfDebug( "User::matchEditToken: broken session data\n" ); @@ -2265,6 +2353,14 @@ class User { return $val == $sessionToken; } + /** + * Check whether the edit token is fine except for the suffix + */ + function matchEditTokenNoSuffix( $val, $salt = '' ) { + $sessionToken = $this->editToken( $salt ); + return substr( $sessionToken, 0, 32 ) == substr( $val, 0, 32 ); + } + /** * Generate a new e-mail confirmation token and send a confirmation * mail to the user's given address. @@ -2289,25 +2385,18 @@ class User { * * @param string $subject * @param string $body - * @param strong $from Optional from address; default $wgPasswordSender will be used otherwise. + * @param string $from Optional from address; default $wgPasswordSender will be used otherwise. * @return mixed True on success, a WikiError object on failure. */ - function sendMail( $subject, $body, $from = null ) { + function sendMail( $subject, $body, $from = null, $replyto = null ) { if( is_null( $from ) ) { global $wgPasswordSender; $from = $wgPasswordSender; } - require_once( 'UserMailer.php' ); $to = new MailAddress( $this ); $sender = new MailAddress( $from ); - $error = userMailer( $to, $sender, $subject, $body ); - - if( $error == '' ) { - return true; - } else { - return new WikiError( $error ); - } + return UserMailer::send( $to, $sender, $subject, $body, $replyto ); } /** @@ -2364,7 +2453,9 @@ class User { * @return bool */ function canSendEmail() { - return $this->isEmailConfirmed(); + $canSend = $this->isEmailConfirmed(); + wfRunHooks( 'UserCanSendEmail', array( &$this, &$canSend ) ); + return $canSend; } /** @@ -2373,7 +2464,7 @@ class User { * @return bool */ function canReceiveEmail() { - return $this->canSendEmail() && !$this->getOption( 'disablemail' ); + return $this->isEmailConfirmed() && !$this->getOption( 'disablemail' ); } /** @@ -2414,6 +2505,18 @@ class User { $this->mEmailToken && $this->mEmailTokenExpires > wfTimestamp(); } + + /** + * Get the timestamp of account creation, or false for + * non-existent/anonymous user accounts + * + * @return mixed + */ + public function getRegistration() { + return $this->mId > 0 + ? $this->mRegistration + : false; + } /** * @param array $groups list of groups @@ -2438,13 +2541,13 @@ class User { * @static */ static function getGroupName( $group ) { + global $wgMessageCache; + $wgMessageCache->loadAllMessages(); $key = "group-$group"; $name = wfMsg( $key ); - if( $name == '' || wfEmptyMsg( $key, $name ) ) { - return $group; - } else { - return $name; - } + return $name == '' || wfEmptyMsg( $key, $name ) + ? $group + : $name; } /** @@ -2453,13 +2556,13 @@ class User { * @static */ static function getGroupMember( $group ) { + global $wgMessageCache; + $wgMessageCache->loadAllMessages(); $key = "group-$group-member"; $name = wfMsg( $key ); - if( $name == '' || wfEmptyMsg( $key, $name ) ) { - return $group; - } else { - return $name; - } + return $name == '' || wfEmptyMsg( $key, $name ) + ? $group + : $name; } /** @@ -2474,7 +2577,20 @@ class User { global $wgGroupPermissions; return array_diff( array_keys( $wgGroupPermissions ), - array( '*', 'user', 'autoconfirmed', 'emailconfirmed' ) ); + self::getImplicitGroups() + ); + } + + /** + * Get a list of implicit groups + * + * @return array + */ + public static function getImplicitGroups() { + global $wgImplicitGroups; + $groups = $wgImplicitGroups; + wfRunHooks( 'UserGetImplicitGroups', array( &$groups ) ); #deprecated, use $wgImplictGroups instead + return $groups; } /** @@ -2484,6 +2600,8 @@ class User { * @return mixed */ static function getGroupPage( $group ) { + global $wgMessageCache; + $wgMessageCache->loadAllMessages(); $page = wfMsgForContent( 'grouppage-' . $group ); if( !wfEmptyMsg( 'grouppage-' . $group, $page ) ) { $title = Title::newFromText( $page ); @@ -2579,4 +2697,5 @@ class User { } } -?> + +