* - 'usable' Valid for batch processes and login
* - 'creatable' Valid for batch processes, login and account creation
*
+ * @throws MWException
* @return bool|string
*/
public static function getCanonicalName( $name, $validate = 'valid' ) {
if( $loggedOut !== null ) {
$this->mTouched = wfTimestamp( TS_MW, $loggedOut );
} else {
- $this->mTouched = '0'; # Allow any pages to be cached
+ $this->mTouched = '1'; # Allow any pages to be cached
}
$this->mToken = null; // Don't run cryptographic functions till we need a token
$this->mEffectiveGroups = null;
$this->mImplicitGroups = null;
$this->mOptions = null;
+ $this->mEditCount = null;
if ( $reloadFrom ) {
$this->mLoadedItems = array();
$defOpt = $wgDefaultUserOptions;
# default language setting
- $variant = $wgContLang->getDefaultVariant();
- $defOpt['variant'] = $variant;
- $defOpt['language'] = $variant;
+ $defOpt['variant'] = $wgContLang->getCode();
+ $defOpt['language'] = $wgContLang->getCode();
foreach( SearchEngine::searchableNamespaces() as $nsnum => $nsname ) {
$defOpt['searchNs'.$nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
}
}
/**
- * Add this existing user object to the database
+ * Add this existing user object to the database. If the user already
+ * exists, a fatal status object is returned, and the user object is
+ * initialised with the data from the database.
+ *
+ * Previously, this function generated a DB error due to a key conflict
+ * if the user already existed. Many extension callers use this function
+ * in code along the lines of:
+ *
+ * $user = User::newFromName( $name );
+ * if ( !$user->isLoggedIn() ) {
+ * $user->addToDatabase();
+ * }
+ * // do something with $user...
+ *
+ * However, this was vulnerable to a race condition (bug 16020). By
+ * initialising the user object if the user exists, we aim to support this
+ * calling sequence as far as possible.
+ *
+ * Note that if the user exists, this function will acquire a write lock,
+ * so it is still advisable to make the call conditional on isLoggedIn(),
+ * and to commit the transaction after calling.
+ *
+ * @return Status
*/
public function addToDatabase() {
$this->load();
'user_registration' => $dbw->timestamp( $this->mRegistration ),
'user_editcount' => 0,
'user_touched' => $dbw->timestamp( $this->mTouched ),
- ), __METHOD__
+ ), __METHOD__,
+ array( 'IGNORE' )
);
+ if ( !$dbw->affectedRows() ) {
+ $this->mId = $dbw->selectField( 'user', 'user_id',
+ array( 'user_name' => $this->mName ), __METHOD__ );
+ $loaded = false;
+ if ( $this->mId ) {
+ if ( $this->loadFromDatabase() ) {
+ $loaded = true;
+ }
+ }
+ if ( !$loaded ) {
+ throw new MWException( __METHOD__. ": hit a key conflict attempting " .
+ "to insert a user row, but then it doesn't exist when we select it!" );
+ }
+ return Status::newFatal( 'userexists' );
+ }
$this->mId = $dbw->insertId();
// Clear instance cache other than user table data, which is already accurate
$this->clearInstanceCache();
$this->saveOptions();
+ return Status::newGood();
}
/**
public static function getGroupsWithPermission( $role ) {
global $wgGroupPermissions;
$allowedGroups = array();
- foreach ( $wgGroupPermissions as $group => $rights ) {
- if ( isset( $rights[$role] ) && $rights[$role] ) {
+ foreach ( array_keys( $wgGroupPermissions ) as $group ) {
+ if ( self::groupHasPermission( $group, $role ) ) {
$allowedGroups[] = $group;
}
}
return $allowedGroups;
}
+ /**
+ * Check, if the given group has the given permission
+ *
+ * @param $group String Group to check
+ * @param $role String Role to check
+ * @return bool
+ */
+ public static function groupHasPermission( $group, $role ) {
+ global $wgGroupPermissions, $wgRevokePermissions;
+ return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
+ && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
+ }
+
/**
* Get the localized descriptive name for a group, if it exists
*
* @todo document
*/
protected function loadOptions() {
+ global $wgContLang;
+
$this->load();
- if ( $this->mOptionsLoaded || !$this->getId() )
+
+ if ( $this->mOptionsLoaded ) {
return;
+ }
$this->mOptions = self::getDefaultOptions();
+ if ( !$this->getId() ) {
+ // For unlogged-in users, load language/variant options from request.
+ // There's no need to do it for logged-in users: they can set preferences,
+ // and handling of page content is done by $pageLang->getPreferredVariant() and such,
+ // so don't override user's choice (especially when the user chooses site default).
+ $variant = $wgContLang->getDefaultVariant();
+ $this->mOptions['variant'] = $variant;
+ $this->mOptions['language'] = $variant;
+ $this->mOptionsLoaded = true;
+ return;
+ }
+
// Maybe load from the object
if ( !is_null( $this->mOptionOverrides ) ) {
wfDebug( "User: loading options for user " . $this->getId() . " from override cache.\n" );