* @package MediaWiki
*/
-/**
- *
- */
-require_once( 'WatchedItem.php' );
-
# Number of characters in user_token field
define( 'USER_TOKEN_LENGTH', 32 );
# Serialized record version
-define( 'MW_USER_VERSION', 2 );
+define( 'MW_USER_VERSION', 3 );
/**
*
* @package MediaWiki
*/
class User {
- /**#@+
- * @access private
- */
- var $mId, $mName, $mPassword, $mEmail, $mNewtalk;
- var $mEmailAuthenticated;
- var $mRights, $mOptions;
- var $mDataLoaded, $mNewpassword;
- var $mSkin;
- var $mBlockedby, $mBlockreason;
- var $mTouched;
- var $mToken;
- var $mRealName;
- var $mHash;
- var $mGroups;
- var $mVersion; // serialized version
-
- /** Construct using User:loadDefaults() */
+ /*
+ * When adding a new private variable, dont forget to add it to __sleep()
+ */
+ /**@{{
+ * @private
+ */
+ var $mBlockedby; //!<
+ var $mBlockreason; //!<
+ var $mDataLoaded; //!<
+ var $mEmail; //!<
+ var $mEmailAuthenticated; //!<
+ var $mGroups; //!<
+ var $mHash; //!<
+ var $mId; //!<
+ var $mName; //!<
+ var $mNewpassword; //!<
+ var $mNewtalk; //!<
+ var $mOptions; //!<
+ var $mPassword; //!<
+ var $mRealName; //!<
+ var $mRegistration; //!<
+ var $mRights; //!<
+ var $mSkin; //!<
+ var $mToken; //!<
+ var $mTouched; //!<
+ var $mVersion; //!< serialized version
+ /**@}} */
+
+ /** Constructor using User:loadDefaults() */
function User() {
$this->loadDefaults();
$this->mVersion = MW_USER_VERSION;
/**
* Static factory method
* @param string $name Username, validated by Title:newFromText()
+ * @param bool $validate Validate username
* @return User
* @static
*/
- function newFromName( $name ) {
+ function newFromName( $name, $validate = true ) {
# Force usernames to capital
global $wgContLang;
$name = $wgContLang->ucfirst( $name );
global $wgAuth;
$canonicalName = $wgAuth->getCanonicalName( $t->getText() );
- if( !User::isValidUserName( $canonicalName ) ) {
+ if( $validate && !User::isValidUserName( $canonicalName ) ) {
return null;
}
/**
* Serialze sleep function, for better cache efficiency and avoidance of
- * silly "incomplete type" errors when skins are cached
+ * silly "incomplete type" errors when skins are cached. The array should
+ * contain names of private variables (see at top of User.php).
*/
function __sleep() {
- return array( 'mId', 'mName', 'mPassword', 'mEmail', 'mNewtalk',
- 'mEmailAuthenticated', 'mRights', 'mOptions', 'mDataLoaded',
- 'mNewpassword', 'mBlockedby', 'mBlockreason', 'mTouched',
- 'mToken', 'mRealName', 'mHash', 'mGroups' );
+ return array(
+'mBlockedby',
+'mBlockreason',
+'mDataLoaded',
+'mEmail',
+'mEmailAuthenticated',
+'mGroups',
+'mHash',
+'mId',
+'mName',
+'mNewpassword',
+'mNewtalk',
+'mOptions',
+'mPassword',
+'mRealName',
+'mRegistration',
+'mRights',
+'mToken',
+'mTouched',
+'mVersion',
+);
}
/**
}
/**
- * does the string match an anonymous IPv4 address?
+ * Does the string match an anonymous IPv4 address?
*
- * Note: We match \d{1,3}\.\d{1,3}\.\d{1,3}\.xxx as an anonymous IP
+ * This function exists for username validation, in order to reject
+ * usernames which are similar in form to IP addresses. Strings such
+ * as 300.300.300.300 will return true because it looks like an IP
+ * address, despite not being strictly valid.
+ *
+ * We match \d{1,3}\.\d{1,3}\.\d{1,3}\.xxx as an anonymous IP
* address because the usemod software would "cloak" anonymous IP
* addresses like this, if we allowed accounts like this to be created
* new users could get the old edits of these anonymous users.
|| strlen( $name ) > $wgMaxNameChars
|| $name != $wgContLang->ucfirst( $name ) )
return false;
-
+
// Ensure that the name can't be misresolved as a different title,
// such as with extra namespace keys at the start.
$parsed = Title::newFromText( $name );
|| $parsed->getNamespace()
|| strcmp( $name, $parsed->getPrefixedText() ) )
return false;
- else
- return true;
+
+ // Check an additional blacklist of troublemaker characters.
+ // Should these be merged into the title char list?
+ $unicodeBlacklist = '/[' .
+ '\x{0080}-\x{009f}' . # iso-8859-1 control chars
+ '\x{00a0}' . # non-breaking space
+ '\x{2000}-\x{200f}' . # various whitespace
+ '\x{2028}-\x{202f}' . # breaks and control chars
+ '\x{3000}' . # ideographic space
+ '\x{e000}-\x{f8ff}' . # private use
+ ']/u';
+ if( preg_match( $unicodeBlacklist, $name ) ) {
+ return false;
+ }
+
+ return true;
}
/**
$fname = 'User::loadDefaults' . $n;
wfProfileIn( $fname );
- global $wgContLang, $wgDBname;
+ global $wgCookiePrefix;
global $wgNamespacesToBeSearchedDefault;
$this->mId = 0;
$this->setToken(); # Random
$this->mHash = false;
- if ( isset( $_COOKIE[$wgDBname.'LoggedOut'] ) ) {
- $this->mTouched = wfTimestamp( TS_MW, $_COOKIE[$wgDBname.'LoggedOut'] );
+ if ( isset( $_COOKIE[$wgCookiePrefix.'LoggedOut'] ) ) {
+ $this->mTouched = wfTimestamp( TS_MW, $_COOKIE[$wgCookiePrefix.'LoggedOut'] );
}
else {
$this->mTouched = '0'; # Allow any pages to be cached
}
+ $this->mRegistration = wfTimestamp( TS_MW );
+
wfProfileOut( $fname );
}
*
* @return array
* @static
- * @access private
+ * @private
*/
function getDefaultOptions() {
/**
* @param string $opt
* @return string
* @static
- * @access public
+ * @public
*/
function getDefaultOption( $opt ) {
$defOpts = User::getDefaultOptions();
/**
* Get blocking information
- * @access private
+ * @private
* @param bool $bFromSlave Specify whether to check slave or master. To improve performance,
* non-critical checks are done against slaves. Check when actually saving should be done against
* master.
}
# Proxy blocking
- if ( !$this->isSysop() && !in_array( $ip, $wgProxyWhitelist ) ) {
+ # FIXME ? proxyunbannable is to deprecate the old isSysop()
+ if ( !$this->isAllowed('proxyunbannable') && !in_array( $ip, $wgProxyWhitelist ) ) {
# Local list
if ( wfIsLocallyBlockedProxy( $ip ) ) {
$this->inDnsBlacklist( $ip, 'http.dnsbl.sorbs.net.' );
}
- function inOpmBlacklist( $ip ) {
- global $wgEnableOpm;
- return $wgEnableOpm &&
- $this->inDnsBlacklist( $ip, 'opm.blitzed.org.' );
- }
-
function inDnsBlacklist( $ip, $base ) {
$fname = 'User::inDnsBlacklist';
wfProfileIn( $fname );
* last-hit counters will be shared across wikis.
*
* @return bool true if a rate limiter was tripped
- * @access public
+ * @public
*/
function pingLimiter( $action='edit' ) {
- global $wgRateLimits;
+ global $wgRateLimits, $wgRateLimitsExcludedGroups;
if( !isset( $wgRateLimits[$action] ) ) {
return false;
}
- if( $this->isAllowed( 'delete' ) ) {
- // goddam cabal
- return false;
+
+ # Some groups shouldn't trigger the ping limiter, ever
+ foreach( $this->getGroups() as $group ) {
+ if( array_search( $group, $wgRateLimitsExcludedGroups ) !== false )
+ return false;
}
-
+
global $wgMemc, $wgDBname, $wgRateLimitLog;
$fname = 'User::pingLimiter';
wfProfileIn( $fname );
* @static
*/
function loadFromSession() {
- global $wgMemc, $wgDBname;
+ global $wgMemc, $wgDBname, $wgCookiePrefix;
if ( isset( $_SESSION['wsUserID'] ) ) {
if ( 0 != $_SESSION['wsUserID'] ) {
} else {
return new User();
}
- } else if ( isset( $_COOKIE["{$wgDBname}UserID"] ) ) {
- $sId = intval( $_COOKIE["{$wgDBname}UserID"] );
+ } else if ( isset( $_COOKIE["{$wgCookiePrefix}UserID"] ) ) {
+ $sId = intval( $_COOKIE["{$wgCookiePrefix}UserID"] );
$_SESSION['wsUserID'] = $sId;
} else {
return new User();
}
if ( isset( $_SESSION['wsUserName'] ) ) {
$sName = $_SESSION['wsUserName'];
- } else if ( isset( $_COOKIE["{$wgDBname}UserName"] ) ) {
- $sName = $_COOKIE["{$wgDBname}UserName"];
+ } else if ( isset( $_COOKIE["{$wgCookiePrefix}UserName"] ) ) {
+ $sName = $_COOKIE["{$wgCookiePrefix}UserName"];
$_SESSION['wsUserName'] = $sName;
} else {
return new User();
if ( isset( $_SESSION['wsToken'] ) ) {
$passwordCorrect = $_SESSION['wsToken'] == $user->mToken;
- } else if ( isset( $_COOKIE["{$wgDBname}Token"] ) ) {
- $passwordCorrect = $user->mToken == $_COOKIE["{$wgDBname}Token"];
+ } else if ( isset( $_COOKIE["{$wgCookiePrefix}Token"] ) ) {
+ $passwordCorrect = $user->mToken == $_COOKIE["{$wgCookiePrefix}Token"];
} else {
return new User(); # Can't log in from session
}
$dbr =& wfGetDB( DB_SLAVE );
$s = $dbr->selectRow( 'user', array( 'user_name','user_password','user_newpassword','user_email',
'user_email_authenticated',
- 'user_real_name','user_options','user_touched', 'user_token' ),
+ 'user_real_name','user_options','user_touched', 'user_token', 'user_registration' ),
array( 'user_id' => $this->mId ), $fname );
if ( $s !== false ) {
$this->decodeOptions( $s->user_options );
$this->mTouched = wfTimestamp(TS_MW,$s->user_touched);
$this->mToken = $s->user_token;
+ $this->mRegistration = wfTimestampOrNull( TS_MW, $s->user_registration );
$res = $dbr->select( 'user_groups',
array( 'ug_group' ),
while( $row = $dbr->fetchObject( $res ) ) {
$this->mGroups[] = $row->ug_group;
}
- $effectiveGroups = array_merge( array( '*', 'user' ), $this->mGroups );
+ $implicitGroups = array( '*', 'user' );
+
+ global $wgAutoConfirmAge;
+ $accountAge = time() - wfTimestampOrNull( TS_UNIX, $this->mRegistration );
+ if( $accountAge >= $wgAutoConfirmAge ) {
+ $implicitGroups[] = 'autoconfirmed';
+ }
+
+ $effectiveGroups = array_merge( $implicitGroups, $this->mGroups );
$this->mRights = $this->getGroupPermissions( $effectiveGroups );
}
/**
* Return the title dbkey form of the name, for eg user pages.
* @return string
- * @access public
+ * @public
*/
function getTitleKey() {
return str_replace( ' ', '_', $this->getName() );
return (bool)$this->mNewtalk;
}
+ /**
+ * Return the talk page(s) this user has new messages on.
+ */
+ function getNewMessageLinks() {
+ global $wgDBname;
+ $talks = array();
+ if (!wfRunHooks('UserRetrieveNewTalks', array(&$this, &$talks)))
+ return $talks;
+
+ if (!$this->getNewtalk())
+ return array();
+ $up = $this->getUserPage();
+ $utp = $up->getTalkPage();
+ return array(array("wiki" => $wgDBname, "link" => $utp->getLocalURL()));
+ }
+
+
/**
* 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
* @param string $field
* @param mixed $id
* @return bool
- * @access private
+ * @private
*/
function checkNewtalk( $field, $id ) {
$fname = 'User::checkNewtalk';
array( $field => $id ), $fname );
return $ok !== false;
}
-
+
/**
- * Add or update the
+ * Add or update the
* @param string $field
* @param mixed $id
- * @access private
+ * @private
*/
function updateNewtalk( $field, $id ) {
$fname = 'User::updateNewtalk';
wfDebug( "$fname: set on ($field, $id)\n" );
return true;
}
-
+
/**
+ * Clear the new messages flag for the given user
* @param string $field
* @param mixed $id
- * @access private
+ * @private
*/
function deleteNewtalk( $field, $id ) {
$fname = 'User::deleteNewtalk';
wfDebug( "$fname: killed on ($field, $id)\n" );
return true;
}
-
+
/**
* Update the 'You have new messages!' status.
* @param bool $val
if( wfReadOnly() ) {
return;
}
-
+
$this->loadFromDatabase();
$this->mNewtalk = $val;
$fname = 'User::setNewtalk';
-
+
if( $this->isAnon() ) {
$field = 'user_ip';
$id = $this->getName();
$field = 'user_id';
$id = $this->getId();
}
-
+
if( $val ) {
$changed = $this->updateNewtalk( $field, $id );
} else {
$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 $wgDBname, $wgMemc;
- $key = "$wgDBname:newtalk:ip:$value";
+ $key = "$wgDBname:newtalk:ip:$val";
$wgMemc->set( $key, $val ? 1 : 0 );
} else {
if( $val ) {
$this->mRealName = $str;
}
+ /**
+ * @param string $oname The option to check
+ * @return string
+ */
function getOption( $oname ) {
$this->loadFromDatabase();
if ( array_key_exists( $oname, $this->mOptions ) ) {
}
}
+ /**
+ * @param string $oname The option to check
+ * @return bool False if the option is not selected, true if it is
+ */
+ function getBoolOption( $oname ) {
+ return (bool)$this->getOption( $oname );
+ }
+
+ /**
+ * Get an option as an integer value from the source string.
+ * @param string $oname The option to check
+ * @param int $default Optional value to return if option is unset/blank.
+ * @return int
+ */
+ function getIntOption( $oname, $default=0 ) {
+ $val = $this->getOption( $oname );
+ if( $val == '' ) {
+ $val = $default;
+ }
+ return intval( $val );
+ }
+
function setOption( $oname, $val ) {
$this->loadFromDatabase();
if ( $oname == 'skin' ) {
# Clear cached skin, so the new one displays immediately in Special:Preferences
unset( $this->mSkin );
}
+ // Filter out any newlines that may have passed through input validation.
+ // Newlines are used to separate items in the options blob.
+ $val = str_replace( "\r\n", "\n", $val );
+ $val = str_replace( "\r", "\n", $val );
+ $val = str_replace( "\n", " ", $val );
$this->mOptions[$oname] = $val;
$this->invalidateCache();
}
}
/**
- * Remove the user from the given group.
+ * Add the user to the given group.
* This takes immediate effect.
* @string $group
*/
}
/**
- * Check if a user is sysop
+ * Deprecated in 1.6, die in 1.7, to be removed in 1.8
* @deprecated
*/
function isSysop() {
- return $this->isAllowed( 'protect' );
+ throw new MWException( "Call to deprecated (v1.7) User::isSysop() method\n" );
+ #return $this->isAllowed( 'protect' );
}
- /** @deprecated */
+ /**
+ * Deprecated in 1.6, die in 1.7, to be removed in 1.8
+ * @deprecated
+ */
function isDeveloper() {
- return $this->isAllowed( 'siteadmin' );
+ throw new MWException( "Call to deprecated (v1.7) User::isDeveloper() method\n" );
+ #return $this->isAllowed( 'siteadmin' );
}
- /** @deprecated */
+ /**
+ * Deprecated in 1.6, die in 1.7, to be removed in 1.8
+ * @deprecated
+ */
function isBureaucrat() {
- return $this->isAllowed( 'makesysop' );
+ throw new MWException( "Call to deprecated (v1.7) User::isBureaucrat() method\n" );
+ #return $this->isAllowed( 'makesysop' );
}
/**
* @return boolean True: action is allowed, False: action should not be allowed
*/
function isAllowed($action='') {
+ if ( $action === '' )
+ // In the spirit of DWIM
+ return true;
+
$this->loadFromDatabase();
return in_array( $action , $this->mRights );
}
$fname = 'User::getSkin';
wfProfileIn( $fname );
- # get all skin names available
- $skinNames = Skin::getSkinNames();
-
# get the user skin
$userSkin = $this->getOption( 'skin' );
- $userSkin = $wgRequest->getText('useskin', $userSkin);
- if ( $userSkin == '' ) { $userSkin = 'standard'; }
-
- if ( !isset( $skinNames[$userSkin] ) ) {
- # in case the user skin could not be found find a replacement
- $fallback = array(
- 0 => 'Standard',
- 1 => 'Nostalgia',
- 2 => 'CologneBlue');
- # if phptal is enabled we should have monobook skin that
- # superseed the good old SkinStandard.
- if ( isset( $skinNames['monobook'] ) ) {
- $fallback[0] = 'MonoBook';
- }
+ $userSkin = $wgRequest->getVal('useskin', $userSkin);
- if(is_numeric($userSkin) && isset( $fallback[$userSkin]) ){
- $sn = $fallback[$userSkin];
- } else {
- $sn = 'Standard';
- }
- } else {
- # The user skin is available
- $sn = $skinNames[$userSkin];
- }
-
- # Grab the skin class and initialise it. Each skin checks for PHPTal
- # and will not load if it's not enabled.
- require_once( $IP.'/skins/'.$sn.'.php' );
-
- # Check if we got if not failback to default skin
- $className = 'Skin'.$sn;
- if( !class_exists( $className ) ) {
- # DO NOT die if the class isn't found. This breaks maintenance
- # scripts and can cause a user account to be unrecoverable
- # except by SQL manipulation if a previously valid skin name
- # is no longer valid.
- $className = 'SkinStandard';
- require_once( $IP.'/skins/Standard.php' );
- }
- $this->mSkin =& new $className;
+ $this->mSkin =& Skin::newFromKey( $userSkin );
wfProfileOut( $fname );
}
return $this->mSkin;
function clearNotification( &$title ) {
global $wgUser, $wgUseEnotif;
+
if ($title->getNamespace() == NS_USER_TALK &&
$title->getText() == $this->getName() ) {
+ if (!wfRunHooks('UserClearNewTalkNotification', array(&$this)))
+ return;
$this->setNewtalk( false );
}
-
+
if( !$wgUseEnotif ) {
return;
}
* the next change of any watched page.
*
* @param int $currentUser user ID number
- * @access public
+ * @public
*/
function clearAllNotifications( $currentUser ) {
global $wgUseEnotif;
}
/**
- * @access private
+ * @private
* @return string Encoding options
*/
function encodeOptions() {
}
/**
- * @access private
+ * @private
*/
function decodeOptions( $str ) {
$a = explode( "\n", $str );
}
function setCookies() {
- global $wgCookieExpiration, $wgCookiePath, $wgCookieDomain, $wgDBname;
+ global $wgCookieExpiration, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookiePrefix;
if ( 0 == $this->mId ) return;
$this->loadFromDatabase();
$exp = time() + $wgCookieExpiration;
$_SESSION['wsUserID'] = $this->mId;
- setcookie( $wgDBname.'UserID', $this->mId, $exp, $wgCookiePath, $wgCookieDomain );
+ setcookie( $wgCookiePrefix.'UserID', $this->mId, $exp, $wgCookiePath, $wgCookieDomain, $wgCookieSecure );
$_SESSION['wsUserName'] = $this->getName();
- setcookie( $wgDBname.'UserName', $this->getName(), $exp, $wgCookiePath, $wgCookieDomain );
+ setcookie( $wgCookiePrefix.'UserName', $this->getName(), $exp, $wgCookiePath, $wgCookieDomain, $wgCookieSecure );
$_SESSION['wsToken'] = $this->mToken;
if ( 1 == $this->getOption( 'rememberpassword' ) ) {
- setcookie( $wgDBname.'Token', $this->mToken, $exp, $wgCookiePath, $wgCookieDomain );
+ setcookie( $wgCookiePrefix.'Token', $this->mToken, $exp, $wgCookiePath, $wgCookieDomain, $wgCookieSecure );
} else {
- setcookie( $wgDBname.'Token', '', time() - 3600 );
+ setcookie( $wgCookiePrefix.'Token', '', time() - 3600 );
}
}
* It will clean the session cookie
*/
function logout() {
- global $wgCookiePath, $wgCookieDomain, $wgDBname;
+ global $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookiePrefix;
$this->loadDefaults();
$this->setLoaded( true );
$_SESSION['wsUserID'] = 0;
- setcookie( $wgDBname.'UserID', '', time() - 3600, $wgCookiePath, $wgCookieDomain );
- setcookie( $wgDBname.'Token', '', time() - 3600, $wgCookiePath, $wgCookieDomain );
+ setcookie( $wgCookiePrefix.'UserID', '', time() - 3600, $wgCookiePath, $wgCookieDomain, $wgCookieSecure );
+ setcookie( $wgCookiePrefix.'Token', '', time() - 3600, $wgCookiePath, $wgCookieDomain, $wgCookieSecure );
# Remember when user logged out, to prevent seeing cached pages
- setcookie( $wgDBname.'LoggedOut', wfTimestampNow(), time() + 86400, $wgCookiePath, $wgCookieDomain );
+ setcookie( $wgCookiePrefix.'LoggedOut', wfTimestampNow(), time() + 86400, $wgCookiePath, $wgCookieDomain, $wgCookieSecure );
}
/**
* Save object settings into database
*/
function saveSettings() {
- global $wgMemc, $wgDBname, $wgUseEnotif;
+ global $wgMemc, $wgDBname;
$fname = 'User::saveSettings';
if ( wfReadOnly() ) { return; }
'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
'user_real_name' => $this->mRealName,
'user_options' => $this->encodeOptions(),
- 'user_token' => $this->mToken
+ 'user_token' => $this->mToken,
+ 'user_registration' => $dbw->timestamp( $this->mRegistration ),
), $fname
);
$this->mId = $dbw->insertId();
}
+ /**
+ * Generate a string which will be different for any combination of
+ * user options which would produce different parser output.
+ * This will be used as part of the hash key for the parser cache,
+ * so users will the same options can share the same cached data
+ * safely.
+ *
+ * Extensions which require it should install 'PageRenderingHash' hook,
+ * which will give them a chance to modify this key based on their own
+ * settings.
+ *
+ * @return string
+ */
function getPageRenderingHash() {
global $wgContLang;
if( $this->mHash ){
$extra = $wgContLang->getExtraHashOptions();
$confstr .= $extra;
+ // Give a chance for extensions to modify the hash, if they have
+ // extra options or other effects on the parser cache.
+ wfRunHooks( 'PageRenderingHash', array( &$confstr ) );
+
$this->mHash = $confstr;
- return $confstr ;
+ return $confstr;
}
function isAllowedToCreateAccount() {
* Get this user's personal page title.
*
* @return Title
- * @access public
+ * @public
*/
function getUserPage() {
return Title::makeTitle( NS_USER, $this->getName() );
* Get this user's talk page title.
*
* @return Title
- * @access public
+ * @public
*/
function getTalkPage() {
$title = $this->getUserPage();
/**
* Determine whether the user is a newbie. Newbies are either
- * anonymous IPs, or the 1% most recently created accounts.
- * Bots and sysops are excluded.
+ * anonymous IPs, or the most recently created accounts.
* @return bool True if it is a newbie.
*/
function isNewbie() {
- return $this->isAnon() || $this->mId > User::getMaxID() * 0.99 && !$this->isAllowed( 'delete' ) && !$this->isBot();
+ return !$this->isAllowed( 'autoconfirmed' );
}
/**
* @param mixed $salt - Optional function-specific data for hash.
* Use a string or an array of strings.
* @return string
- * @access public
+ * @public
*/
function editToken( $salt = '' ) {
if( !isset( $_SESSION['wsEditToken'] ) ) {
* @param string $val - the input value to compare
* @param string $salt - Optional function-specific data for hash
* @return bool
- * @access public
+ * @public
*/
function matchEditToken( $val, $salt = '' ) {
global $wgMemc;
-
-/*
- if ( !isset( $_SESSION['wsEditToken'] ) ) {
- $logfile = '/home/wikipedia/logs/session_debug/session.log';
- $mckey = memsess_key( session_id() );
- $uname = @posix_uname();
- $msg = "wsEditToken not set!\n" .
- 'apache server=' . $uname['nodename'] . "\n" .
- 'session_id = ' . session_id() . "\n" .
- '$_SESSION=' . var_export( $_SESSION, true ) . "\n" .
- '$_COOKIE=' . var_export( $_COOKIE, true ) . "\n" .
- "mc get($mckey) = " . var_export( $wgMemc->get( $mckey ), true ) . "\n\n\n";
-
- @error_log( $msg, 3, $logfile );
+ $sessionToken = $this->editToken( $salt );
+ if ( $val != $sessionToken ) {
+ wfDebug( "User::matchEditToken: broken session data\n" );
}
-*/
- return ( $val == $this->editToken( $salt ) );
+ return $val == $sessionToken;
}
/**
* A hash (unsalted since it's used as a key) is stored.
* @param &$expiration mixed output: accepts the expiration time
* @return string
- * @access private
+ * @private
*/
function confirmationToken( &$expiration ) {
$fname = 'User::confirmationToken';
* the URL the user can use to confirm.
* @param &$expiration mixed output: accepts the expiration time
* @return string
- * @access private
+ * @private
*/
function confirmationTokenUrl( &$expiration ) {
$token = $this->confirmationToken( $expiration );
function isEmailConfirmed() {
global $wgEmailAuthentication;
$this->loadFromDatabase();
- if( $this->isAnon() )
- return false;
- if( !$this->isValidEmailAddr( $this->mEmail ) )
- return false;
- if( $wgEmailAuthentication && !$this->getEmailAuthenticationTimestamp() )
- return false;
- return true;
+ $confirmed = true;
+ if( wfRunHooks( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
+ if( $this->isAnon() )
+ return false;
+ if( !$this->isValidEmailAddr( $this->mEmail ) )
+ return false;
+ if( $wgEmailAuthentication && !$this->getEmailAuthenticationTimestamp() )
+ return false;
+ return true;
+ } else {
+ return $confirmed;
+ }
}
/**
/**
* @param string $group key name
- * @return string localized descriptive name, if provided
+ * @return string localized descriptive name for group, if provided
* @static
*/
function getGroupName( $group ) {
- $key = "group-$group-name";
+ $key = "group-$group";
$name = wfMsg( $key );
if( $name == '' || $name == "<$key>" ) {
return $group;
}
}
+ /**
+ * @param string $group key name
+ * @return string localized descriptive name for member of a group, if provided
+ * @static
+ */
+ function getGroupMember( $group ) {
+ $key = "group-$group-member";
+ $name = wfMsg( $key );
+ if( $name == '' || $name == "<$key>" ) {
+ return $group;
+ } else {
+ return $name;
+ }
+ }
+
+
/**
* Return the set of defined explicit groups.
* The * and 'user' groups are not included.
global $wgGroupPermissions;
return array_diff(
array_keys( $wgGroupPermissions ),
- array( '*', 'user' ) );
+ array( '*', 'user', 'autoconfirmed' ) );
}
-
+
+ /**
+ * Get the title of a page describing a particular group
+ *
+ * @param $group Name of the group
+ * @return mixed
+ */
+ function getGroupPage( $group ) {
+ $page = wfMsgForContent( 'grouppage-' . $group );
+ if( !wfEmptyMsg( 'grouppage-' . $group, $page ) ) {
+ $title = Title::newFromText( $page );
+ if( is_object( $title ) )
+ return $title;
+ }
+ return false;
+ }
+
+
}
?>