MediaWiki  master
User.php
Go to the documentation of this file.
1 <?php
30 use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
45 use Wikimedia\Assert\Assert;
46 use Wikimedia\Assert\PreconditionException;
47 use Wikimedia\IPUtils;
51 use Wikimedia\ScopedCallback;
52 
69  use ProtectedHookAccessorTrait;
71 
76  public const READ_EXCLUSIVE = IDBAccessObject::READ_EXCLUSIVE;
77 
82  public const READ_LOCKING = IDBAccessObject::READ_LOCKING;
83 
87  public const TOKEN_LENGTH = 32;
88 
92  public const INVALID_TOKEN = '*** INVALID ***';
93 
98  private const VERSION = 17;
99 
105  public const GETOPTIONS_EXCLUDE_DEFAULTS = UserOptionsLookup::EXCLUDE_DEFAULTS;
106 
110  public const CHECK_USER_RIGHTS = true;
111 
115  public const IGNORE_USER_RIGHTS = false;
116 
121  public const MAINTENANCE_SCRIPT_USER = 'Maintenance script';
122 
130  protected static $mCacheVars = [
131  // user table
132  'mId',
133  'mName',
134  'mRealName',
135  'mEmail',
136  'mTouched',
137  'mToken',
138  'mEmailAuthenticated',
139  'mEmailToken',
140  'mEmailTokenExpires',
141  'mRegistration',
142  // actor table
143  'mActorId',
144  ];
145 
147  // Some of these are public, including for use by the UserFactory, but they generally
148  // should not be set manually
149  // @{
151  public $mId;
153  public $mName;
159  public $mActorId;
161  public $mRealName;
162 
164  public $mEmail;
166  public $mTouched;
168  protected $mQuickTouched;
170  protected $mToken;
174  protected $mEmailToken;
178  protected $mRegistration;
179  // @}
180 
181  // @{
185  protected $mLoadedItems = [];
186  // @}
187 
198  public $mFrom;
199 
204  protected $mDatePreference;
211  public $mBlockedby;
213  protected $mHash;
219  protected $mBlockreason;
221  protected $mGlobalBlock;
223  protected $mLocked;
230  public $mHideName;
231 
233  private $mRequest;
234 
240  public $mBlock;
241 
247  protected $mAllowUsertalk;
248 
250  private $mBlockedFromCreateAccount = false;
251 
253  protected $queryFlagsUsed = self::READ_NORMAL;
254 
257 
273  public function __construct() {
274  $this->clearInstanceCache( 'defaults' );
275  }
276 
283  public function getWikiId() {
284  return self::LOCAL;
285  }
286 
290  public function __toString() {
291  return $this->getName();
292  }
293 
294  public function &__get( $name ) {
295  // A shortcut for $mRights deprecation phase
296  if ( $name === 'mRights' ) {
297  $copy = MediaWikiServices::getInstance()
298  ->getPermissionManager()
299  ->getUserPermissions( $this );
300  return $copy;
301  } elseif ( $name === 'mOptions' ) {
302  wfDeprecated( 'User::$mOptions', '1.35' );
303  $options = MediaWikiServices::getInstance()->getUserOptionsLookup()->getOptions( $this );
304  return $options;
305  } elseif ( !property_exists( $this, $name ) ) {
306  // T227688 - do not break $u->foo['bar'] = 1
307  wfLogWarning( 'tried to get non-existent property' );
308  $this->$name = null;
309  return $this->$name;
310  } else {
311  wfLogWarning( 'tried to get non-visible property' );
312  $null = null;
313  return $null;
314  }
315  }
316 
317  public function __set( $name, $value ) {
318  // A shortcut for $mRights deprecation phase, only known legitimate use was for
319  // testing purposes, other uses seem bad in principle
320  if ( $name === 'mRights' ) {
321  MediaWikiServices::getInstance()->getPermissionManager()->overrideUserRightsForTesting(
322  $this,
323  $value ?? []
324  );
325  } elseif ( $name === 'mOptions' ) {
326  wfDeprecated( 'User::$mOptions', '1.35' );
327  MediaWikiServices::getInstance()->getUserOptionsManager()->clearUserOptionsCache( $this );
328  foreach ( $value as $key => $val ) {
329  $this->setOption( $key, $val );
330  }
331  } elseif ( !property_exists( $this, $name ) ) {
332  $this->$name = $value;
333  } else {
334  wfLogWarning( 'tried to set non-visible property' );
335  }
336  }
337 
338  public function __sleep(): array {
339  return array_diff(
340  array_keys( get_object_vars( $this ) ),
341  [
342  'mThisAsAuthority' // memoization, will be recreated on demand.
343  ]
344  );
345  }
346 
361  public function isSafeToLoad() {
362  global $wgFullyInitialised;
363 
364  // The user is safe to load if:
365  // * MW_NO_SESSION is undefined AND $wgFullyInitialised is true (safe to use session data)
366  // * mLoadedItems === true (already loaded)
367  // * mFrom !== 'session' (sessions not involved at all)
368 
369  return ( !defined( 'MW_NO_SESSION' ) && $wgFullyInitialised ) ||
370  $this->mLoadedItems === true || $this->mFrom !== 'session';
371  }
372 
378  public function load( $flags = self::READ_NORMAL ) {
379  global $wgFullyInitialised;
380 
381  if ( $this->mLoadedItems === true ) {
382  return;
383  }
384 
385  // Set it now to avoid infinite recursion in accessors
386  $oldLoadedItems = $this->mLoadedItems;
387  $this->mLoadedItems = true;
388  $this->queryFlagsUsed = $flags;
389 
390  // If this is called too early, things are likely to break.
391  if ( !$wgFullyInitialised && $this->mFrom === 'session' ) {
392  LoggerFactory::getInstance( 'session' )
393  ->warning( 'User::loadFromSession called before the end of Setup.php', [
394  'exception' => new Exception( 'User::loadFromSession called before the end of Setup.php' ),
395  ] );
396  $this->loadDefaults();
397  $this->mLoadedItems = $oldLoadedItems;
398  return;
399  }
400 
401  switch ( $this->mFrom ) {
402  case 'defaults':
403  $this->loadDefaults();
404  break;
405  case 'id':
406  // Make sure this thread sees its own changes, if the ID isn't 0
407  if ( $this->mId != 0 ) {
408  $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
409  if ( $lb->hasOrMadeRecentPrimaryChanges() ) {
410  $flags |= self::READ_LATEST;
411  $this->queryFlagsUsed = $flags;
412  }
413  }
414 
415  $this->loadFromId( $flags );
416  break;
417  case 'actor':
418  case 'name':
419  // Make sure this thread sees its own changes
420  $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
421  if ( $lb->hasOrMadeRecentPrimaryChanges() ) {
422  $flags |= self::READ_LATEST;
423  $this->queryFlagsUsed = $flags;
424  }
425 
426  list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
427  $row = wfGetDB( $index )->selectRow(
428  'actor',
429  [ 'actor_id', 'actor_user', 'actor_name' ],
430  $this->mFrom === 'name'
431  // make sure to use normalized form of IP for anonymous users
432  ? [ 'actor_name' => IPUtils::sanitizeIP( $this->mName ) ]
433  : [ 'actor_id' => $this->mActorId ],
434  __METHOD__,
435  $options
436  );
437 
438  if ( !$row ) {
439  // Ugh.
440  $this->loadDefaults( $this->mFrom === 'name' ? $this->mName : false );
441  } elseif ( $row->actor_user ) {
442  $this->mId = $row->actor_user;
443  $this->loadFromId( $flags );
444  } else {
445  $this->loadDefaults( $row->actor_name, $row->actor_id );
446  }
447  break;
448  case 'session':
449  if ( !$this->loadFromSession() ) {
450  // Loading from session failed. Load defaults.
451  $this->loadDefaults();
452  }
453  $this->getHookRunner()->onUserLoadAfterLoadFromSession( $this );
454  break;
455  default:
456  throw new UnexpectedValueException(
457  "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
458  }
459  }
460 
466  public function loadFromId( $flags = self::READ_NORMAL ) {
467  if ( $this->mId == 0 ) {
468  // Anonymous users are not in the database (don't need cache)
469  $this->loadDefaults();
470  return false;
471  }
472 
473  // Try cache (unless this needs data from the primary DB).
474  // NOTE: if this thread called saveSettings(), the cache was cleared.
475  $latest = DBAccessObjectUtils::hasFlags( $flags, self::READ_LATEST );
476  if ( $latest ) {
477  if ( !$this->loadFromDatabase( $flags ) ) {
478  // Can't load from ID
479  return false;
480  }
481  } else {
482  $this->loadFromCache();
483  }
484 
485  $this->mLoadedItems = true;
486  $this->queryFlagsUsed = $flags;
487 
488  return true;
489  }
490 
496  public static function purge( $dbDomain, $userId ) {
497  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
498  $key = $cache->makeGlobalKey( 'user', 'id', $dbDomain, $userId );
499  $cache->delete( $key );
500  }
501 
507  protected function getCacheKey( WANObjectCache $cache ) {
508  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
509 
510  return $cache->makeGlobalKey( 'user', 'id', $lbFactory->getLocalDomainID(), $this->mId );
511  }
512 
519  $id = $this->getId();
520 
521  return $id ? [ $this->getCacheKey( $cache ) ] : [];
522  }
523 
530  protected function loadFromCache() {
531  global $wgFullyInitialised;
532 
533  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
534  $data = $cache->getWithSetCallback(
535  $this->getCacheKey( $cache ),
536  $cache::TTL_HOUR,
537  function ( $oldValue, &$ttl, array &$setOpts ) use ( $cache, $wgFullyInitialised ) {
538  $setOpts += Database::getCacheSetOptions( wfGetDB( DB_REPLICA ) );
539  wfDebug( "User: cache miss for user {$this->mId}" );
540 
541  $this->loadFromDatabase( self::READ_NORMAL );
542 
543  $data = [];
544  foreach ( self::$mCacheVars as $name ) {
545  $data[$name] = $this->$name;
546  }
547 
548  $ttl = $cache->adaptiveTTL( wfTimestamp( TS_UNIX, $this->mTouched ), $ttl );
549 
550  if ( $wgFullyInitialised ) {
551  $groupMemberships = MediaWikiServices::getInstance()
552  ->getUserGroupManager()
553  ->getUserGroupMemberships( $this, $this->queryFlagsUsed );
554 
555  // if a user group membership is about to expire, the cache needs to
556  // expire at that time (T163691)
557  foreach ( $groupMemberships as $ugm ) {
558  if ( $ugm->getExpiry() ) {
559  $secondsUntilExpiry =
560  wfTimestamp( TS_UNIX, $ugm->getExpiry() ) - time();
561 
562  if ( $secondsUntilExpiry > 0 && $secondsUntilExpiry < $ttl ) {
563  $ttl = $secondsUntilExpiry;
564  }
565  }
566  }
567  }
568 
569  return $data;
570  },
571  [ 'pcTTL' => $cache::TTL_PROC_LONG, 'version' => self::VERSION ]
572  );
573 
574  // Restore from cache
575  foreach ( self::$mCacheVars as $name ) {
576  $this->$name = $data[$name];
577  }
578 
579  return true;
580  }
581 
582  /***************************************************************************/
583  // region newFrom*() static factory methods
606  public static function newFromName( $name, $validate = 'valid' ) {
607  // Backwards compatibility with strings / false
608  $validationLevels = [
609  'valid' => UserFactory::RIGOR_VALID,
610  'usable' => UserFactory::RIGOR_USABLE,
611  'creatable' => UserFactory::RIGOR_CREATABLE
612  ];
613  if ( $validate === true ) {
614  $validate = 'valid';
615  }
616  if ( $validate === false ) {
617  $validation = UserFactory::RIGOR_NONE;
618  } elseif ( array_key_exists( $validate, $validationLevels ) ) {
619  $validation = $validationLevels[ $validate ];
620  } else {
621  // Not a recognized value, probably a test for unsupported validation
622  // levels, regardless, just pass it along
623  $validation = $validate;
624  }
625 
626  $user = MediaWikiServices::getInstance()
627  ->getUserFactory()
628  ->newFromName( (string)$name, $validation );
629 
630  // UserFactory returns null instead of false
631  if ( $user === null ) {
632  $user = false;
633  }
634  return $user;
635  }
636 
647  public static function newFromId( $id ) {
648  return MediaWikiServices::getInstance()
649  ->getUserFactory()
650  ->newFromId( (int)$id );
651  }
652 
664  public static function newFromActorId( $id ) {
665  return MediaWikiServices::getInstance()
666  ->getUserFactory()
667  ->newFromActorId( (int)$id );
668  }
669 
683  public static function newFromIdentity( UserIdentity $identity ) {
684  // Don't use the service if we already have a User object,
685  // so that User::newFromIdentity calls don't break things in unit tests.
686  if ( $identity instanceof User ) {
687  return $identity;
688  }
689 
690  return MediaWikiServices::getInstance()
691  ->getUserFactory()
692  ->newFromUserIdentity( $identity );
693  }
694 
712  public static function newFromAnyId( $userId, $userName, $actorId, $dbDomain = false ) {
713  return MediaWikiServices::getInstance()
714  ->getUserFactory()
715  ->newFromAnyId( $userId, $userName, $actorId, $dbDomain );
716  }
717 
733  public static function newFromConfirmationCode( $code, $flags = self::READ_NORMAL ) {
734  return MediaWikiServices::getInstance()
735  ->getUserFactory()
736  ->newFromConfirmationCode( (string)$code, $flags );
737  }
738 
746  public static function newFromSession( WebRequest $request = null ) {
747  $user = new User;
748  $user->mFrom = 'session';
749  $user->mRequest = $request;
750  return $user;
751  }
752 
768  public static function newFromRow( $row, $data = null ) {
769  $user = new User;
770  $user->loadFromRow( $row, $data );
771  return $user;
772  }
773 
809  public static function newSystemUser( $name, $options = [] ) {
810  $options += [
811  'validate' => UserNameUtils::RIGOR_VALID,
812  'create' => true,
813  'steal' => false,
814  ];
815 
816  // Username validation
817  // Backwards compatibility with strings / false
818  $validationLevels = [
819  'valid' => UserNameUtils::RIGOR_VALID,
820  'usable' => UserNameUtils::RIGOR_USABLE,
821  'creatable' => UserNameUtils::RIGOR_CREATABLE
822  ];
823  $validate = $options['validate'];
824 
825  // @phan-suppress-next-line PhanSuspiciousValueComparison
826  if ( $validate === false ) {
827  $validation = UserNameUtils::RIGOR_NONE;
828  } elseif ( array_key_exists( $validate, $validationLevels ) ) {
829  $validation = $validationLevels[ $validate ];
830  } else {
831  // Not a recognized value, probably a test for unsupported validation
832  // levels, regardless, just pass it along
833  $validation = $validate;
834  }
835 
836  if ( $validation !== UserNameUtils::RIGOR_VALID ) {
838  __METHOD__ . ' options["validation"] parameter must be omitted or set to "valid".',
839  '1.36'
840  );
841  }
842  $services = MediaWikiServices::getInstance();
843  $userNameUtils = $services->getUserNameUtils();
844 
845  $name = $userNameUtils->getCanonical( (string)$name, $validation );
846  if ( $name === false ) {
847  return null;
848  }
849 
850  $loadBalancer = $services->getDBLoadBalancer();
851  $dbr = $loadBalancer->getConnectionRef( DB_REPLICA );
852 
853  $userQuery = self::getQueryInfo();
854  $row = $dbr->selectRow(
855  $userQuery['tables'],
856  $userQuery['fields'],
857  [ 'user_name' => $name ],
858  __METHOD__,
859  [],
860  $userQuery['joins']
861  );
862  if ( !$row ) {
863  // Try the primary database...
864  $dbw = $loadBalancer->getConnectionRef( DB_PRIMARY );
865  $row = $dbw->selectRow(
866  $userQuery['tables'],
867  $userQuery['fields'],
868  [ 'user_name' => $name ],
869  __METHOD__,
870  [],
871  $userQuery['joins']
872  );
873  }
874 
875  if ( !$row ) {
876  // No user. Create it?
877  if ( !$options['create'] ) {
878  // No.
879  return null;
880  }
881 
882  // If it's a reserved user that had an anonymous actor created for it at
883  // some point, we need special handling.
884  return self::insertNewUser( static function ( UserIdentity $actor, IDatabase $dbw ) {
885  return MediaWikiServices::getInstance()->getActorStore()->acquireSystemActorId( $actor, $dbw );
886  }, $name, [ 'token' => self::INVALID_TOKEN ] );
887  }
888 
889  $user = self::newFromRow( $row );
890 
891  if ( !$user->isSystemUser() ) {
892  // User exists. Steal it?
893  if ( !$options['steal'] ) {
894  return null;
895  }
896 
897  $services->getAuthManager()->revokeAccessForUser( $name );
898 
899  $user->invalidateEmail();
900  $user->mToken = self::INVALID_TOKEN;
901  $user->saveSettings();
902  SessionManager::singleton()->preventSessionsForUser( $user->getName() );
903  }
904 
905  return $user;
906  }
907 
909  // endregion -- end of newFrom*() static factory methods
910 
916  public static function whoIs( $id ) {
917  return UserCache::singleton()->getProp( $id, 'name' );
918  }
919 
926  public static function whoIsReal( $id ) {
927  return UserCache::singleton()->getProp( $id, 'real_name' );
928  }
929 
937  public static function idFromName( $name, $flags = self::READ_NORMAL ) {
938  $actor = MediaWikiServices::getInstance()
939  ->getUserIdentityLookup()
940  ->getUserIdentityByName( (string)$name, $flags );
941  if ( $actor && $actor->getId() ) {
942  return $actor->getId();
943  }
944  return null;
945  }
946 
953  public static function resetIdByNameCache() {
954  // TODO: when removing this call, also remove the ActorStore::clearCaches() method!
955  wfDeprecated( __METHOD__, '1.37' );
956  MediaWikiServices::getInstance()->getActorStore()->clearCaches();
957  }
958 
978  public static function isIP( $name ) {
979  wfDeprecated( __METHOD__, '1.35' );
980  return preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/', $name )
981  || IPUtils::isIPv6( $name );
982  }
983 
993  public function isIPRange() {
994  wfDeprecated( __METHOD__, '1.35' );
995  return IPUtils::isValidRange( $this->mName );
996  }
997 
1012  public static function isValidUserName( $name ) {
1013  wfDeprecated( __METHOD__, '1.35' );
1014  return MediaWikiServices::getInstance()->getUserNameUtils()->isValid( $name );
1015  }
1016 
1031  public static function isUsableName( $name ) {
1032  wfDeprecated( __METHOD__, '1.35' );
1033  return MediaWikiServices::getInstance()->getUserNameUtils()->isUsable( $name );
1034  }
1035 
1046  public static function findUsersByGroup( $groups, $limit = 5000, $after = null ) {
1047  if ( $groups === [] ) {
1048  return UserArrayFromResult::newFromIDs( [] );
1049  }
1050 
1051  $groups = array_unique( (array)$groups );
1052  $limit = min( 5000, $limit );
1053 
1054  $conds = [ 'ug_group' => $groups ];
1055  if ( $after !== null ) {
1056  $conds[] = 'ug_user > ' . (int)$after;
1057  }
1058 
1059  $dbr = wfGetDB( DB_REPLICA );
1060  $ids = $dbr->selectFieldValues(
1061  'user_groups',
1062  'ug_user',
1063  $conds,
1064  __METHOD__,
1065  [
1066  'DISTINCT' => true,
1067  'ORDER BY' => 'ug_user',
1068  'LIMIT' => $limit,
1069  ]
1070  ) ?: [];
1071  return UserArray::newFromIDs( $ids );
1072  }
1073 
1089  public static function isCreatableName( $name ) {
1090  wfDeprecated( __METHOD__, '1.35' );
1091  return MediaWikiServices::getInstance()->getUserNameUtils()->isCreatable( $name );
1092  }
1093 
1100  public function isValidPassword( $password ) {
1101  // simple boolean wrapper for checkPasswordValidity
1102  return $this->checkPasswordValidity( $password )->isGood();
1103  }
1104 
1126  public function checkPasswordValidity( $password ) {
1127  global $wgPasswordPolicy;
1128 
1129  $upp = new UserPasswordPolicy(
1130  $wgPasswordPolicy['policies'],
1131  $wgPasswordPolicy['checks']
1132  );
1133 
1134  $status = Status::newGood( [] );
1135  $result = false; // init $result to false for the internal checks
1136 
1137  if ( !$this->getHookRunner()->onIsValidPassword( $password, $result, $this ) ) {
1138  $status->error( $result );
1139  return $status;
1140  }
1141 
1142  if ( $result === false ) {
1143  $status->merge( $upp->checkUserPassword( $this, $password ), true );
1144  return $status;
1145  }
1146 
1147  if ( $result === true ) {
1148  return $status;
1149  }
1150 
1151  $status->error( $result );
1152  return $status; // the isValidPassword hook set a string $result and returned true
1153  }
1154 
1172  public static function getCanonicalName( $name, $validate = 'valid' ) {
1173  wfDeprecated( __METHOD__, '1.35' );
1174  // Backwards compatibility with strings / false
1175  $validationLevels = [
1176  'valid' => UserNameUtils::RIGOR_VALID,
1177  'usable' => UserNameUtils::RIGOR_USABLE,
1178  'creatable' => UserNameUtils::RIGOR_CREATABLE
1179  ];
1180 
1181  if ( $validate === false ) {
1182  $validation = UserNameUtils::RIGOR_NONE;
1183  } elseif ( array_key_exists( $validate, $validationLevels ) ) {
1184  $validation = $validationLevels[ $validate ];
1185  } else {
1186  // Not a recognized value, probably a test for unsupported validation
1187  // levels, regardless, just pass it along
1188  $validation = $validate;
1189  }
1190 
1191  return MediaWikiServices::getInstance()
1192  ->getUserNameUtils()
1193  ->getCanonical( (string)$name, $validation );
1194  }
1195 
1205  public function loadDefaults( $name = false, $actorId = null ) {
1206  $this->mId = 0;
1207  $this->mName = $name;
1208  $this->mActorId = $actorId;
1209  $this->mRealName = '';
1210  $this->mEmail = '';
1211 
1212  $loggedOut = $this->mRequest && !defined( 'MW_NO_SESSION' )
1213  ? $this->mRequest->getSession()->getLoggedOutTimestamp() : 0;
1214  if ( $loggedOut !== 0 ) {
1215  $this->mTouched = wfTimestamp( TS_MW, $loggedOut );
1216  } else {
1217  $this->mTouched = '1'; # Allow any pages to be cached
1218  }
1219 
1220  $this->mToken = null; // Don't run cryptographic functions till we need a token
1221  $this->mEmailAuthenticated = null;
1222  $this->mEmailToken = '';
1223  $this->mEmailTokenExpires = null;
1224  $this->mRegistration = wfTimestamp( TS_MW );
1225 
1226  $this->getHookRunner()->onUserLoadDefaults( $this, $name );
1227  }
1228 
1241  public function isItemLoaded( $item, $all = 'all' ) {
1242  return ( $this->mLoadedItems === true && $all === 'all' ) ||
1243  ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] === true );
1244  }
1245 
1253  public function setItemLoaded( $item ) {
1254  if ( is_array( $this->mLoadedItems ) ) {
1255  $this->mLoadedItems[$item] = true;
1256  }
1257  }
1258 
1264  private function loadFromSession() {
1265  // MediaWiki\Session\Session already did the necessary authentication of the user
1266  // returned here, so just use it if applicable.
1267  $session = $this->getRequest()->getSession();
1268  $user = $session->getUser();
1269  if ( $user->isRegistered() ) {
1270  $this->loadFromUserObject( $user );
1271 
1272  // Other code expects these to be set in the session, so set them.
1273  $session->set( 'wsUserID', $this->getId() );
1274  $session->set( 'wsUserName', $this->getName() );
1275  $session->set( 'wsToken', $this->getToken() );
1276 
1277  return true;
1278  }
1279 
1280  return false;
1281  }
1282 
1290  public function loadFromDatabase( $flags = self::READ_LATEST ) {
1291  // Paranoia
1292  $this->mId = intval( $this->mId );
1293 
1294  if ( !$this->mId ) {
1295  // Anonymous users are not in the database
1296  $this->loadDefaults();
1297  return false;
1298  }
1299 
1300  list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
1301  $db = wfGetDB( $index );
1302 
1303  $userQuery = self::getQueryInfo();
1304  $s = $db->selectRow(
1305  $userQuery['tables'],
1306  $userQuery['fields'],
1307  [ 'user_id' => $this->mId ],
1308  __METHOD__,
1309  $options,
1310  $userQuery['joins']
1311  );
1312 
1313  $this->queryFlagsUsed = $flags;
1314 
1315  // hook is hard deprecated since 1.37
1316  $this->getHookRunner()->onUserLoadFromDatabase( $this, $s );
1317 
1318  if ( $s !== false ) {
1319  // Initialise user table data
1320  $this->loadFromRow( $s );
1321  return true;
1322  }
1323 
1324  // Invalid user_id
1325  $this->mId = 0;
1326  $this->loadDefaults( 'Unknown user' );
1327 
1328  return false;
1329  }
1330 
1342  protected function loadFromRow( $row, $data = null ) {
1343  if ( !is_object( $row ) ) {
1344  throw new InvalidArgumentException( '$row must be an object' );
1345  }
1346 
1347  $all = true;
1348 
1349  if ( isset( $row->actor_id ) ) {
1350  $this->mActorId = (int)$row->actor_id;
1351  if ( $this->mActorId !== 0 ) {
1352  $this->mFrom = 'actor';
1353  }
1354  $this->setItemLoaded( 'actor' );
1355  } else {
1356  $all = false;
1357  }
1358 
1359  if ( isset( $row->user_name ) && $row->user_name !== '' ) {
1360  $this->mName = $row->user_name;
1361  $this->mFrom = 'name';
1362  $this->setItemLoaded( 'name' );
1363  } else {
1364  $all = false;
1365  }
1366 
1367  if ( isset( $row->user_real_name ) ) {
1368  $this->mRealName = $row->user_real_name;
1369  $this->setItemLoaded( 'realname' );
1370  } else {
1371  $all = false;
1372  }
1373 
1374  if ( isset( $row->user_id ) ) {
1375  $this->mId = intval( $row->user_id );
1376  if ( $this->mId !== 0 ) {
1377  $this->mFrom = 'id';
1378  }
1379  $this->setItemLoaded( 'id' );
1380  } else {
1381  $all = false;
1382  }
1383 
1384  if ( isset( $row->user_editcount ) ) {
1385  // Sanity check - don't try to set edit count for anonymous users
1386  // We check the id here and not in UserEditTracker because calling
1387  // User::getId() can trigger some other loading. This will result in
1388  // discarding the user_editcount field for rows if the id wasn't set.
1389  if ( $this->mId !== null && $this->mId !== 0 ) {
1390  MediaWikiServices::getInstance()
1391  ->getUserEditTracker()
1392  ->setCachedUserEditCount( $this, (int)$row->user_editcount );
1393  }
1394  } else {
1395  $all = false;
1396  }
1397 
1398  if ( isset( $row->user_touched ) ) {
1399  $this->mTouched = wfTimestamp( TS_MW, $row->user_touched );
1400  } else {
1401  $all = false;
1402  }
1403 
1404  if ( isset( $row->user_token ) ) {
1405  // The definition for the column is binary(32), so trim the NULs
1406  // that appends. The previous definition was char(32), so trim
1407  // spaces too.
1408  $this->mToken = rtrim( $row->user_token, " \0" );
1409  if ( $this->mToken === '' ) {
1410  $this->mToken = null;
1411  }
1412  } else {
1413  $all = false;
1414  }
1415 
1416  if ( isset( $row->user_email ) ) {
1417  $this->mEmail = $row->user_email;
1418  $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
1419  $this->mEmailToken = $row->user_email_token;
1420  $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
1421  $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
1422  } else {
1423  $all = false;
1424  }
1425 
1426  if ( $all ) {
1427  $this->mLoadedItems = true;
1428  }
1429 
1430  if ( is_array( $data ) ) {
1431 
1432  if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) {
1433  MediaWikiServices::getInstance()
1434  ->getUserGroupManager()
1435  ->loadGroupMembershipsFromArray(
1436  $this,
1437  $data['user_groups'],
1438  $this->queryFlagsUsed
1439  );
1440  }
1441  }
1442  }
1443 
1449  protected function loadFromUserObject( $user ) {
1450  $user->load();
1451  foreach ( self::$mCacheVars as $var ) {
1452  $this->$var = $user->$var;
1453  }
1454  }
1455 
1472  public function addAutopromoteOnceGroups( $event ) {
1473  wfDeprecated( __METHOD__, '1.35' );
1474  return MediaWikiServices::getInstance()
1475  ->getUserGroupManager()
1476  ->addUserToAutopromoteOnceGroups( $this, $event );
1477  }
1478 
1488  protected function makeUpdateConditions( IDatabase $db, array $conditions ) {
1489  if ( $this->mTouched ) {
1490  // CAS check: only update if the row wasn't changed sicne it was loaded.
1491  $conditions['user_touched'] = $db->timestamp( $this->mTouched );
1492  }
1493 
1494  return $conditions;
1495  }
1496 
1507  public function checkAndSetTouched() {
1508  $this->load();
1509 
1510  if ( !$this->mId ) {
1511  return false; // anon
1512  }
1513 
1514  // Get a new user_touched that is higher than the old one
1515  $newTouched = $this->newTouchedTimestamp();
1516 
1517  $dbw = wfGetDB( DB_PRIMARY );
1518  $dbw->update( 'user',
1519  [ 'user_touched' => $dbw->timestamp( $newTouched ) ],
1520  $this->makeUpdateConditions( $dbw, [
1521  'user_id' => $this->mId,
1522  ] ),
1523  __METHOD__
1524  );
1525  $success = ( $dbw->affectedRows() > 0 );
1526 
1527  if ( $success ) {
1528  $this->mTouched = $newTouched;
1529  $this->clearSharedCache( 'changed' );
1530  } else {
1531  // Clears on failure too since that is desired if the cache is stale
1532  $this->clearSharedCache( 'refresh' );
1533  }
1534 
1535  return $success;
1536  }
1537 
1545  public function clearInstanceCache( $reloadFrom = false ) {
1546  global $wgFullyInitialised;
1547 
1548  $this->mDatePreference = null;
1549  $this->mBlockedby = -1; # Unset
1550  $this->mHash = false;
1551  $this->mThisAsAuthority = null;
1552 
1553  if ( $wgFullyInitialised && $this->mFrom ) {
1554  $services = MediaWikiServices::getInstance();
1555  $services->getPermissionManager()->invalidateUsersRightsCache( $this );
1556  $services->getUserOptionsManager()->clearUserOptionsCache( $this );
1557  $services->getTalkPageNotificationManager()->clearInstanceCache( $this );
1558  $services->getUserGroupManager()->clearCache( $this );
1559  $services->getUserEditTracker()->clearUserEditCache( $this );
1560  }
1561 
1562  if ( $reloadFrom ) {
1563  $this->mLoadedItems = [];
1564  $this->mFrom = $reloadFrom;
1565  }
1566  }
1567 
1575  public static function getDefaultOptions() {
1576  wfDeprecated( __METHOD__, '1.35' );
1577  return MediaWikiServices::getInstance()
1578  ->getUserOptionsLookup()
1579  ->getDefaultOptions();
1580  }
1581 
1589  public static function getDefaultOption( $opt ) {
1590  wfDeprecated( __METHOD__, '1.35' );
1591  return MediaWikiServices::getInstance()
1592  ->getUserOptionsLookup()
1593  ->getDefaultOption( $opt );
1594  }
1595 
1607  private function getBlockedStatus( $fromReplica = true, $disableIpBlockExemptChecking = false ) {
1608  if ( $this->mBlockedby != -1 ) {
1609  return;
1610  }
1611 
1612  wfDebug( __METHOD__ . ": checking blocked status for " . $this->getName() );
1613 
1614  // Initialize data...
1615  // Otherwise something ends up stomping on $this->mBlockedby when
1616  // things get lazy-loaded later, causing false positive block hits
1617  // due to -1 !== 0. Probably session-related... Nothing should be
1618  // overwriting mBlockedby, surely?
1619  $this->load();
1620 
1621  // TODO: Block checking shouldn't really be done from the User object. Block
1622  // checking can involve checking for IP blocks, cookie blocks, and/or XFF blocks,
1623  // which need more knowledge of the request context than the User should have.
1624  // Since we do currently check blocks from the User, we have to do the following
1625  // here:
1626  // - Check if this is the user associated with the main request
1627  // - If so, pass the relevant request information to the block manager
1628  $request = null;
1629  if ( $this->isGlobalSessionUser() ) {
1630  // This is the global user, so we need to pass the request
1631  $request = $this->getRequest();
1632  }
1633 
1634  $block = MediaWikiServices::getInstance()->getBlockManager()->getUserBlock(
1635  $this,
1636  $request,
1637  $fromReplica,
1638  $disableIpBlockExemptChecking
1639  );
1640 
1641  if ( $block ) {
1642  $this->mBlock = $block;
1643  $this->mBlockedby = $block->getByName();
1644  $this->mBlockreason = $block->getReason();
1645  $this->mHideName = $block->getHideName();
1646  $this->mAllowUsertalk = $block->isUsertalkEditAllowed();
1647  } else {
1648  $this->mBlock = null;
1649  $this->mBlockedby = '';
1650  $this->mBlockreason = '';
1651  $this->mHideName = 0;
1652  $this->mAllowUsertalk = false;
1653  }
1654  }
1655 
1661  public function isPingLimitable() {
1662  global $wgRateLimitsExcludedIPs;
1663  if ( IPUtils::isInRanges( $this->getRequest()->getIP(), $wgRateLimitsExcludedIPs ) ) {
1664  // No other good way currently to disable rate limits
1665  // for specific IPs. :P
1666  // But this is a crappy hack and should die.
1667  return false;
1668  }
1669  return !$this->isAllowed( 'noratelimit' );
1670  }
1671 
1688  public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
1689  $logger = LoggerFactory::getInstance( 'ratelimit' );
1690 
1691  // Call the 'PingLimiter' hook
1692  $result = false;
1693  if ( !$this->getHookRunner()->onPingLimiter( $this, $action, $result, $incrBy ) ) {
1694  return $result;
1695  }
1696 
1697  global $wgRateLimits;
1698  if ( !isset( $wgRateLimits[$action] ) ) {
1699  return false;
1700  }
1701 
1702  $limits = array_merge(
1703  [ '&can-bypass' => true ],
1704  $wgRateLimits[$action]
1705  );
1706 
1707  // Some groups shouldn't trigger the ping limiter, ever
1708  if ( $limits['&can-bypass'] && !$this->isPingLimitable() ) {
1709  return false;
1710  }
1711 
1712  $logger->debug( __METHOD__ . ": limiting $action rate for {$this->getName()}" );
1713 
1714  $keys = [];
1715  $id = $this->getId();
1716  $isNewbie = $this->isNewbie();
1718 
1719  if ( $id == 0 ) {
1720  // "shared anon" limit, for all anons combined
1721  if ( isset( $limits['anon'] ) ) {
1722  $keys[$cache->makeKey( 'limiter', $action, 'anon' )] = $limits['anon'];
1723  }
1724  } else {
1725  // "global per name" limit, across sites
1726  if ( isset( $limits['user-global'] ) ) {
1727  $lookup = MediaWikiServices::getInstance()
1728  ->getCentralIdLookupFactory()
1729  ->getNonLocalLookup();
1730 
1731  $centralId = $lookup
1732  ? $lookup->centralIdFromLocalUser( $this, CentralIdLookup::AUDIENCE_RAW )
1733  : 0;
1734 
1735  if ( $centralId ) {
1736  // We don't have proper realms, use provider ID.
1737  $realm = $lookup->getProviderId();
1738 
1739  $globalKey = $cache->makeGlobalKey( 'limiter', $action, 'user-global',
1740  $realm, $centralId );
1741  } else {
1742  // Fall back to a local key for a local ID
1743  $globalKey = $cache->makeKey( 'limiter', $action, 'user-global',
1744  'local', $id );
1745  }
1746  $keys[$globalKey] = $limits['user-global'];
1747  }
1748  }
1749 
1750  if ( $isNewbie ) {
1751  // "per ip" limit for anons and newbie users
1752  if ( isset( $limits['ip'] ) ) {
1753  $ip = $this->getRequest()->getIP();
1754  $keys[$cache->makeGlobalKey( 'limiter', $action, 'ip', $ip )] = $limits['ip'];
1755  }
1756  // "per subnet" limit for anons and newbie users
1757  if ( isset( $limits['subnet'] ) ) {
1758  $ip = $this->getRequest()->getIP();
1759  $subnet = IPUtils::getSubnet( $ip );
1760  if ( $subnet !== false ) {
1761  $keys[$cache->makeGlobalKey( 'limiter', $action, 'subnet', $subnet )] = $limits['subnet'];
1762  }
1763  }
1764  }
1765 
1766  // determine the "per user account" limit
1767  $userLimit = false;
1768  if ( $id !== 0 && isset( $limits['user'] ) ) {
1769  // default limit for logged-in users
1770  $userLimit = $limits['user'];
1771  }
1772  // limits for newbie logged-in users (overrides all the normal user limits)
1773  if ( $id !== 0 && $isNewbie && isset( $limits['newbie'] ) ) {
1774  $userLimit = $limits['newbie'];
1775  } else {
1776  // Check for group-specific limits
1777  // If more than one group applies, use the highest allowance (if higher than the default)
1778  $userGroups = MediaWikiServices::getInstance()->getUserGroupManager()->getUserGroups( $this );
1779  foreach ( $userGroups as $group ) {
1780  if ( isset( $limits[$group] ) ) {
1781  if ( $userLimit === false
1782  || $limits[$group][0] / $limits[$group][1] > $userLimit[0] / $userLimit[1]
1783  ) {
1784  $userLimit = $limits[$group];
1785  }
1786  }
1787  }
1788  }
1789 
1790  // Set the user limit key
1791  if ( $userLimit !== false ) {
1792  // phan is confused because &can-bypass's value is a bool, so it assumes
1793  // that $userLimit is also a bool here.
1794  // @phan-suppress-next-line PhanTypeInvalidExpressionArrayDestructuring
1795  list( $max, $period ) = $userLimit;
1796  $logger->debug( __METHOD__ . ": effective user limit: $max in {$period}s" );
1797  $keys[$cache->makeKey( 'limiter', $action, 'user', $id )] = $userLimit;
1798  }
1799 
1800  // ip-based limits for all ping-limitable users
1801  if ( isset( $limits['ip-all'] ) ) {
1802  $ip = $this->getRequest()->getIP();
1803  // ignore if user limit is more permissive
1804  if ( $isNewbie || $userLimit === false
1805  || $limits['ip-all'][0] / $limits['ip-all'][1] > $userLimit[0] / $userLimit[1] ) {
1806  $keys[$cache->makeGlobalKey( 'limiter', $action, 'ip-all', $ip )] = $limits['ip-all'];
1807  }
1808  }
1809 
1810  // subnet-based limits for all ping-limitable users
1811  if ( isset( $limits['subnet-all'] ) ) {
1812  $ip = $this->getRequest()->getIP();
1813  $subnet = IPUtils::getSubnet( $ip );
1814  if ( $subnet !== false ) {
1815  // ignore if user limit is more permissive
1816  if ( $isNewbie || $userLimit === false
1817  || $limits['ip-all'][0] / $limits['ip-all'][1]
1818  > $userLimit[0] / $userLimit[1] ) {
1819  $keys[$cache->makeGlobalKey( 'limiter', $action, 'subnet-all', $subnet )] = $limits['subnet-all'];
1820  }
1821  }
1822  }
1823 
1824  // XXX: We may want to use $cache->getCurrentTime() here, but that would make it
1825  // harder to test for T246991. Also $cache->getCurrentTime() is documented
1826  // as being for testing only, so it apparently should not be called here.
1827  $now = MWTimestamp::time();
1828  $clockFudge = 3; // avoid log spam when a clock is slightly off
1829 
1830  $triggered = false;
1831  foreach ( $keys as $key => $limit ) {
1832 
1833  // Do the update in a merge callback, for atomicity.
1834  // To use merge(), we need to explicitly track the desired expiry timestamp.
1835  // This tracking was introduced to investigate T246991. Once it is no longer needed,
1836  // we could go back to incrWithInit(), though that has more potential for race
1837  // conditions between the get() and incrWithInit() calls.
1838  $cache->merge(
1839  $key,
1840  function ( $cache, $key, $data, &$expiry )
1841  use ( $action, $logger, &$triggered, $now, $clockFudge, $limit, $incrBy )
1842  {
1843  // phan is confused because &can-bypass's value is a bool, so it assumes
1844  // that $userLimit is also a bool here.
1845  // @phan-suppress-next-line PhanTypeInvalidExpressionArrayDestructuring
1846  list( $max, $period ) = $limit;
1847 
1848  $expiry = $now + (int)$period;
1849  $count = 0;
1850 
1851  // Already pinged?
1852  if ( $data ) {
1853  // NOTE: in order to investigate T246991, we write the expiry time
1854  // into the payload, along with the count.
1855  $fields = explode( '|', $data );
1856  $storedCount = (int)( $fields[0] ?? 0 );
1857  $storedExpiry = (int)( $fields[1] ?? PHP_INT_MAX );
1858 
1859  // Found a stale entry. This should not happen!
1860  if ( $storedExpiry < ( $now + $clockFudge ) ) {
1861  $logger->info(
1862  'User::pingLimiter: '
1863  . 'Stale rate limit entry, cache key failed to expire (T246991)',
1864  [
1865  'action' => $action,
1866  'user' => $this->getName(),
1867  'limit' => $max,
1868  'period' => $period,
1869  'count' => $storedCount,
1870  'key' => $key,
1871  'expiry' => MWTimestamp::convert( TS_DB, $storedExpiry ),
1872  ]
1873  );
1874  } else {
1875  // NOTE: We'll keep the original expiry when bumping counters,
1876  // resulting in a kind of fixed-window throttle.
1877  $expiry = min( $storedExpiry, $now + (int)$period );
1878  $count = $storedCount;
1879  }
1880  }
1881 
1882  // Limit exceeded!
1883  if ( $count >= $max ) {
1884  if ( !$triggered ) {
1885  $logger->info(
1886  'User::pingLimiter: User tripped rate limit',
1887  [
1888  'action' => $action,
1889  'user' => $this->getName(),
1890  'ip' => $this->getRequest()->getIP(),
1891  'limit' => $max,
1892  'period' => $period,
1893  'count' => $count,
1894  'key' => $key
1895  ]
1896  );
1897  }
1898 
1899  $triggered = true;
1900  }
1901 
1902  $count += $incrBy;
1903  $data = "$count|$expiry";
1904  return $data;
1905  }
1906  );
1907  }
1908 
1909  return $triggered;
1910  }
1911 
1924  public function isBlocked( $fromReplica = true ) {
1925  return $this->getBlock( $fromReplica ) !== null;
1926  }
1927 
1940  public function getBlock(
1941  $freshness = self::READ_NORMAL,
1942  $disableIpBlockExemptChecking = false
1943  ): ?Block {
1944  if ( is_bool( $freshness ) ) {
1945  $fromReplica = $freshness;
1946  } else {
1947  $fromReplica = ( $freshness !== self::READ_LATEST );
1948  }
1949 
1950  $this->getBlockedStatus( $fromReplica, $disableIpBlockExemptChecking );
1951  return $this->mBlock instanceof AbstractBlock ? $this->mBlock : null;
1952  }
1953 
1965  public function isBlockedFrom( $title, $fromReplica = false ) {
1966  // TODO: remove the cast when PermissionManager accepts PageIdentity
1968  return MediaWikiServices::getInstance()->getPermissionManager()
1969  ->isBlockedFrom( $this, $title, $fromReplica );
1970  }
1971 
1978  public function blockedBy() {
1979  wfDeprecated( __METHOD__, '1.38' );
1980  $this->getBlockedStatus();
1981  return $this->mBlockedby;
1982  }
1983 
1990  public function blockedFor() {
1991  $this->getBlockedStatus();
1992  return $this->mBlockreason;
1993  }
1994 
2001  public function getBlockId() {
2002  wfDeprecated( __METHOD__, '1.38' );
2003  $this->getBlockedStatus();
2004  return ( $this->mBlock ? $this->mBlock->getId() : false );
2005  }
2006 
2015  public function isBlockedGlobally( $ip = '' ) {
2016  return $this->getGlobalBlock( $ip ) instanceof AbstractBlock;
2017  }
2018 
2029  public function getGlobalBlock( $ip = '' ) {
2030  if ( $this->mGlobalBlock !== null ) {
2031  return $this->mGlobalBlock ?: null;
2032  }
2033  // User is already an IP?
2034  if ( IPUtils::isIPAddress( $this->getName() ) ) {
2035  $ip = $this->getName();
2036  } elseif ( !$ip ) {
2037  $ip = $this->getRequest()->getIP();
2038  }
2039  $blocked = false;
2040  $block = null;
2041  $this->getHookRunner()->onUserIsBlockedGlobally( $this, $ip, $blocked, $block );
2042 
2043  if ( $blocked && $block === null ) {
2044  // back-compat: UserIsBlockedGlobally didn't have $block param first
2045  $block = new SystemBlock( [
2046  'address' => $ip,
2047  'systemBlock' => 'global-block'
2048  ] );
2049  }
2050 
2051  $this->mGlobalBlock = $blocked ? $block : false;
2052  return $this->mGlobalBlock ?: null;
2053  }
2054 
2060  public function isLocked() {
2061  if ( $this->mLocked !== null ) {
2062  return $this->mLocked;
2063  }
2064  // Reset for hook
2065  $this->mLocked = false;
2066  $this->getHookRunner()->onUserIsLocked( $this, $this->mLocked );
2067  return $this->mLocked;
2068  }
2069 
2075  public function isHidden() {
2076  if ( $this->mHideName !== null ) {
2077  return (bool)$this->mHideName;
2078  }
2079  $this->getBlockedStatus();
2080  return (bool)$this->mHideName;
2081  }
2082 
2088  public function getId( $wikiId = self::LOCAL ): int {
2089  $this->deprecateInvalidCrossWiki( $wikiId, '1.36' );
2090  if ( $this->mId === null && $this->mName !== null ) {
2091  $userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils();
2092  if ( $userNameUtils->isIP( $this->mName ) || ExternalUserNames::isExternal( $this->mName ) ) {
2093  // Special case, we know the user is anonymous
2094  // Note that "external" users are "local" (they have an actor ID that is relative to
2095  // the local wiki).
2096  return 0;
2097  }
2098  }
2099 
2100  if ( !$this->isItemLoaded( 'id' ) ) {
2101  // Don't load if this was initialized from an ID
2102  $this->load();
2103  }
2104 
2105  return (int)$this->mId;
2106  }
2107 
2112  public function setId( $v ) {
2113  $this->mId = $v;
2114  $this->clearInstanceCache( 'id' );
2115  }
2116 
2121  public function getName(): string {
2122  if ( $this->isItemLoaded( 'name', 'only' ) ) {
2123  // Special case optimisation
2124  return $this->mName;
2125  }
2126 
2127  $this->load();
2128  if ( $this->mName === false ) {
2129  // Clean up IPs
2130  $this->mName = IPUtils::sanitizeIP( $this->getRequest()->getIP() );
2131  }
2132 
2133  return $this->mName;
2134  }
2135 
2149  public function setName( $str ) {
2150  $this->load();
2151  $this->mName = $str;
2152  }
2153 
2167  public function getActorId( $dbwOrWikiId = self::LOCAL ): int {
2168  if ( $dbwOrWikiId ) {
2169  wfDeprecatedMsg( 'Passing a parameter to getActorId() is deprecated', '1.36' );
2170  }
2171 
2172  if ( is_string( $dbwOrWikiId ) ) {
2173  $this->assertWiki( $dbwOrWikiId );
2174  }
2175 
2176  if ( !$this->isItemLoaded( 'actor' ) ) {
2177  $this->load();
2178  }
2179 
2180  if ( !$this->mActorId && $dbwOrWikiId instanceof IDatabase ) {
2181  MediaWikiServices::getInstance()
2182  ->getActorStoreFactory()
2183  ->getActorNormalization( $dbwOrWikiId->getDomainID() )
2184  ->acquireActorId( $this, $dbwOrWikiId );
2185  // acquireActorId will call setActorId on $this
2186  Assert::postcondition(
2187  $this->mActorId !== null,
2188  "Failed to acquire actor ID for user id {$this->mId} name {$this->mName}"
2189  );
2190  }
2191 
2192  return (int)$this->mActorId;
2193  }
2194 
2204  public function setActorId( int $actorId ) {
2205  $this->mActorId = $actorId;
2206  $this->setItemLoaded( 'actor' );
2207  }
2208 
2213  public function getTitleKey() {
2214  return str_replace( ' ', '_', $this->getName() );
2215  }
2216 
2223  private function newTouchedTimestamp() {
2224  $time = time();
2225  if ( $this->mTouched ) {
2226  $time = max( $time, wfTimestamp( TS_UNIX, $this->mTouched ) + 1 );
2227  }
2228 
2229  return wfTimestamp( TS_MW, $time );
2230  }
2231 
2242  public function clearSharedCache( $mode = 'refresh' ) {
2243  if ( !$this->getId() ) {
2244  return;
2245  }
2246 
2247  $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
2248  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
2249  $key = $this->getCacheKey( $cache );
2250 
2251  if ( $mode === 'refresh' ) {
2252  $cache->delete( $key, 1 ); // low tombstone/"hold-off" TTL
2253  } else {
2254  $lb->getConnectionRef( DB_PRIMARY )->onTransactionPreCommitOrIdle(
2255  static function () use ( $cache, $key ) {
2256  $cache->delete( $key );
2257  },
2258  __METHOD__
2259  );
2260  }
2261  }
2262 
2268  public function invalidateCache() {
2269  $this->touch();
2270  $this->clearSharedCache( 'changed' );
2271  }
2272 
2285  public function touch() {
2286  $id = $this->getId();
2287  if ( $id ) {
2288  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
2289  $key = $cache->makeKey( 'user-quicktouched', 'id', $id );
2290  $cache->touchCheckKey( $key );
2291  $this->mQuickTouched = null;
2292  }
2293  }
2294 
2300  public function validateCache( $timestamp ) {
2301  return ( $timestamp >= $this->getTouched() );
2302  }
2303 
2312  public function getTouched() {
2313  $this->load();
2314 
2315  if ( $this->mId ) {
2316  if ( $this->mQuickTouched === null ) {
2317  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
2318  $key = $cache->makeKey( 'user-quicktouched', 'id', $this->mId );
2319 
2320  $this->mQuickTouched = wfTimestamp( TS_MW, $cache->getCheckKeyTime( $key ) );
2321  }
2322 
2323  return max( $this->mTouched, $this->mQuickTouched );
2324  }
2325 
2326  return $this->mTouched;
2327  }
2328 
2334  public function getDBTouched() {
2335  $this->load();
2336 
2337  return $this->mTouched;
2338  }
2339 
2352  public function changeAuthenticationData( array $data ) {
2353  $manager = MediaWikiServices::getInstance()->getAuthManager();
2354  $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
2355  $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
2356 
2357  $status = Status::newGood( 'ignored' );
2358  foreach ( $reqs as $req ) {
2359  $status->merge( $manager->allowsAuthenticationDataChange( $req ), true );
2360  }
2361  if ( $status->getValue() === 'ignored' ) {
2362  $status->warning( 'authenticationdatachange-ignored' );
2363  }
2364 
2365  if ( $status->isGood() ) {
2366  foreach ( $reqs as $req ) {
2367  $manager->changeAuthenticationData( $req );
2368  }
2369  }
2370  return $status;
2371  }
2372 
2379  public function getToken( $forceCreation = true ) {
2381 
2382  $this->load();
2383  if ( !$this->mToken && $forceCreation ) {
2384  $this->setToken();
2385  }
2386 
2387  if ( !$this->mToken ) {
2388  // The user doesn't have a token, return null to indicate that.
2389  return null;
2390  }
2391 
2392  if ( $this->mToken === self::INVALID_TOKEN ) {
2393  // We return a random value here so existing token checks are very
2394  // likely to fail.
2395  return MWCryptRand::generateHex( self::TOKEN_LENGTH );
2396  }
2397 
2398  if ( $wgAuthenticationTokenVersion === null ) {
2399  // $wgAuthenticationTokenVersion not in use, so return the raw secret
2400  return $this->mToken;
2401  }
2402 
2403  // $wgAuthenticationTokenVersion in use, so hmac it.
2404  $ret = MWCryptHash::hmac( $wgAuthenticationTokenVersion, $this->mToken, false );
2405 
2406  // The raw hash can be overly long. Shorten it up.
2407  $len = max( 32, self::TOKEN_LENGTH );
2408  if ( strlen( $ret ) < $len ) {
2409  // Should never happen, even md5 is 128 bits
2410  throw new \UnexpectedValueException( 'Hmac returned less than 128 bits' );
2411  }
2412 
2413  return substr( $ret, -$len );
2414  }
2415 
2422  public function setToken( $token = false ) {
2423  $this->load();
2424  if ( $this->mToken === self::INVALID_TOKEN ) {
2425  LoggerFactory::getInstance( 'session' )
2426  ->debug( __METHOD__ . ": Ignoring attempt to set token for system user \"$this\"" );
2427  } elseif ( !$token ) {
2428  $this->mToken = MWCryptRand::generateHex( self::TOKEN_LENGTH );
2429  } else {
2430  $this->mToken = $token;
2431  }
2432  }
2433 
2438  public function getEmail(): string {
2439  $this->load();
2440  $email = $this->mEmail;
2441  $this->getHookRunner()->onUserGetEmail( $this, $email );
2442  // In case a hook handler returns e.g. null
2443  $this->mEmail = is_string( $email ) ? $email : '';
2444  return $this->mEmail;
2445  }
2446 
2452  $this->load();
2453  $this->getHookRunner()->onUserGetEmailAuthenticationTimestamp(
2454  $this, $this->mEmailAuthenticated );
2456  }
2457 
2462  public function setEmail( string $str ) {
2463  $this->load();
2464  if ( $str == $this->getEmail() ) {
2465  return;
2466  }
2467  $this->invalidateEmail();
2468  $this->mEmail = $str;
2469  $this->getHookRunner()->onUserSetEmail( $this, $this->mEmail );
2470  }
2471 
2479  public function setEmailWithConfirmation( string $str ) {
2481 
2482  if ( !$wgEnableEmail ) {
2483  return Status::newFatal( 'emaildisabled' );
2484  }
2485 
2486  $oldaddr = $this->getEmail();
2487  if ( $str === $oldaddr ) {
2488  return Status::newGood( true );
2489  }
2490 
2491  $type = $oldaddr != '' ? 'changed' : 'set';
2492  $notificationResult = null;
2493 
2494  if ( $wgEmailAuthentication && $type === 'changed' ) {
2495  // Send the user an email notifying the user of the change in registered
2496  // email address on their previous email address
2497  $change = $str != '' ? 'changed' : 'removed';
2498  $notificationResult = $this->sendMail(
2499  wfMessage( 'notificationemail_subject_' . $change )->text(),
2500  wfMessage( 'notificationemail_body_' . $change,
2501  $this->getRequest()->getIP(),
2502  $this->getName(),
2503  $str )->text()
2504  );
2505  }
2506 
2507  $this->setEmail( $str );
2508 
2509  if ( $str !== '' && $wgEmailAuthentication ) {
2510  // Send a confirmation request to the new address if needed
2511  $result = $this->sendConfirmationMail( $type );
2512 
2513  if ( $notificationResult !== null ) {
2514  $result->merge( $notificationResult );
2515  }
2516 
2517  if ( $result->isGood() ) {
2518  // Say to the caller that a confirmation and notification mail has been sent
2519  $result->value = 'eauth';
2520  }
2521  } else {
2522  $result = Status::newGood( true );
2523  }
2524 
2525  return $result;
2526  }
2527 
2532  public function getRealName(): string {
2533  if ( !$this->isItemLoaded( 'realname' ) ) {
2534  $this->load();
2535  }
2536 
2537  return $this->mRealName;
2538  }
2539 
2544  public function setRealName( string $str ) {
2545  $this->load();
2546  $this->mRealName = $str;
2547  }
2548 
2561  public function getOption( $oname, $defaultOverride = null, $ignoreHidden = false ) {
2562  if ( $oname === null ) {
2563  return null; // b/c
2564  }
2565  return MediaWikiServices::getInstance()
2566  ->getUserOptionsLookup()
2567  ->getOption( $this, $oname, $defaultOverride, $ignoreHidden );
2568  }
2569 
2580  public function getOptions( $flags = 0 ) {
2581  wfDeprecated( __METHOD__, '1.35' );
2582  return MediaWikiServices::getInstance()
2583  ->getUserOptionsLookup()
2584  ->getOptions( $this, $flags );
2585  }
2586 
2596  public function getBoolOption( $oname ) {
2597  wfDeprecated( __METHOD__, '1.35' );
2598  return MediaWikiServices::getInstance()
2599  ->getUserOptionsLookup()
2600  ->getBoolOption( $this, $oname );
2601  }
2602 
2613  public function getIntOption( $oname, $defaultOverride = 0 ) {
2614  wfDeprecated( __METHOD__, '1.35' );
2615  if ( $oname === null ) {
2616  return null; // b/c
2617  }
2618  return MediaWikiServices::getInstance()
2619  ->getUserOptionsLookup()
2620  ->getIntOption( $this, $oname, $defaultOverride );
2621  }
2622 
2633  public function setOption( $oname, $val ) {
2634  wfDeprecated( __METHOD__, '1.35' );
2635  MediaWikiServices::getInstance()
2636  ->getUserOptionsManager()
2637  ->setOption( $this, $oname, $val );
2638  }
2639 
2650  public function getTokenFromOption( $oname ) {
2651  global $wgHiddenPrefs;
2652 
2653  $id = $this->getId();
2654  if ( !$id || in_array( $oname, $wgHiddenPrefs ) ) {
2655  return false;
2656  }
2657 
2658  $token = $this->getOption( $oname );
2659  if ( !$token ) {
2660  // Default to a value based on the user token to avoid space
2661  // wasted on storing tokens for all users. When this option
2662  // is set manually by the user, only then is it stored.
2663  $token = hash_hmac( 'sha1', "$oname:$id", $this->getToken() );
2664  }
2665 
2666  return $token;
2667  }
2668 
2678  public function resetTokenFromOption( $oname ) {
2679  global $wgHiddenPrefs;
2680  if ( in_array( $oname, $wgHiddenPrefs ) ) {
2681  return false;
2682  }
2683 
2684  $token = MWCryptRand::generateHex( 40 );
2685  MediaWikiServices::getInstance()
2686  ->getUserOptionsManager()
2687  ->setOption( $this, $oname, $token );
2688  return $token;
2689  }
2690 
2716  public static function listOptionKinds() {
2717  wfDeprecated( __METHOD__, '1.35' );
2718  return MediaWikiServices::getInstance()
2719  ->getUserOptionsManager()
2720  ->listOptionKinds();
2721  }
2722 
2738  public function getOptionKinds( IContextSource $context, $options = null ) {
2739  wfDeprecated( __METHOD__, '1.35' );
2740  return MediaWikiServices::getInstance()
2741  ->getUserOptionsManager()
2742  ->getOptionKinds( $this, $context, $options );
2743  }
2744 
2761  public function resetOptions(
2762  $resetKinds = [ 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused' ],
2763  IContextSource $context = null
2764  ) {
2765  wfDeprecated( __METHOD__, '1.35' );
2766  MediaWikiServices::getInstance()
2767  ->getUserOptionsManager()
2768  ->resetOptions(
2769  $this,
2770  $context ?? RequestContext::getMain(),
2771  $resetKinds
2772  );
2773  }
2774 
2779  public function getDatePreference() {
2780  // Important migration for old data rows
2781  if ( $this->mDatePreference === null ) {
2782  global $wgLang;
2783  $value = $this->getOption( 'date' );
2784  $map = $wgLang->getDatePreferenceMigrationMap();
2785  if ( isset( $map[$value] ) ) {
2786  $value = $map[$value];
2787  }
2788  $this->mDatePreference = $value;
2789  }
2790  return $this->mDatePreference;
2791  }
2792 
2799  public function requiresHTTPS() {
2800  global $wgForceHTTPS, $wgSecureLogin;
2801  if ( $wgForceHTTPS ) {
2802  return true;
2803  }
2804  if ( !$wgSecureLogin ) {
2805  return false;
2806  }
2807  return MediaWikiServices::getInstance()
2808  ->getUserOptionsLookup()
2809  ->getBoolOption( $this, 'prefershttps' );
2810  }
2811 
2820  public function getStubThreshold() {
2821  wfDeprecated( __METHOD__, '1.37' );
2822  return 0;
2823  }
2824 
2834  public function getRights() {
2835  wfDeprecated( __METHOD__, '1.34' );
2836  return MediaWikiServices::getInstance()->getPermissionManager()->getUserPermissions( $this );
2837  }
2838 
2847  public function getGroups() {
2848  return MediaWikiServices::getInstance()
2849  ->getUserGroupManager()
2850  ->getUserGroups( $this, $this->queryFlagsUsed );
2851  }
2852 
2862  public function getGroupMemberships() {
2863  return MediaWikiServices::getInstance()
2864  ->getUserGroupManager()
2865  ->getUserGroupMemberships( $this, $this->queryFlagsUsed );
2866  }
2867 
2879  public function getEffectiveGroups( $recache = false ) {
2880  wfDeprecated( __METHOD__, '1.35' );
2881  return MediaWikiServices::getInstance()
2882  ->getUserGroupManager()
2883  ->getUserEffectiveGroups( $this, $this->queryFlagsUsed, $recache );
2884  }
2885 
2897  public function getAutomaticGroups( $recache = false ) {
2898  wfDeprecated( __METHOD__, '1.35' );
2899  return MediaWikiServices::getInstance()
2900  ->getUserGroupManager()
2901  ->getUserImplicitGroups( $this, $this->queryFlagsUsed, $recache );
2902  }
2903 
2916  public function getFormerGroups() {
2917  wfDeprecated( __METHOD__, '1.35' );
2918  return MediaWikiServices::getInstance()
2919  ->getUserGroupManager()
2920  ->getUserFormerGroups( $this, $this->queryFlagsUsed );
2921  }
2922 
2927  public function getEditCount() {
2928  return MediaWikiServices::getInstance()
2929  ->getUserEditTracker()
2930  ->getUserEditCount( $this );
2931  }
2932 
2946  public function addGroup( $group, $expiry = null ) {
2947  return MediaWikiServices::getInstance()
2948  ->getUserGroupManager()
2949  ->addUserToGroup( $this, $group, $expiry, true );
2950  }
2951 
2961  public function removeGroup( $group ) {
2962  return MediaWikiServices::getInstance()
2963  ->getUserGroupManager()
2964  ->removeUserFromGroup( $this, $group );
2965  }
2966 
2975  public function isRegistered(): bool {
2976  return $this->getId() != 0;
2977  }
2978 
2985  public function isLoggedIn() {
2986  // Hard-deprecated in 1.37
2987  wfDeprecated( __METHOD__, '1.36' );
2988  return $this->isRegistered();
2989  }
2990 
2995  public function isAnon() {
2996  return !$this->isRegistered();
2997  }
2998 
3003  public function isBot() {
3004  $userGroupManager = MediaWikiServices::getInstance()->getUserGroupManager();
3005  if ( in_array( 'bot', $userGroupManager->getUserGroups( $this ) ) && $this->isAllowed( 'bot' ) ) {
3006  return true;
3007  }
3008 
3009  $isBot = false;
3010  $this->getHookRunner()->onUserIsBot( $this, $isBot );
3011 
3012  return $isBot;
3013  }
3014 
3024  public function isSystemUser() {
3025  $this->load();
3026  if ( $this->getEmail() || $this->mToken !== self::INVALID_TOKEN ||
3027  MediaWikiServices::getInstance()->getAuthManager()->userCanAuthenticate( $this->mName )
3028  ) {
3029  return false;
3030  }
3031  return true;
3032  }
3033 
3034  public function isAllowedAny( ...$permissions ): bool {
3035  return $this->getThisAsAuthority()->isAllowedAny( ...$permissions );
3036  }
3037 
3038  public function isAllowedAll( ...$permissions ): bool {
3039  return $this->getThisAsAuthority()->isAllowedAll( ...$permissions );
3040  }
3041 
3042  public function isAllowed( string $permission ): bool {
3043  return $this->getThisAsAuthority()->isAllowed( $permission );
3044  }
3045 
3050  public function useRCPatrol() {
3051  global $wgUseRCPatrol;
3052  return $wgUseRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
3053  }
3054 
3059  public function useNPPatrol() {
3061  return (
3063  && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
3064  );
3065  }
3066 
3071  public function useFilePatrol() {
3073  return (
3075  && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
3076  );
3077  }
3078 
3084  public function getRequest() {
3085  if ( $this->mRequest ) {
3086  return $this->mRequest;
3087  }
3088  return RequestContext::getMain()->getRequest();
3089  }
3090 
3096  public function getExperienceLevel() {
3097  global $wgLearnerEdits,
3101 
3102  if ( $this->isAnon() ) {
3103  return false;
3104  }
3105 
3106  $editCount = $this->getEditCount();
3107  $registration = $this->getRegistration();
3108  $now = time();
3109  $learnerRegistration = wfTimestamp( TS_MW, $now - $wgLearnerMemberSince * 86400 );
3110  $experiencedRegistration = wfTimestamp( TS_MW, $now - $wgExperiencedUserMemberSince * 86400 );
3111  if ( $registration === null ) {
3112  // for some very old accounts, this information is missing in the database
3113  // treat them as old enough to be 'experienced'
3114  $registration = $experiencedRegistration;
3115  }
3116 
3117  if ( $editCount < $wgLearnerEdits ||
3118  $registration > $learnerRegistration ) {
3119  return 'newcomer';
3120  }
3121 
3122  if ( $editCount > $wgExperiencedUserEdits &&
3123  $registration <= $experiencedRegistration
3124  ) {
3125  return 'experienced';
3126  }
3127 
3128  return 'learner';
3129  }
3130 
3139  public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
3140  $this->load();
3141  if ( $this->mId == 0 ) {
3142  return;
3143  }
3144 
3145  $session = $this->getRequest()->getSession();
3146  if ( $request && $session->getRequest() !== $request ) {
3147  $session = $session->sessionWithRequest( $request );
3148  }
3149  $delay = $session->delaySave();
3150 
3151  if ( !$session->getUser()->equals( $this ) ) {
3152  if ( !$session->canSetUser() ) {
3153  LoggerFactory::getInstance( 'session' )
3154  ->warning( __METHOD__ .
3155  ": Cannot save user \"$this\" to a user \"{$session->getUser()}\"'s immutable session"
3156  );
3157  return;
3158  }
3159  $session->setUser( $this );
3160  }
3161 
3162  $session->setRememberUser( $rememberMe );
3163  if ( $secure !== null ) {
3164  $session->setForceHTTPS( $secure );
3165  }
3166 
3167  $session->persist();
3168 
3169  ScopedCallback::consume( $delay );
3170  }
3171 
3175  public function logout() {
3176  // Avoid PHP 7.1 warning of passing $this by reference
3177  $user = $this;
3178  if ( $this->getHookRunner()->onUserLogout( $user ) ) {
3179  $this->doLogout();
3180  }
3181  }
3182 
3187  public function doLogout() {
3188  $session = $this->getRequest()->getSession();
3189  if ( !$session->canSetUser() ) {
3190  LoggerFactory::getInstance( 'session' )
3191  ->warning( __METHOD__ . ": Cannot log out of an immutable session" );
3192  $error = 'immutable';
3193  } elseif ( !$session->getUser()->equals( $this ) ) {
3194  LoggerFactory::getInstance( 'session' )
3195  ->warning( __METHOD__ .
3196  ": Cannot log user \"$this\" out of a user \"{$session->getUser()}\"'s session"
3197  );
3198  // But we still may as well make this user object anon
3199  $this->clearInstanceCache( 'defaults' );
3200  $error = 'wronguser';
3201  } else {
3202  $this->clearInstanceCache( 'defaults' );
3203  $delay = $session->delaySave();
3204  $session->unpersist(); // Clear cookies (T127436)
3205  $session->setLoggedOutTimestamp( time() );
3206  $session->setUser( new User );
3207  $session->set( 'wsUserID', 0 ); // Other code expects this
3208  $session->resetAllTokens();
3209  ScopedCallback::consume( $delay );
3210  $error = false;
3211  }
3212  LoggerFactory::getInstance( 'authevents' )->info( 'Logout', [
3213  'event' => 'logout',
3214  'successful' => $error === false,
3215  'status' => $error ?: 'success',
3216  ] );
3217  }
3218 
3223  public function saveSettings() {
3224  if ( wfReadOnly() ) {
3225  // @TODO: caller should deal with this instead!
3226  // This should really just be an exception.
3228  null,
3229  "Could not update user with ID '{$this->mId}'; DB is read-only."
3230  ) );
3231  return;
3232  }
3233 
3234  $this->load();
3235  if ( $this->mId == 0 ) {
3236  return; // anon
3237  }
3238 
3239  // Get a new user_touched that is higher than the old one.
3240  // This will be used for a CAS check as a last-resort safety
3241  // check against race conditions and replica DB lag.
3242  $newTouched = $this->newTouchedTimestamp();
3243 
3244  $dbw = wfGetDB( DB_PRIMARY );
3245  $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $newTouched ) {
3246  $dbw->update( 'user',
3247  [ /* SET */
3248  'user_name' => $this->mName,
3249  'user_real_name' => $this->mRealName,
3250  'user_email' => $this->mEmail,
3251  'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3252  'user_touched' => $dbw->timestamp( $newTouched ),
3253  'user_token' => strval( $this->mToken ),
3254  'user_email_token' => $this->mEmailToken,
3255  'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
3256  ], $this->makeUpdateConditions( $dbw, [ /* WHERE */
3257  'user_id' => $this->mId,
3258  ] ), $fname
3259  );
3260 
3261  if ( !$dbw->affectedRows() ) {
3262  // Maybe the problem was a missed cache update; clear it to be safe
3263  $this->clearSharedCache( 'refresh' );
3264  // User was changed in the meantime or loaded with stale data
3265  $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ? 'primary' : 'replica';
3266  LoggerFactory::getInstance( 'preferences' )->warning(
3267  "CAS update failed on user_touched for user ID '{user_id}' ({db_flag} read)",
3268  [ 'user_id' => $this->mId, 'db_flag' => $from ]
3269  );
3270  throw new MWException( "CAS update failed on user_touched. " .
3271  "The version of the user to be saved is older than the current version."
3272  );
3273  }
3274 
3275  $dbw->update(
3276  'actor',
3277  [ 'actor_name' => $this->mName ],
3278  [ 'actor_user' => $this->mId ],
3279  $fname
3280  );
3281  MediaWikiServices::getInstance()->getActorStore()->deleteUserIdentityFromCache( $this );
3282  } );
3283 
3284  $this->mTouched = $newTouched;
3285  MediaWikiServices::getInstance()->getUserOptionsManager()->saveOptions( $this );
3286 
3287  $this->getHookRunner()->onUserSaveSettings( $this );
3288  $this->clearSharedCache( 'changed' );
3289  $hcu = MediaWikiServices::getInstance()->getHtmlCacheUpdater();
3290  $hcu->purgeTitleUrls( $this->getUserPage(), $hcu::PURGE_INTENT_TXROUND_REFLECTED );
3291  }
3292 
3299  public function idForName( $flags = self::READ_NORMAL ) {
3300  $s = trim( $this->getName() );
3301  if ( $s === '' ) {
3302  return 0;
3303  }
3304 
3305  list( $index, $options ) = DBAccessObjectUtils::getDBOptions( $flags );
3306  $db = wfGetDB( $index );
3307 
3308  $id = $db->selectField( 'user',
3309  'user_id', [ 'user_name' => $s ], __METHOD__, $options );
3310 
3311  return (int)$id;
3312  }
3313 
3328  public static function createNew( $name, $params = [] ) {
3329  return self::insertNewUser( static function ( UserIdentity $actor, IDatabase $dbw ) {
3330  return MediaWikiServices::getInstance()->getActorStore()->createNewActor( $actor, $dbw );
3331  }, $name, $params );
3332  }
3333 
3341  private static function insertNewUser( callable $insertActor, $name, $params = [] ) {
3342  foreach ( [ 'password', 'newpassword', 'newpass_time', 'password_expires' ] as $field ) {
3343  if ( isset( $params[$field] ) ) {
3344  wfDeprecated( __METHOD__ . " with param '$field'", '1.27' );
3345  unset( $params[$field] );
3346  }
3347  }
3348 
3349  $user = new User;
3350  $user->load();
3351  $user->setToken(); // init token
3352  if ( isset( $params['options'] ) ) {
3353  MediaWikiServices::getInstance()
3354  ->getUserOptionsManager()
3355  ->loadUserOptions( $user, $user->queryFlagsUsed, $params['options'] );
3356  unset( $params['options'] );
3357  }
3358  $dbw = wfGetDB( DB_PRIMARY );
3359 
3360  $noPass = PasswordFactory::newInvalidPassword()->toString();
3361 
3362  $fields = [
3363  'user_name' => $name,
3364  'user_password' => $noPass,
3365  'user_newpassword' => $noPass,
3366  'user_email' => $user->mEmail,
3367  'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
3368  'user_real_name' => $user->mRealName,
3369  'user_token' => strval( $user->mToken ),
3370  'user_registration' => $dbw->timestamp( $user->mRegistration ),
3371  'user_editcount' => 0,
3372  'user_touched' => $dbw->timestamp( $user->newTouchedTimestamp() ),
3373  ];
3374  foreach ( $params as $name => $value ) {
3375  $fields["user_$name"] = $value;
3376  }
3377 
3378  return $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $fields, $insertActor ) {
3379  $dbw->insert( 'user', $fields, $fname, [ 'IGNORE' ] );
3380  if ( $dbw->affectedRows() ) {
3381  $newUser = self::newFromId( $dbw->insertId() );
3382  $newUser->mName = $fields['user_name'];
3383  // Don't pass $this, since calling ::getId, ::getName might force ::load
3384  // and this user might not be ready for the yet.
3385  $newUser->mActorId = $insertActor( new UserIdentityValue( $newUser->mId, $newUser->mName ), $dbw );
3386  // Load the user from primary DB to avoid replica lag
3387  $newUser->load( self::READ_LATEST );
3388  } else {
3389  $newUser = null;
3390  }
3391  return $newUser;
3392  } );
3393  }
3394 
3421  public function addToDatabase() {
3422  $this->load();
3423  if ( !$this->mToken ) {
3424  $this->setToken(); // init token
3425  }
3426 
3427  if ( !is_string( $this->mName ) ) {
3428  throw new RuntimeException( "User name field is not set." );
3429  }
3430 
3431  $this->mTouched = $this->newTouchedTimestamp();
3432 
3433  $dbw = wfGetDB( DB_PRIMARY );
3434  $status = $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) {
3435  $noPass = PasswordFactory::newInvalidPassword()->toString();
3436  $dbw->insert( 'user',
3437  [
3438  'user_name' => $this->mName,
3439  'user_password' => $noPass,
3440  'user_newpassword' => $noPass,
3441  'user_email' => $this->mEmail,
3442  'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3443  'user_real_name' => $this->mRealName,
3444  'user_token' => strval( $this->mToken ),
3445  'user_registration' => $dbw->timestamp( $this->mRegistration ),
3446  'user_editcount' => 0,
3447  'user_touched' => $dbw->timestamp( $this->mTouched ),
3448  ], $fname,
3449  [ 'IGNORE' ]
3450  );
3451  if ( !$dbw->affectedRows() ) {
3452  // Use locking reads to bypass any REPEATABLE-READ snapshot.
3453  $this->mId = $dbw->selectField(
3454  'user',
3455  'user_id',
3456  [ 'user_name' => $this->mName ],
3457  $fname,
3458  [ 'LOCK IN SHARE MODE' ]
3459  );
3460  $loaded = false;
3461  if ( $this->mId && $this->loadFromDatabase( IDBAccessObject::READ_LOCKING ) ) {
3462  $loaded = true;
3463  }
3464  if ( !$loaded ) {
3465  throw new MWException( $fname . ": hit a key conflict attempting " .
3466  "to insert user '{$this->mName}' row, but it was not present in select!" );
3467  }
3468  return Status::newFatal( 'userexists' );
3469  }
3470  $this->mId = $dbw->insertId();
3471 
3472  // Don't pass $this, since calling ::getId, ::getName might force ::load
3473  // and this user might not be ready for the yet.
3474  $this->mActorId = MediaWikiServices::getInstance()
3475  ->getActorNormalization()
3476  ->acquireActorId( new UserIdentityValue( $this->mId, $this->mName ), $dbw );
3477  return Status::newGood();
3478  } );
3479  if ( !$status->isGood() ) {
3480  return $status;
3481  }
3482 
3483  // Clear instance cache other than user table data and actor, which is already accurate
3484  $this->clearInstanceCache();
3485 
3486  MediaWikiServices::getInstance()->getUserOptionsManager()->saveOptions( $this );
3487  return Status::newGood();
3488  }
3489 
3495  public function spreadAnyEditBlock() {
3496  if ( $this->isRegistered() && $this->getBlock() ) {
3497  return $this->spreadBlock();
3498  }
3499 
3500  return false;
3501  }
3502 
3508  protected function spreadBlock() {
3509  wfDebug( __METHOD__ . "()" );
3510  $this->load();
3511  if ( $this->mId == 0 ) {
3512  return false;
3513  }
3514 
3515  $userblock = DatabaseBlock::newFromTarget( $this->getName() );
3516  if ( !$userblock ) {
3517  return false;
3518  }
3519 
3520  return (bool)$userblock->doAutoblock( $this->getRequest()->getIP() );
3521  }
3522 
3528  public function isBlockedFromCreateAccount() {
3529  $this->getBlockedStatus();
3530  if ( $this->mBlock && $this->mBlock->appliesToRight( 'createaccount' ) ) {
3531  return $this->mBlock;
3532  }
3533 
3534  # T15611: if the IP address the user is trying to create an account from is
3535  # blocked with createaccount disabled, prevent new account creation there even
3536  # when the user is logged in
3537  if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
3538  $this->mBlockedFromCreateAccount = DatabaseBlock::newFromTarget(
3539  null, $this->getRequest()->getIP()
3540  );
3541  }
3542  return $this->mBlockedFromCreateAccount instanceof AbstractBlock
3543  && $this->mBlockedFromCreateAccount->appliesToRight( 'createaccount' )
3544  ? $this->mBlockedFromCreateAccount
3545  : false;
3546  }
3547 
3552  public function isBlockedFromEmailuser() {
3553  $this->getBlockedStatus();
3554  return $this->mBlock && $this->mBlock->appliesToRight( 'sendemail' );
3555  }
3556 
3563  public function isBlockedFromUpload() {
3564  $this->getBlockedStatus();
3565  return $this->mBlock && $this->mBlock->appliesToRight( 'upload' );
3566  }
3567 
3572  public function isAllowedToCreateAccount() {
3573  return $this->isAllowed( 'createaccount' ) && !$this->isBlockedFromCreateAccount();
3574  }
3575 
3581  public function getUserPage() {
3582  return Title::makeTitle( NS_USER, $this->getName() );
3583  }
3584 
3590  public function getTalkPage() {
3591  $title = $this->getUserPage();
3592  return $title->getTalkPage();
3593  }
3594 
3600  public function isNewbie() {
3601  return !$this->isAllowed( 'autoconfirmed' );
3602  }
3603 
3616  public function getEditTokenObject( $salt = '', $request = null ) {
3617  if ( $this->isAnon() ) {
3618  return new LoggedOutEditToken();
3619  }
3620 
3621  if ( !$request ) {
3622  $request = $this->getRequest();
3623  }
3624  return $request->getSession()->getToken( $salt );
3625  }
3626 
3641  public function getEditToken( $salt = '', $request = null ) {
3642  return $this->getEditTokenObject( $salt, $request )->toString();
3643  }
3644 
3658  public function matchEditToken( $val, $salt = '', $request = null, $maxage = null ) {
3659  return $this->getEditTokenObject( $salt, $request )->match( $val, $maxage );
3660  }
3661 
3673  public function matchEditTokenNoSuffix( $val, $salt = '', $request = null, $maxage = null ) {
3674  wfDeprecated( __METHOD__, '1.37' );
3675  $val = substr( $val, 0, strspn( $val, '0123456789abcdef' ) ) . Token::SUFFIX;
3676  return $this->matchEditToken( $val, $salt, $request, $maxage );
3677  }
3678 
3686  public function sendConfirmationMail( $type = 'created' ) {
3687  global $wgLang;
3688  $expiration = null; // gets passed-by-ref and defined in next line.
3689  $token = $this->confirmationToken( $expiration );
3690  $url = $this->confirmationTokenUrl( $token );
3691  $invalidateURL = $this->invalidationTokenUrl( $token );
3692  $this->saveSettings();
3693 
3694  if ( $type == 'created' || $type === false ) {
3695  $message = 'confirmemail_body';
3696  $type = 'created';
3697  } elseif ( $type === true ) {
3698  $message = 'confirmemail_body_changed';
3699  $type = 'changed';
3700  } else {
3701  // Messages: confirmemail_body_changed, confirmemail_body_set
3702  $message = 'confirmemail_body_' . $type;
3703  }
3704 
3705  $mail = [
3706  'subject' => wfMessage( 'confirmemail_subject' )->text(),
3707  'body' => wfMessage( $message,
3708  $this->getRequest()->getIP(),
3709  $this->getName(),
3710  $url,
3711  $wgLang->userTimeAndDate( $expiration, $this ),
3712  $invalidateURL,
3713  $wgLang->userDate( $expiration, $this ),
3714  $wgLang->userTime( $expiration, $this ) )->text(),
3715  'from' => null,
3716  'replyTo' => null,
3717  ];
3718  $info = [
3719  'type' => $type,
3720  'ip' => $this->getRequest()->getIP(),
3721  'confirmURL' => $url,
3722  'invalidateURL' => $invalidateURL,
3723  'expiration' => $expiration
3724  ];
3725 
3726  $this->getHookRunner()->onUserSendConfirmationMail( $this, $mail, $info );
3727  return $this->sendMail( $mail['subject'], $mail['body'], $mail['from'], $mail['replyTo'] );
3728  }
3729 
3741  public function sendMail( $subject, $body, $from = null, $replyto = null ) {
3742  global $wgPasswordSender;
3743 
3744  if ( $from instanceof User ) {
3745  $sender = MailAddress::newFromUser( $from );
3746  } else {
3747  $sender = new MailAddress( $wgPasswordSender,
3748  wfMessage( 'emailsender' )->inContentLanguage()->text() );
3749  }
3750  $to = MailAddress::newFromUser( $this );
3751 
3752  return UserMailer::send( $to, $sender, $subject, $body, [
3753  'replyTo' => $replyto,
3754  ] );
3755  }
3756 
3767  protected function confirmationToken( &$expiration ) {
3769  $now = time();
3770  $expires = $now + $wgUserEmailConfirmationTokenExpiry;
3771  $expiration = wfTimestamp( TS_MW, $expires );
3772  $this->load();
3773  $token = MWCryptRand::generateHex( 32 );
3774  $hash = md5( $token );
3775  $this->mEmailToken = $hash;
3776  $this->mEmailTokenExpires = $expiration;
3777  return $token;
3778  }
3779 
3785  protected function confirmationTokenUrl( $token ) {
3786  return $this->getTokenUrl( 'ConfirmEmail', $token );
3787  }
3788 
3794  protected function invalidationTokenUrl( $token ) {
3795  return $this->getTokenUrl( 'InvalidateEmail', $token );
3796  }
3797 
3812  protected function getTokenUrl( $page, $token ) {
3813  // Hack to bypass localization of 'Special:'
3814  $title = Title::makeTitle( NS_MAIN, "Special:$page/$token" );
3815  return $title->getCanonicalURL();
3816  }
3817 
3825  public function confirmEmail() {
3826  // Check if it's already confirmed, so we don't touch the database
3827  // and fire the ConfirmEmailComplete hook on redundant confirmations.
3828  if ( !$this->isEmailConfirmed() ) {
3830  $this->getHookRunner()->onConfirmEmailComplete( $this );
3831  }
3832  return true;
3833  }
3834 
3842  public function invalidateEmail() {
3843  $this->load();
3844  $this->mEmailToken = null;
3845  $this->mEmailTokenExpires = null;
3846  $this->setEmailAuthenticationTimestamp( null );
3847  $this->mEmail = '';
3848  $this->getHookRunner()->onInvalidateEmailComplete( $this );
3849  return true;
3850  }
3851 
3856  public function setEmailAuthenticationTimestamp( $timestamp ) {
3857  $this->load();
3858  $this->mEmailAuthenticated = $timestamp;
3859  $this->getHookRunner()->onUserSetEmailAuthenticationTimestamp(
3860  $this, $this->mEmailAuthenticated );
3861  }
3862 
3868  public function canSendEmail() {
3870  if ( !$wgEnableEmail || !$wgEnableUserEmail || !$this->isAllowed( 'sendemail' ) ) {
3871  return false;
3872  }
3873  $hookErr = $this->isEmailConfirmed();
3874  $this->getHookRunner()->onUserCanSendEmail( $this, $hookErr );
3875  return $hookErr;
3876  }
3877 
3883  public function canReceiveEmail() {
3884  return $this->isEmailConfirmed() && !$this->getOption( 'disablemail' );
3885  }
3886 
3897  public function isEmailConfirmed(): bool {
3898  global $wgEmailAuthentication;
3899  $this->load();
3900  // Avoid PHP 7.1 warning of passing $this by reference
3901  $user = $this;
3902  $confirmed = true;
3903  if ( $this->getHookRunner()->onEmailConfirmed( $user, $confirmed ) ) {
3904  if ( $this->isAnon() ) {
3905  return false;
3906  }
3907  if ( !Sanitizer::validateEmail( $this->getEmail() ) ) {
3908  return false;
3909  }
3910  if ( $wgEmailAuthentication && !$this->getEmailAuthenticationTimestamp() ) {
3911  return false;
3912  }
3913  return true;
3914  }
3915 
3916  return $confirmed;
3917  }
3918 
3923  public function isEmailConfirmationPending() {
3924  global $wgEmailAuthentication;
3925  return $wgEmailAuthentication &&
3926  !$this->isEmailConfirmed() &&
3927  $this->mEmailToken &&
3928  $this->mEmailTokenExpires > wfTimestamp();
3929  }
3930 
3938  public function getRegistration() {
3939  if ( $this->isAnon() ) {
3940  return false;
3941  }
3942  $this->load();
3943  return $this->mRegistration;
3944  }
3945 
3954  public function getFirstEditTimestamp() {
3955  wfDeprecated( __METHOD__, '1.36' );
3956  return MediaWikiServices::getInstance()
3957  ->getUserEditTracker()
3958  ->getFirstEditTimestamp( $this );
3959  }
3960 
3970  public function getLatestEditTimestamp() {
3971  wfDeprecated( __METHOD__, '1.36' );
3972  return MediaWikiServices::getInstance()
3973  ->getUserEditTracker()
3974  ->getLatestEditTimestamp( $this );
3975  }
3976 
3986  public static function getGroupPermissions( $groups ) {
3987  return MediaWikiServices::getInstance()->getGroupPermissionsLookup()->getGroupPermissions( $groups );
3988  }
3989 
3999  public static function getGroupsWithPermission( $role ) {
4000  return MediaWikiServices::getInstance()->getGroupPermissionsLookup()->getGroupsWithPermission( $role );
4001  }
4002 
4018  public static function groupHasPermission( $group, $role ) {
4019  return MediaWikiServices::getInstance()->getGroupPermissionsLookup()
4020  ->groupHasPermission( $group, $role );
4021  }
4022 
4030  public static function getAllGroups() {
4031  return MediaWikiServices::getInstance()
4032  ->getUserGroupManager()
4033  ->listAllGroups();
4034  }
4035 
4040  public static function getImplicitGroups() {
4041  return MediaWikiServices::getInstance()
4042  ->getUserGroupManager()
4043  ->listAllImplicitGroups();
4044  }
4045 
4056  public static function changeableByGroup( $group ) {
4057  wfDeprecated( __METHOD__, '1.37' );
4058  return MediaWikiServices::getInstance()
4059  ->getUserGroupManager()
4060  ->getGroupsChangeableByGroup( $group );
4061  }
4062 
4071  public function changeableGroups() {
4072  wfDeprecated( __METHOD__, '1.37' );
4073  return MediaWikiServices::getInstance()
4074  ->getUserGroupManager()
4075  ->getGroupsChangeableBy( $this );
4076  }
4077 
4082  public function incEditCount() {
4083  MediaWikiServices::getInstance()->getUserEditTracker()->incrementUserEditCount( $this );
4084  }
4085 
4093  public static function getRightDescription( $right ) {
4094  $key = "right-$right";
4095  $msg = wfMessage( $key );
4096  return $msg->isDisabled() ? $right : $msg->text();
4097  }
4098 
4108  public static function getQueryInfo() {
4109  $ret = [
4110  'tables' => [ 'user', 'user_actor' => 'actor' ],
4111  'fields' => [
4112  'user_id',
4113  'user_name',
4114  'user_real_name',
4115  'user_email',
4116  'user_touched',
4117  'user_token',
4118  'user_email_authenticated',
4119  'user_email_token',
4120  'user_email_token_expires',
4121  'user_registration',
4122  'user_editcount',
4123  'user_actor.actor_id',
4124  ],
4125  'joins' => [
4126  'user_actor' => [ 'JOIN', 'user_actor.actor_user = user_id' ],
4127  ],
4128  ];
4129 
4130  return $ret;
4131  }
4132 
4140  public static function newFatalPermissionDeniedStatus( $permission ) {
4141  global $wgLang;
4142 
4143  $groups = [];
4144  foreach ( MediaWikiServices::getInstance()
4145  ->getGroupPermissionsLookup()
4146  ->getGroupsWithPermission( $permission ) as $group ) {
4147  $groups[] = UserGroupMembership::getLink( $group, RequestContext::getMain(), 'wiki' );
4148  }
4149 
4150  if ( $groups ) {
4151  return Status::newFatal( 'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
4152  }
4153 
4154  return Status::newFatal( 'badaccess-group0' );
4155  }
4156 
4166  public function getInstanceForUpdate() {
4167  if ( !$this->getId() ) {
4168  return null; // anon
4169  }
4170 
4171  $user = self::newFromId( $this->getId() );
4172  if ( !$user->loadFromId( IDBAccessObject::READ_EXCLUSIVE ) ) {
4173  return null;
4174  }
4175 
4176  return $user;
4177  }
4178 
4186  public function equals( ?UserIdentity $user ): bool {
4187  if ( !$user ) {
4188  return false;
4189  }
4190  // XXX it's not clear whether central ID providers are supposed to obey this
4191  return $this->getName() === $user->getName();
4192  }
4193 
4201  public function isAllowUsertalk() {
4202  wfDeprecated( __METHOD__, '1.37' );
4203  return $this->mAllowUsertalk;
4204  }
4205 
4211  public function getUser(): UserIdentity {
4212  return $this;
4213  }
4214 
4222  public function probablyCan( string $action, PageIdentity $target, PermissionStatus $status = null ): bool {
4223  return $this->getThisAsAuthority()->probablyCan( $action, $target, $status );
4224  }
4225 
4233  public function definitelyCan( string $action, PageIdentity $target, PermissionStatus $status = null ): bool {
4234  return $this->getThisAsAuthority()->definitelyCan( $action, $target, $status );
4235  }
4236 
4244  public function authorizeRead( string $action, PageIdentity $target, PermissionStatus $status = null
4245  ): bool {
4246  return $this->getThisAsAuthority()->authorizeRead( $action, $target, $status );
4247  }
4248 
4256  public function authorizeWrite( string $action, PageIdentity $target, PermissionStatus $status = null ): bool {
4257  return $this->getThisAsAuthority()->authorizeWrite( $action, $target, $status );
4258  }
4259 
4265  private function getThisAsAuthority(): Authority {
4266  if ( !$this->mThisAsAuthority ) {
4267  // TODO: For users that are not User::isGlobalSessionUser,
4268  // creating a UserAuthority here is incorrect, since it depends
4269  // on global WebRequest, but that is what we've used to do before Authority.
4270  // When PermissionManager is refactored into Authority, we need
4271  // to provide base implementation, based on just user groups/rights,
4272  // and use it here.
4273  $this->mThisAsAuthority = new UserAuthority(
4274  $this,
4275  MediaWikiServices::getInstance()->getPermissionManager()
4276  );
4277  }
4278  return $this->mThisAsAuthority;
4279  }
4280 
4285  private function isGlobalSessionUser(): bool {
4286  // The session user is set up towards the end of Setup.php. Until then,
4287  // assume it's a logged-out user.
4288  $sessionUser = RequestContext::getMain()->getUser();
4289  $globalUserName = $sessionUser->isSafeToLoad()
4290  ? $sessionUser->getName()
4291  : IPUtils::sanitizeIP( $sessionUser->getRequest()->getIP() );
4292 
4293  return $this->getName() === $globalUserName;
4294  }
4295 }
User\getDefaultOption
static getDefaultOption( $opt)
Get a given default option value.
Definition: User.php:1589
User\newFromConfirmationCode
static newFromConfirmationCode( $code, $flags=self::READ_NORMAL)
Factory method to fetch whichever user has a given email confirmation code.
Definition: User.php:733
$wgHiddenPrefs
$wgHiddenPrefs
An array of preferences to not show for the user.
Definition: DefaultSettings.php:5741
MediaWiki\User\UserIdentityValue
Value object representing a user's identity.
Definition: UserIdentityValue.php:35
Page\PageIdentity
Interface for objects (potentially) representing an editable wiki page.
Definition: PageIdentity.php:64
User\loadFromId
loadFromId( $flags=self::READ_NORMAL)
Load user table data, given mId has already been set.
Definition: User.php:466
User\load
load( $flags=self::READ_NORMAL)
Load the user table data for this object from the source given by mFrom.
Definition: User.php:378
MediaWiki\DAO\WikiAwareEntityTrait
trait WikiAwareEntityTrait
Definition: WikiAwareEntityTrait.php:32
Wikimedia\Rdbms\Database
Relational database abstraction object.
Definition: Database.php:52
User\newFromId
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:647
Wikimedia\Rdbms\IDatabase\affectedRows
affectedRows()
Get the number of rows affected by the last write query.
User\confirmationTokenUrl
confirmationTokenUrl( $token)
Return a URL the user can use to confirm their email address.
Definition: User.php:3785
User\__set
__set( $name, $value)
Definition: User.php:317
MediaWiki\DAO\deprecateInvalidCrossWiki
deprecateInvalidCrossWiki( $wikiId, string $since)
Emits a deprecation warning $since version if $wikiId is not the same as this wiki.
Definition: WikiAwareEntityTrait.php:70
User\$mToken
string $mToken
Definition: User.php:170
User\$mBlockedby
string int $mBlockedby
Definition: User.php:211
StatusValue\newFatal
static newFatal( $message,... $parameters)
Factory function for fatal errors.
Definition: StatusValue.php:70
ObjectCache\getLocalClusterInstance
static getLocalClusterInstance()
Get the main cluster-local cache object.
Definition: ObjectCache.php:273
User\isValidPassword
isValidPassword( $password)
Is the input a valid password for this user?
Definition: User.php:1100
User\useFilePatrol
useFilePatrol()
Check whether to enable new files patrol features for this user.
Definition: User.php:3071
MWCryptHash\hmac
static hmac( $data, $key, $raw=true)
Generate an acceptably unstable one-way-hmac of some text making use of the best hash algorithm that ...
Definition: MWCryptHash.php:106
User\isAnon
isAnon()
Get whether the user is anonymous.
Definition: User.php:2995
User\$mBlockedFromCreateAccount
AbstractBlock bool $mBlockedFromCreateAccount
Definition: User.php:250
User\$mBlockreason
string $mBlockreason
TODO: This should be removed when User::BlockedFor and AbstractBlock::getReason are hard deprecated.
Definition: User.php:219
User\getTokenUrl
getTokenUrl( $page, $token)
Internal function to format the e-mail validation/invalidation URLs.
Definition: User.php:3812
User\isRegistered
isRegistered()
Get whether the user is registered.
Definition: User.php:2975
User\$mCacheVars
static string[] $mCacheVars
List of member variables which are saved to the shared cache (memcached).
Definition: User.php:130
User\resetTokenFromOption
resetTokenFromOption( $oname)
Reset a token stored in the preferences (like the watchlist one).
Definition: User.php:2678
User\isBlockedFrom
isBlockedFrom( $title, $fromReplica=false)
Check if user is blocked from editing a particular article.
Definition: User.php:1965
User\loadFromUserObject
loadFromUserObject( $user)
Load the data for this user object from another user object.
Definition: User.php:1449
MediaWiki\MediaWikiServices
MediaWikiServices is the service locator for the application scope of MediaWiki.
Definition: MediaWikiServices.php:199
User\newFatalPermissionDeniedStatus
static newFatalPermissionDeniedStatus( $permission)
Factory function for fatal permission-denied errors.
Definition: User.php:4140
User\getEditTokenObject
getEditTokenObject( $salt='', $request=null)
Initialize (if necessary) and return a session token value which can be used in edit forms to show th...
Definition: User.php:3616
User\isBot
isBot()
Definition: User.php:3003
User\newTouchedTimestamp
newTouchedTimestamp()
Generate a current or new-future timestamp to be stored in the user_touched field when we update thin...
Definition: User.php:2223
$wgExperiencedUserMemberSince
$wgExperiencedUserMemberSince
Number of days the user must exist before becoming "experienced".
Definition: DefaultSettings.php:5145
User\getEditCount
getEditCount()
Get the user's edit count.
Definition: User.php:2927
User\spreadBlock
spreadBlock()
If this (non-anonymous) user is blocked, block the IP address they've successfully logged in from.
Definition: User.php:3508
if
if(ini_get( 'mbstring.func_overload')) if(!defined('MW_ENTRY_POINT'))
Pre-config setup: Before loading LocalSettings.php.
Definition: Setup.php:88
User\incEditCount
incEditCount()
Schedule a deferred update to update the user's edit count.
Definition: User.php:4082
User\newFromSession
static newFromSession(WebRequest $request=null)
Create a new user object using data from session.
Definition: User.php:746
UserMailer\send
static send( $to, $from, $subject, $body, $options=[])
This function will perform a direct (authenticated) login to a SMTP Server to use for mail relaying i...
Definition: UserMailer.php:115
User\getOptionKinds
getOptionKinds(IContextSource $context, $options=null)
Return an associative array mapping preferences keys to the kind of a preference they're used for.
Definition: User.php:2738
User\isEmailConfirmationPending
isEmailConfirmationPending()
Check whether there is an outstanding request for e-mail confirmation.
Definition: User.php:3923
User\getBlockId
getBlockId()
If user is blocked, return the ID for the block.
Definition: User.php:2001
User\getIntOption
getIntOption( $oname, $defaultOverride=0)
Get the user's current setting for a given option, as an integer value.
Definition: User.php:2613
true
return true
Definition: router.php:90
User\getOptions
getOptions( $flags=0)
Get all user's options.
Definition: User.php:2580
User\$mTouched
string $mTouched
TS_MW timestamp from the DB.
Definition: User.php:166
User\__construct
__construct()
Lightweight constructor for an anonymous user.
Definition: User.php:273
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:1665
User\getToken
getToken( $forceCreation=true)
Get the user's current token.
Definition: User.php:2379
User\setEmail
setEmail(string $str)
Set the user's e-mail address.
Definition: User.php:2462
User\spreadAnyEditBlock
spreadAnyEditBlock()
If this user is logged-in and blocked, block any IP address they've successfully logged in from.
Definition: User.php:3495
User\$mAllowUsertalk
bool $mAllowUsertalk
TODO: This should be removed when User::isAllowUsertalk is removed.
Definition: User.php:247
$wgEmailAuthentication
$wgEmailAuthentication
Require email authentication before sending mail to an email address.
Definition: DefaultSettings.php:1973
MediaWiki\Permissions\UserAuthority
Represents the authority of a given User.
Definition: UserAuthority.php:45
$wgEnableUserEmail
$wgEnableUserEmail
Set to true to enable user-to-user e-mail.
Definition: DefaultSettings.php:1861
User\$mHideName
bool $mHideName
Definition: User.php:230
User\getStubThreshold
getStubThreshold()
Get the user preferred stub threshold.
Definition: User.php:2820
Sanitizer\validateEmail
static validateEmail( $addr)
Does a string look like an e-mail address?
Definition: Sanitizer.php:1745
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1098
User\$mLocked
bool $mLocked
Definition: User.php:223
User\newFromName
static newFromName( $name, $validate='valid')
Definition: User.php:606
User\loadFromRow
loadFromRow( $row, $data=null)
Initialize this object from a row from the user table.
Definition: User.php:1342
wfMessage
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
Definition: GlobalFunctions.php:1183
User\setEmailAuthenticationTimestamp
setEmailAuthenticationTimestamp( $timestamp)
Set the e-mail authentication timestamp.
Definition: User.php:3856
User\$mEmail
string $mEmail
Definition: User.php:164
User\getUserPage
getUserPage()
Get this user's personal page title.
Definition: User.php:3581
User\getGroups
getGroups()
Get the list of explicit group memberships this user has.
Definition: User.php:2847
User\newFromIdentity
static newFromIdentity(UserIdentity $identity)
Returns a User object corresponding to the given UserIdentity.
Definition: User.php:683
wfLogWarning
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
Definition: GlobalFunctions.php:1056
User\useNPPatrol
useNPPatrol()
Check whether to enable new pages patrol features for this user.
Definition: User.php:3059
DBAccessObjectUtils\getDBOptions
static getDBOptions( $bitfield)
Get an appropriate DB index, options, and fallback DB index for a query.
Definition: DBAccessObjectUtils.php:52
User\getDatePreference
getDatePreference()
Get the user's preferred date format.
Definition: User.php:2779
User\isSafeToLoad
isSafeToLoad()
Test if it's safe to load this User object.
Definition: User.php:361
$success
$success
Definition: NoLocalSettings.php:42
User\isValidUserName
static isValidUserName( $name)
Is the input a valid username?
Definition: User.php:1012
Wikimedia\Rdbms\IDatabase\selectField
selectField( $table, $var, $cond='', $fname=__METHOD__, $options=[], $join_conds=[])
A SELECT wrapper which returns a single field from a single result row.
User\sendConfirmationMail
sendConfirmationMail( $type='created')
Generate a new e-mail confirmation token and send a confirmation/invalidation mail to the user's give...
Definition: User.php:3686
User\groupHasPermission
static groupHasPermission( $group, $role)
Check, if the given group has the given permission.
Definition: User.php:4018
User\getEmailAuthenticationTimestamp
getEmailAuthenticationTimestamp()
Get the timestamp of the user's e-mail authentication.
Definition: User.php:2451
User\pingLimiter
pingLimiter( $action='edit', $incrBy=1)
Primitive rate limits: enforce maximum actions per time period to put a brake on flooding.
Definition: User.php:1688
User\getActorId
getActorId( $dbwOrWikiId=self::LOCAL)
Get the user's actor ID.
Definition: User.php:2167
User\useRCPatrol
useRCPatrol()
Check whether to enable recent changes patrol features for this user.
Definition: User.php:3050
User\invalidateEmail
invalidateEmail()
Invalidate the user's e-mail confirmation, and unauthenticate the e-mail address if it was already co...
Definition: User.php:3842
User\newFromRow
static newFromRow( $row, $data=null)
Create a new user object from a user row.
Definition: User.php:768
$wgUseRCPatrol
$wgUseRCPatrol
Use RC Patrolling to check for vandalism (from recent changes and watchlists) New pages and new files...
Definition: DefaultSettings.php:8073
User\$mHash
string $mHash
Definition: User.php:213
$wgUseNPPatrol
$wgUseNPPatrol
Use new page patrolling to check new pages on Special:Newpages.
Definition: DefaultSettings.php:8089
User\getBlock
getBlock( $freshness=self::READ_NORMAL, $disableIpBlockExemptChecking=false)
Get the block affecting the user, or null if the user is not blocked.
Definition: User.php:1940
$wgLang
$wgLang
Definition: Setup.php:834
MediaWiki\User\UserIdentity
Interface for objects representing user identity.
Definition: UserIdentity.php:39
User\isIPRange
isIPRange()
Is the user an IP range?
Definition: User.php:993
User\probablyCan
probablyCan(string $action, PageIdentity $target, PermissionStatus $status=null)
Definition: User.php:4222
User\getRights
getRights()
Get the permissions this user has.
Definition: User.php:2834
User\createNew
static createNew( $name, $params=[])
Add a user to the database, return the user object.
Definition: User.php:3328
User\getRequest
getRequest()
Get the WebRequest object to use with this object.
Definition: User.php:3084
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
User\getWikiId
getWikiId()
Returns self::LOCAL to indicate the user is associated with the local wiki.
Definition: User.php:283
User\getAutomaticGroups
getAutomaticGroups( $recache=false)
Get the list of implicit group memberships this user has.
Definition: User.php:2897
User\INVALID_TOKEN
const INVALID_TOKEN
An invalid string value for the user_token field.
Definition: User.php:92
NS_MAIN
const NS_MAIN
Definition: Defines.php:64
User\getDefaultOptions
static getDefaultOptions()
Combine the language default options with any site-specific options and add the default language vari...
Definition: User.php:1575
User\getInstanceForUpdate
getInstanceForUpdate()
Get a new instance of this user that was loaded from the primary DB via a locking read.
Definition: User.php:4166
$dbr
$dbr
Definition: testCompression.php:54
$wgExperiencedUserEdits
$wgExperiencedUserEdits
Number of edits the user must have before becoming "experienced".
Definition: DefaultSettings.php:5139
User\newSystemUser
static newSystemUser( $name, $options=[])
Static factory method for creation of a "system" user from username.
Definition: User.php:809
Wikimedia\Rdbms\IDatabase\update
update( $table, $set, $conds, $fname=__METHOD__, $options=[])
Update all rows in a table that match a given condition.
User\addGroup
addGroup( $group, $expiry=null)
Add the user to the given group.
Definition: User.php:2946
MailAddress
Stores a single person's name and email address.
Definition: MailAddress.php:36
MWExceptionHandler\logException
static logException(Throwable $e, $catcher=self::CAUGHT_BY_OTHER, $extraData=[])
Log a throwable to the exception log (if enabled).
Definition: MWExceptionHandler.php:700
LoggedOutEditToken
Value object representing a logged-out user's edit token.
Definition: LoggedOutEditToken.php:37
User\matchEditToken
matchEditToken( $val, $salt='', $request=null, $maxage=null)
Check given value against the token value stored in the session.
Definition: User.php:3658
User\getEmail
getEmail()
Get the user's e-mail address.
Definition: User.php:2438
MediaWiki\Block\DatabaseBlock
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
Definition: DatabaseBlock.php:50
User\getTalkPage
getTalkPage()
Get this user's talk page title.
Definition: User.php:3590
User\equals
equals(?UserIdentity $user)
Checks if two user objects point to the same user.
Definition: User.php:4186
User\addToDatabase
addToDatabase()
Add this existing user object to the database.
Definition: User.php:3421
Wikimedia\Rdbms\IDatabase\timestamp
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...
User\invalidateCache
invalidateCache()
Immediately touch the user data cache for this account.
Definition: User.php:2268
TitleValue\castPageToLinkTarget
static castPageToLinkTarget(?PageReference $page)
Casts a PageReference to a LinkTarget.
Definition: TitleValue.php:136
wfDeprecatedMsg
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
Definition: GlobalFunctions.php:1028
MWException
MediaWiki exception.
Definition: MWException.php:29
User\invalidationTokenUrl
invalidationTokenUrl( $token)
Return a URL the user can use to invalidate their email address.
Definition: User.php:3794
User\isLocked
isLocked()
Check if user account is locked.
Definition: User.php:2060
User\$mDatePreference
string $mDatePreference
Lazy-initialized variables, invalidated with clearInstanceCache.
Definition: User.php:204
$wgAuthenticationTokenVersion
string null $wgAuthenticationTokenVersion
Versioning for authentication tokens.
Definition: DefaultSettings.php:5779
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
Definition: GlobalFunctions.php:997
User\authorizeWrite
authorizeWrite(string $action, PageIdentity $target, PermissionStatus $status=null)
Definition: User.php:4256
MediaWiki\Logger\LoggerFactory
PSR-3 logger instance factory.
Definition: LoggerFactory.php:45
User\checkPasswordValidity
checkPasswordValidity( $password)
Check if this is a valid password for this user.
Definition: User.php:1126
User\confirmEmail
confirmEmail()
Mark the e-mail address confirmed.
Definition: User.php:3825
User\setItemLoaded
setItemLoaded( $item)
Set that an item has been loaded.
Definition: User.php:1253
UserGroupMembership\getLink
static getLink( $ugm, IContextSource $context, $format, $userName=null)
Gets a link for a user group, possibly including the expiry date if relevant.
Definition: UserGroupMembership.php:103
User\blockedFor
blockedFor()
If user is blocked, return the specified reason for the block.
Definition: User.php:1990
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2200
$wgFullyInitialised
if(!defined( 'MW_NO_SESSION') &&! $wgCommandLineMode) if(! $wgCommandLineMode) $wgFullyInitialised
Definition: Setup.php:888
MailAddress\newFromUser
static newFromUser(UserEmailContact $user)
Create a new MailAddress object for the given user.
Definition: MailAddress.php:72
User\isAllowedToCreateAccount
isAllowedToCreateAccount()
Get whether the user is allowed to create an account.
Definition: User.php:3572
User\logout
logout()
Log this user out.
Definition: User.php:3175
User\confirmationToken
confirmationToken(&$expiration)
Generate, store, and return a new e-mail confirmation code.
Definition: User.php:3767
User\getCacheKey
getCacheKey(WANObjectCache $cache)
Definition: User.php:507
wfTimestampOrNull
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
Definition: GlobalFunctions.php:1681
User\getImplicitGroups
static getImplicitGroups()
Definition: User.php:4040
User\setRealName
setRealName(string $str)
Set the user's real name.
Definition: User.php:2544
User\isHidden
isHidden()
Check if user account is hidden.
Definition: User.php:2075
User\definitelyCan
definitelyCan(string $action, PageIdentity $target, PermissionStatus $status=null)
Definition: User.php:4233
User\isBlockedFromEmailuser
isBlockedFromEmailuser()
Get whether the user is blocked from using Special:Emailuser.
Definition: User.php:3552
User\setEmailWithConfirmation
setEmailWithConfirmation(string $str)
Set the user's e-mail address and a confirmation mail if needed.
Definition: User.php:2479
User\$mBlock
AbstractBlock null $mBlock
Definition: User.php:240
User\loadDefaults
loadDefaults( $name=false, $actorId=null)
Set cached properties to default.
Definition: User.php:1205
User\isIP
static isIP( $name)
Does the string match an anonymous IP address?
Definition: User.php:978
User\validateCache
validateCache( $timestamp)
Validate the cache for this account.
Definition: User.php:2300
User\getEffectiveGroups
getEffectiveGroups( $recache=false)
Get the list of implicit group memberships this user has.
Definition: User.php:2879
User\isPingLimitable
isPingLimitable()
Is this user subject to rate limiting?
Definition: User.php:1661
User\removeGroup
removeGroup( $group)
Remove the user from the given group.
Definition: User.php:2961
User\canReceiveEmail
canReceiveEmail()
Is this user allowed to receive e-mails within limits of current site configuration?
Definition: User.php:3883
User\isNewbie
isNewbie()
Determine whether the user is a newbie.
Definition: User.php:3600
User\touch
touch()
Update the "touched" timestamp for the user.
Definition: User.php:2285
MediaWiki\User\UserIdentity\getName
getName()
$title
$title
Definition: testCompression.php:38
User\clearInstanceCache
clearInstanceCache( $reloadFrom=false)
Clear various cached data stored in this object.
Definition: User.php:1545
$wgEnableEmail
$wgEnableEmail
Set to true to enable the e-mail basic features: Password reminders, etc.
Definition: DefaultSettings.php:1855
User\CHECK_USER_RIGHTS
const CHECK_USER_RIGHTS
Definition: User.php:110
User\TOKEN_LENGTH
const TOKEN_LENGTH
Number of characters required for the user_token field.
Definition: User.php:87
Title\makeTitle
static makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:650
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:1694
User\$mQuickTouched
string $mQuickTouched
TS_MW timestamp from cache.
Definition: User.php:168
User\newFromAnyId
static newFromAnyId( $userId, $userName, $actorId, $dbDomain=false)
Static factory method for creation from an ID, name, and/or actor ID.
Definition: User.php:712
User\getId
getId( $wikiId=self::LOCAL)
Get the user's ID.
Definition: User.php:2088
User\setName
setName( $str)
Set the user name.
Definition: User.php:2149
User\$mRealName
string $mRealName
Definition: User.php:161
User\resetOptions
resetOptions( $resetKinds=[ 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused'], IContextSource $context=null)
Reset certain (or all) options to the site defaults.
Definition: User.php:2761
UserArray\newFromIDs
static newFromIDs( $ids)
Definition: UserArray.php:52
User\getBlockedStatus
getBlockedStatus( $fromReplica=true, $disableIpBlockExemptChecking=false)
Get blocking information.
Definition: User.php:1607
UserPasswordPolicy
Check if a user's password complies with any password policies that apply to that user,...
Definition: UserPasswordPolicy.php:31
$wgUseFilePatrol
$wgUseFilePatrol
Use file patrolling to check new files on Special:Newfiles.
Definition: DefaultSettings.php:8100
wfDebug
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:894
User\__get
& __get( $name)
Definition: User.php:294
User\saveSettings
saveSettings()
Save this user's settings into the database.
Definition: User.php:3223
User\isAllowedAll
isAllowedAll(... $permissions)
Checks whether this authority has any of the given permissions in general.
Definition: User.php:3038
User\getFirstEditTimestamp
getFirstEditTimestamp()
Get the timestamp of the first edit.
Definition: User.php:3954
User\authorizeRead
authorizeRead(string $action, PageIdentity $target, PermissionStatus $status=null)
Definition: User.php:4244
User\GETOPTIONS_EXCLUDE_DEFAULTS
const GETOPTIONS_EXCLUDE_DEFAULTS
Exclude user options that are set to their default value.
Definition: User.php:105
MediaWiki\Block\Block
Represents a block that may prevent users from performing specific operations.
Definition: Block.php:37
MediaWiki\Permissions\Authority
This interface represents the authority associated the current execution context, such as a web reque...
Definition: Authority.php:37
User\getFormerGroups
getFormerGroups()
Returns the groups the user has belonged to.
Definition: User.php:2916
MediaWiki\DAO\WikiAwareEntity\assertWiki
assertWiki( $wikiId)
Throws if $wikiId is different from the return value of getWikiId().
$s
foreach( $mmfl['setupFiles'] as $fileName) if( $queue) if(empty( $mmfl['quiet'])) $s
Definition: mergeMessageFileList.php:206
User\whoIs
static whoIs( $id)
Get the username corresponding to a given user ID.
Definition: User.php:916
DBAccessObjectUtils\hasFlags
static hasFlags( $bitfield, $flags)
Definition: DBAccessObjectUtils.php:35
User\isAllowedAny
isAllowedAny(... $permissions)
Checks whether this authority has any of the given permissions in general.
Definition: User.php:3034
User\loadFromSession
loadFromSession()
Load user data from the session.
Definition: User.php:1264
$wgRateLimits
$wgRateLimits
Simple rate limiter options to brake edit floods.
Definition: DefaultSettings.php:6537
User\isBlockedGlobally
isBlockedGlobally( $ip='')
Check if user is blocked on all wikis.
Definition: User.php:2015
$wgForceHTTPS
bool $wgForceHTTPS
If this is true, when an insecure HTTP request is received, always redirect to HTTPS.
Definition: DefaultSettings.php:167
User\getOption
getOption( $oname, $defaultOverride=null, $ignoreHidden=false)
Get the user's current setting for a given option.
Definition: User.php:2561
User\idForName
idForName( $flags=self::READ_NORMAL)
If only this user's username is known, and it exists, return the user ID.
Definition: User.php:3299
StatusValue\newGood
static newGood( $value=null)
Factory function for good results.
Definition: StatusValue.php:82
DB_PRIMARY
const DB_PRIMARY
Definition: defines.php:27
User\getTouched
getTouched()
Get the user touched timestamp.
Definition: User.php:2312
User\$mId
int $mId
Cache variables.
Definition: User.php:151
User\isSystemUser
isSystemUser()
Get whether the user is a system user.
Definition: User.php:3024
User\getGlobalBlock
getGlobalBlock( $ip='')
Check if user is blocked on all wikis.
Definition: User.php:2029
User\__toString
__toString()
Definition: User.php:290
MediaWiki\Block\SystemBlock
System blocks are temporary blocks that are created on enforcement (e.g.
Definition: SystemBlock.php:35
MediaWiki\Session\SessionManager
This serves as the entry point to the MediaWiki session handling system.
Definition: SessionManager.php:83
User\checkAndSetTouched
checkAndSetTouched()
Bump user_touched if it didn't change since this object was loaded.
Definition: User.php:1507
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:137
User\getRealName
getRealName()
Get the user's real name.
Definition: User.php:2532
User\setCookies
setCookies( $request=null, $secure=null, $rememberMe=false)
Persist this user's session (e.g.
Definition: User.php:3139
User\getGroupPermissions
static getGroupPermissions( $groups)
Get the permissions associated with a given list of groups.
Definition: User.php:3986
User\changeableGroups
changeableGroups()
Returns an array of groups that this user can add and remove.
Definition: User.php:4071
User\VERSION
const VERSION
Version number to tag cached versions of serialized User objects.
Definition: User.php:98
MediaWiki\Mail\UserEmailContact
Definition: UserEmailContact.php:11
User\matchEditTokenNoSuffix
matchEditTokenNoSuffix( $val, $salt='', $request=null, $maxage=null)
Check given value against the token value stored in the session, ignoring the suffix.
Definition: User.php:3673
User\getAllGroups
static getAllGroups()
Return the set of defined explicit groups.
Definition: User.php:4030
NS_USER
const NS_USER
Definition: Defines.php:66
MWCryptRand\generateHex
static generateHex( $chars)
Generate a run of cryptographically random data and return it in hexadecimal string format.
Definition: MWCryptRand.php:36
User\isBlockedFromUpload
isBlockedFromUpload()
Get whether the user is blocked from using Special:Upload.
Definition: User.php:3563
User\setActorId
setActorId(int $actorId)
Sets the actor id.
Definition: User.php:2204
RequestContext\getMain
static getMain()
Get the RequestContext object associated with the main request.
Definition: RequestContext.php:484
User\getQueryInfo
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new user object.
Definition: User.php:4108
MediaWiki\User\UserOptionsLookup
Provides access to user options.
Definition: UserOptionsLookup.php:29
User\blockedBy
blockedBy()
If user is blocked, return the name of the user who placed the block.
Definition: User.php:1978
User\$mLoadedItems
array bool $mLoadedItems
Array with already loaded items or true if all items have been loaded.
Definition: User.php:185
$wgLearnerEdits
$wgLearnerEdits
The following variables define 3 user experience levels:
Definition: DefaultSettings.php:5127
User\getDBTouched
getDBTouched()
Get the user_touched timestamp field (time of last DB updates)
Definition: User.php:2334
Wikimedia\Rdbms\IDatabase\insert
insert( $table, $rows, $fname=__METHOD__, $options=[])
Insert the given row(s) into a table.
MediaWiki\Auth\AuthManager
This serves as the entry point to the authentication system.
Definition: AuthManager.php:102
IContextSource
Interface for objects which can provide a MediaWiki context on request.
Definition: IContextSource.php:58
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form stripping il...
Definition: WebRequest.php:43
MediaWiki\Permissions\PermissionStatus
A StatusValue for permission errors.
Definition: PermissionStatus.php:35
User\changeableByGroup
static changeableByGroup( $group)
Returns an array of the groups that a particular group can add/remove.
Definition: User.php:4056
User\setId
setId( $v)
Set the user and reload all fields according to a given ID.
Definition: User.php:2112
User\getExperienceLevel
getExperienceLevel()
Compute experienced level based on edit count and registration date.
Definition: User.php:3096
$wgUserEmailConfirmationTokenExpiry
$wgUserEmailConfirmationTokenExpiry
The time, in seconds, when an email confirmation email expires.
Definition: DefaultSettings.php:1905
User\getRegistration
getRegistration()
Get the timestamp of account creation.
Definition: User.php:3938
User\isAllowed
isAllowed(string $permission)
Checks whether this authority has the given permission in general.
Definition: User.php:3042
PasswordFactory\newInvalidPassword
static newInvalidPassword()
Create an InvalidPassword.
Definition: PasswordFactory.php:242
MediaWiki\Block\AbstractBlock\appliesToRight
appliesToRight( $right)
Determine whether the block prevents a given right.
Definition: AbstractBlock.php:268
User\getRightDescription
static getRightDescription( $right)
Get the description of a given right.
Definition: User.php:4093
User\changeAuthenticationData
changeAuthenticationData(array $data)
Changes credentials of the user.
Definition: User.php:2352
$cache
$cache
Definition: mcc.php:33
$wgRateLimitsExcludedIPs
$wgRateLimitsExcludedIPs
Array of IPs / CIDR ranges which should be excluded from rate limits.
Definition: DefaultSettings.php:6619
User\isLoggedIn
isLoggedIn()
Get whether the user is registered.
Definition: User.php:2985
Wikimedia\Rdbms\DBExpectedError
Base class for the more common types of database errors.
Definition: DBExpectedError.php:34
User\$mActorId
int null $mActorId
Switched from protected to public for use in UserFactory.
Definition: User.php:159
User\getTitleKey
getTitleKey()
Get the user's name escaped by underscores.
Definition: User.php:2213
User\purge
static purge( $dbDomain, $userId)
Definition: User.php:496
User\setToken
setToken( $token=false)
Set the random token (used for persistent authentication) Called from loadDefaults() among other plac...
Definition: User.php:2422
User\idFromName
static idFromName( $name, $flags=self::READ_NORMAL)
Get database id given a user name.
Definition: User.php:937
MediaWiki\User\UserNameUtils
UserNameUtils service.
Definition: UserNameUtils.php:42
User\resetIdByNameCache
static resetIdByNameCache()
Reset the cache used in idFromName().
Definition: User.php:953
User\$mEmailTokenExpires
string $mEmailTokenExpires
Definition: User.php:176
User\findUsersByGroup
static findUsersByGroup( $groups, $limit=5000, $after=null)
Return the users who are members of the given group(s).
Definition: User.php:1046
User\getCanonicalName
static getCanonicalName( $name, $validate='valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid.
Definition: User.php:1172
User\isEmailConfirmed
isEmailConfirmed()
Is this user's e-mail address valid-looking and confirmed within limits of the current site configura...
Definition: User.php:3897
User\$mGlobalBlock
AbstractBlock $mGlobalBlock
Definition: User.php:221
User\isAllowUsertalk
isAllowUsertalk()
Checks if usertalk is allowed.
Definition: User.php:4201
UserCache\singleton
static singleton()
Definition: UserCache.php:48
User\clearSharedCache
clearSharedCache( $mode='refresh')
Clear user data from memcached.
Definition: User.php:2242
User\isBlocked
isBlocked( $fromReplica=true)
Check if user is blocked.
Definition: User.php:1924
User\newFromActorId
static newFromActorId( $id)
Static factory method for creation from a given actor ID.
Definition: User.php:664
User\$mThisAsAuthority
Authority null $mThisAsAuthority
lazy-initialized Authority of this user
Definition: User.php:256
$keys
$keys
Definition: testCompression.php:72
User\loadFromCache
loadFromCache()
Load user data from shared cache, given mId has already been set.
Definition: User.php:530
$wgLearnerMemberSince
$wgLearnerMemberSince
Number of days the user must exist before becoming a learner.
Definition: DefaultSettings.php:5133
User\addAutopromoteOnceGroups
addAutopromoteOnceGroups( $event)
Add the user to the group if he/she meets given criteria.
Definition: User.php:1472
User\sendMail
sendMail( $subject, $body, $from=null, $replyto=null)
Send an e-mail to this user's account.
Definition: User.php:3741
User\getTokenFromOption
getTokenFromOption( $oname)
Get a token stored in the preferences (like the watchlist one), resetting it if it's empty (and savin...
Definition: User.php:2650
User\$mEmailToken
string $mEmailToken
Definition: User.php:174
Wikimedia\Rdbms\IDatabase\timestampOrNull
timestampOrNull( $ts=null)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...
User\loadFromDatabase
loadFromDatabase( $flags=self::READ_LATEST)
Load user data from the database.
Definition: User.php:1290
User\$mName
string $mName
Definition: User.php:153
User\$mRegistration
string $mRegistration
Definition: User.php:178
MediaWiki\Block\AbstractBlock
Definition: AbstractBlock.php:37
$wgPasswordPolicy
$wgPasswordPolicy
Password policy for the wiki.
Definition: DefaultSettings.php:5272
User\IGNORE_USER_RIGHTS
const IGNORE_USER_RIGHTS
Definition: User.php:115
User\$mRequest
WebRequest $mRequest
Definition: User.php:233
MediaWiki\Session\Token
Value object representing a CSRF token.
Definition: Token.php:32
CentralIdLookup\AUDIENCE_RAW
const AUDIENCE_RAW
Definition: CentralIdLookup.php:38
User\getBoolOption
getBoolOption( $oname)
Get the user's current setting for a given option, as a boolean value.
Definition: User.php:2596
Wikimedia\Rdbms\IDatabase\insertId
insertId()
Get the inserted value of an auto-increment row.
User\isUsableName
static isUsableName( $name)
Usernames which fail to pass this function will be blocked from user login and new account registrati...
Definition: User.php:1031
User\makeUpdateConditions
makeUpdateConditions(IDatabase $db, array $conditions)
Builds update conditions.
Definition: User.php:1488
$wgPasswordSender
$wgPasswordSender
Sender email address for e-mail notifications.
Definition: DefaultSettings.php:1841
User\__sleep
__sleep()
Definition: User.php:338
User\isBlockedFromCreateAccount
isBlockedFromCreateAccount()
Get whether the user is explicitly blocked from account creation.
Definition: User.php:3528
User\getEditToken
getEditToken( $salt='', $request=null)
Initialize (if necessary) and return a session token value which can be used in edit forms to show th...
Definition: User.php:3641
User\requiresHTTPS
requiresHTTPS()
Determine based on the wiki configuration and the user's options, whether this user must be over HTTP...
Definition: User.php:2799
User\isItemLoaded
isItemLoaded( $item, $all='all')
Return whether an item has been loaded.
Definition: User.php:1241
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:68
User\setOption
setOption( $oname, $val)
Set the given option for a user.
Definition: User.php:2633
User\$queryFlagsUsed
int $queryFlagsUsed
User::READ_* constant bitfield used to load data.
Definition: User.php:253
User\whoIsReal
static whoIsReal( $id)
Get the real name of a user given their user ID.
Definition: User.php:926
ExternalUserNames\isExternal
static isExternal( $username)
Tells whether the username is external or not.
Definition: ExternalUserNames.php:149
User\getName
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:2121
$wgSecureLogin
$wgSecureLogin
This is to let user authenticate using https when they come from http.
Definition: DefaultSettings.php:5767
User\doLogout
doLogout()
Clear the user's session, and reset the instance cache.
Definition: User.php:3187
MediaWiki\User\UserFactory
Creates User objects.
Definition: UserFactory.php:41
User\getGroupMemberships
getGroupMemberships()
Get the list of explicit group memberships this user has, stored as UserGroupMembership objects.
Definition: User.php:2862
User\canSendEmail
canSendEmail()
Is this user allowed to send e-mails within limits of current site configuration?
Definition: User.php:3868
User\insertNewUser
static insertNewUser(callable $insertActor, $name, $params=[])
See ::createNew.
Definition: User.php:3341
User\isCreatableName
static isCreatableName( $name)
Usernames which fail to pass this function will be blocked from new account registrations,...
Definition: User.php:1089
User\isGlobalSessionUser
isGlobalSessionUser()
Check whether this is the global session user.
Definition: User.php:4285
User\getUser
getUser()
Definition: User.php:4211
User\getMutableCacheKeys
getMutableCacheKeys(WANObjectCache $cache)
Definition: User.php:518
MediaWiki\Auth\AuthenticationRequest
This is a value object for authentication requests.
Definition: AuthenticationRequest.php:38
User\getLatestEditTimestamp
getLatestEditTimestamp()
Get the timestamp of the latest edit.
Definition: User.php:3970
User\MAINTENANCE_SCRIPT_USER
const MAINTENANCE_SCRIPT_USER
Username used for various maintenance scripts.
Definition: User.php:121
User\$mEmailAuthenticated
string $mEmailAuthenticated
Definition: User.php:172
User\getGroupsWithPermission
static getGroupsWithPermission( $role)
Get all the groups who have a given permission.
Definition: User.php:3999
User\$mFrom
string $mFrom
Initialization data source if mLoadedItems!==true.
Definition: User.php:198
User\listOptionKinds
static listOptionKinds()
Return a list of the types of user options currently returned by User::getOptionKinds().
Definition: User.php:2716
User\getThisAsAuthority
getThisAsAuthority()
Returns the Authority of this User if it's the main request context user.
Definition: User.php:4265
$type
$type
Definition: testCompression.php:52