MediaWiki  1.23.16
User.php
Go to the documentation of this file.
1 <?php
27 define( 'USER_TOKEN_LENGTH', 32 );
28 
33 define( 'MW_USER_VERSION', 9 );
34 
39 define( 'EDIT_TOKEN_SUFFIX', '+\\' );
40 
45 class PasswordError extends MWException {
46  // NOP
47 }
48 
59 class User {
67 
72 
79  static $mCacheVars = array(
80  // user table
81  'mId',
82  'mName',
83  'mRealName',
84  'mPassword',
85  'mNewpassword',
86  'mNewpassTime',
87  'mEmail',
88  'mTouched',
89  'mToken',
90  'mEmailAuthenticated',
91  'mEmailToken',
92  'mEmailTokenExpires',
93  'mPasswordExpires',
94  'mRegistration',
95  'mEditCount',
96  // user_groups table
97  'mGroups',
98  // user_properties table
99  'mOptionOverrides',
100  );
101 
108  static $mCoreRights = array(
109  'apihighlimits',
110  'autoconfirmed',
111  'autopatrol',
112  'bigdelete',
113  'block',
114  'blockemail',
115  'bot',
116  'browsearchive',
117  'createaccount',
118  'createpage',
119  'createtalk',
120  'delete',
121  'deletedhistory',
122  'deletedtext',
123  'deletelogentry',
124  'deleterevision',
125  'edit',
126  'editcontentmodel',
127  'editinterface',
128  'editprotected',
129  'editmyoptions',
130  'editmyprivateinfo',
131  'editmyusercss',
132  'editmyuserjs',
133  'editmywatchlist',
134  'editsemiprotected',
135  'editusercssjs', #deprecated
136  'editusercss',
137  'edituserjs',
138  'hideuser',
139  'import',
140  'importupload',
141  'ipblock-exempt',
142  'markbotedits',
143  'mergehistory',
144  'minoredit',
145  'move',
146  'movefile',
147  'move-rootuserpages',
148  'move-subpages',
149  'nominornewtalk',
150  'noratelimit',
151  'override-export-depth',
152  'passwordreset',
153  'patrol',
154  'patrolmarks',
155  'protect',
156  'proxyunbannable',
157  'purge',
158  'read',
159  'reupload',
160  'reupload-own',
161  'reupload-shared',
162  'rollback',
163  'sendemail',
164  'siteadmin',
165  'suppressionlog',
166  'suppressredirect',
167  'suppressrevision',
168  'unblockself',
169  'undelete',
170  'unwatchedpages',
171  'upload',
172  'upload_by_url',
173  'userrights',
174  'userrights-interwiki',
175  'viewmyprivateinfo',
176  'viewmywatchlist',
177  'writeapi',
178  );
182  static $mAllRights = false;
183 
190 
191  protected $mPasswordExpires;
193 
199 
203  private $mLoadedItems = array();
205 
215  var $mFrom;
216 
223 
227  private $mRequest;
228 
232  var $mBlock;
233 
237  var $mAllowUsertalk;
238 
242  private $mBlockedFromCreateAccount = false;
243 
247  private $mWatchedItems = array();
248 
249  static $idCacheByName = array();
250 
261  public function __construct() {
262  $this->clearInstanceCache( 'defaults' );
263  }
264 
268  public function __toString() {
269  return $this->getName();
270  }
271 
275  public function load() {
276  if ( $this->mLoadedItems === true ) {
277  return;
278  }
279  wfProfileIn( __METHOD__ );
280 
281  // Set it now to avoid infinite recursion in accessors
282  $this->mLoadedItems = true;
283 
284  switch ( $this->mFrom ) {
285  case 'defaults':
286  $this->loadDefaults();
287  break;
288  case 'name':
289  $this->mId = self::idFromName( $this->mName );
290  if ( !$this->mId ) {
291  // Nonexistent user placeholder object
292  $this->loadDefaults( $this->mName );
293  } else {
294  $this->loadFromId();
295  }
296  break;
297  case 'id':
298  $this->loadFromId();
299  break;
300  case 'session':
301  if ( !$this->loadFromSession() ) {
302  // Loading from session failed. Load defaults.
303  $this->loadDefaults();
304  }
305  wfRunHooks( 'UserLoadAfterLoadFromSession', array( $this ) );
306  break;
307  default:
308  wfProfileOut( __METHOD__ );
309  throw new MWException( "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
310  }
311  wfProfileOut( __METHOD__ );
312  }
313 
318  public function loadFromId() {
319  global $wgMemc;
320  if ( $this->mId == 0 ) {
321  $this->loadDefaults();
322  return false;
323  }
324 
325  // Try cache
326  $key = wfMemcKey( 'user', 'id', $this->mId );
327  $data = $wgMemc->get( $key );
328  if ( !is_array( $data ) || $data['mVersion'] < MW_USER_VERSION ) {
329  // Object is expired, load from DB
330  $data = false;
331  }
332 
333  if ( !$data ) {
334  wfDebug( "User: cache miss for user {$this->mId}\n" );
335  // Load from DB
336  if ( !$this->loadFromDatabase() ) {
337  // Can't load from ID, user is anonymous
338  return false;
339  }
340  $this->saveToCache();
341  } else {
342  wfDebug( "User: got user {$this->mId} from cache\n" );
343  // Restore from cache
344  foreach ( self::$mCacheVars as $name ) {
345  $this->$name = $data[$name];
346  }
347  }
348 
349  $this->mLoadedItems = true;
350 
351  return true;
352  }
353 
357  public function saveToCache() {
358  $this->load();
359  $this->loadGroups();
360  $this->loadOptions();
361  if ( $this->isAnon() ) {
362  // Anonymous users are uncached
363  return;
364  }
365  $data = array();
366  foreach ( self::$mCacheVars as $name ) {
367  $data[$name] = $this->$name;
368  }
369  $data['mVersion'] = MW_USER_VERSION;
370  $key = wfMemcKey( 'user', 'id', $this->mId );
371  global $wgMemc;
372  $wgMemc->set( $key, $data );
373  }
374 
377 
394  public static function newFromName( $name, $validate = 'valid' ) {
395  if ( $validate === true ) {
396  $validate = 'valid';
397  }
398  $name = self::getCanonicalName( $name, $validate );
399  if ( $name === false ) {
400  return false;
401  } else {
402  // Create unloaded user object
403  $u = new User;
404  $u->mName = $name;
405  $u->mFrom = 'name';
406  $u->setItemLoaded( 'name' );
407  return $u;
408  }
409  }
410 
417  public static function newFromId( $id ) {
418  $u = new User;
419  $u->mId = $id;
420  $u->mFrom = 'id';
421  $u->setItemLoaded( 'id' );
422  return $u;
423  }
424 
435  public static function newFromConfirmationCode( $code ) {
436  $dbr = wfGetDB( DB_SLAVE );
437  $id = $dbr->selectField( 'user', 'user_id', array(
438  'user_email_token' => md5( $code ),
439  'user_email_token_expires > ' . $dbr->addQuotes( $dbr->timestamp() ),
440  ) );
441  if ( $id !== false ) {
442  return User::newFromId( $id );
443  } else {
444  return null;
445  }
446  }
447 
455  public static function newFromSession( WebRequest $request = null ) {
456  $user = new User;
457  $user->mFrom = 'session';
458  $user->mRequest = $request;
459  return $user;
460  }
461 
476  public static function newFromRow( $row, $data = null ) {
477  $user = new User;
478  $user->loadFromRow( $row, $data );
479  return $user;
480  }
481 
483 
489  public static function whoIs( $id ) {
490  return UserCache::singleton()->getProp( $id, 'name' );
491  }
492 
499  public static function whoIsReal( $id ) {
500  return UserCache::singleton()->getProp( $id, 'real_name' );
501  }
502 
508  public static function idFromName( $name ) {
510  if ( is_null( $nt ) ) {
511  // Illegal name
512  return null;
513  }
514 
515  if ( isset( self::$idCacheByName[$name] ) ) {
516  return self::$idCacheByName[$name];
517  }
518 
519  $dbr = wfGetDB( DB_SLAVE );
520  $s = $dbr->selectRow( 'user', array( 'user_id' ), array( 'user_name' => $nt->getText() ), __METHOD__ );
521 
522  if ( $s === false ) {
523  $result = null;
524  } else {
525  $result = $s->user_id;
526  }
527 
528  self::$idCacheByName[$name] = $result;
529 
530  if ( count( self::$idCacheByName ) > 1000 ) {
531  self::$idCacheByName = array();
532  }
533 
534  return $result;
535  }
536 
540  public static function resetIdByNameCache() {
541  self::$idCacheByName = array();
542  }
543 
560  public static function isIP( $name ) {
561  return preg_match( '/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/', $name ) || IP::isIPv6( $name );
562  }
563 
575  public static function isValidUserName( $name ) {
576  global $wgContLang, $wgMaxNameChars;
577 
578  if ( $name == ''
579  || User::isIP( $name )
580  || strpos( $name, '/' ) !== false
581  || strlen( $name ) > $wgMaxNameChars
582  || $name != $wgContLang->ucfirst( $name ) ) {
583  wfDebugLog( 'username', __METHOD__ .
584  ": '$name' invalid due to empty, IP, slash, length, or lowercase" );
585  return false;
586  }
587 
588  // Ensure that the name can't be misresolved as a different title,
589  // such as with extra namespace keys at the start.
590  $parsed = Title::newFromText( $name );
591  if ( is_null( $parsed )
592  || $parsed->getNamespace()
593  || strcmp( $name, $parsed->getPrefixedText() ) ) {
594  wfDebugLog( 'username', __METHOD__ .
595  ": '$name' invalid due to ambiguous prefixes" );
596  return false;
597  }
598 
599  // Check an additional blacklist of troublemaker characters.
600  // Should these be merged into the title char list?
601  $unicodeBlacklist = '/[' .
602  '\x{0080}-\x{009f}' . # iso-8859-1 control chars
603  '\x{00a0}' . # non-breaking space
604  '\x{2000}-\x{200f}' . # various whitespace
605  '\x{2028}-\x{202f}' . # breaks and control chars
606  '\x{3000}' . # ideographic space
607  '\x{e000}-\x{f8ff}' . # private use
608  ']/u';
609  if ( preg_match( $unicodeBlacklist, $name ) ) {
610  wfDebugLog( 'username', __METHOD__ .
611  ": '$name' invalid due to blacklisted characters" );
612  return false;
613  }
614 
615  return true;
616  }
617 
629  public static function isUsableName( $name ) {
630  global $wgReservedUsernames;
631  // Must be a valid username, obviously ;)
632  if ( !self::isValidUserName( $name ) ) {
633  return false;
634  }
635 
636  static $reservedUsernames = false;
637  if ( !$reservedUsernames ) {
638  $reservedUsernames = $wgReservedUsernames;
639  wfRunHooks( 'UserGetReservedNames', array( &$reservedUsernames ) );
640  }
641 
642  // Certain names may be reserved for batch processes.
643  foreach ( $reservedUsernames as $reserved ) {
644  if ( substr( $reserved, 0, 4 ) == 'msg:' ) {
645  $reserved = wfMessage( substr( $reserved, 4 ) )->inContentLanguage()->text();
646  }
647  if ( $reserved == $name ) {
648  return false;
649  }
650  }
651  return true;
652  }
653 
666  public static function isCreatableName( $name ) {
667  global $wgInvalidUsernameCharacters;
668 
669  // Ensure that the username isn't longer than 235 bytes, so that
670  // (at least for the builtin skins) user javascript and css files
671  // will work. (bug 23080)
672  if ( strlen( $name ) > 235 ) {
673  wfDebugLog( 'username', __METHOD__ .
674  ": '$name' invalid due to length" );
675  return false;
676  }
677 
678  // Preg yells if you try to give it an empty string
679  if ( $wgInvalidUsernameCharacters !== '' ) {
680  if ( preg_match( '/[' . preg_quote( $wgInvalidUsernameCharacters, '/' ) . ']/', $name ) ) {
681  wfDebugLog( 'username', __METHOD__ .
682  ": '$name' invalid due to wgInvalidUsernameCharacters" );
683  return false;
684  }
685  }
686 
687  return self::isUsableName( $name );
688  }
689 
696  public function isValidPassword( $password ) {
697  //simple boolean wrapper for getPasswordValidity
698  return $this->getPasswordValidity( $password ) === true;
699  }
700 
701 
708  public function getPasswordValidity( $password ) {
710  if ( $result->isGood() ) {
711  return true;
712  } else {
713  $messages = array();
714  foreach ( $result->getErrorsByType( 'error' ) as $error ) {
715  $messages[] = $error['message'];
716  }
717  foreach ( $result->getErrorsByType( 'warning' ) as $warning ) {
718  $messages[] = $warning['message'];
719  }
720  if ( count( $messages ) === 1 ) {
721  return $messages[0];
722  }
723  return $messages;
724  }
725  }
726 
735  public function checkPasswordValidity( $password ) {
736  global $wgMinimalPasswordLength, $wgContLang;
737 
738  static $blockedLogins = array(
739  'Useruser' => 'Passpass', 'Useruser1' => 'Passpass1', # r75589
740  'Apitestsysop' => 'testpass', 'Apitestuser' => 'testpass' # r75605
741  );
742 
743  $status = Status::newGood();
744 
745  $result = false; //init $result to false for the internal checks
746 
747  if ( !wfRunHooks( 'isValidPassword', array( $password, &$result, $this ) ) ) {
748  $status->error( $result );
749  return $status;
750  }
751 
752  if ( $result === false ) {
753  if ( strlen( $password ) < $wgMinimalPasswordLength ) {
754  $status->error( 'passwordtooshort', $wgMinimalPasswordLength );
755  return $status;
756  } elseif ( $wgContLang->lc( $password ) == $wgContLang->lc( $this->mName ) ) {
757  $status->error( 'password-name-match' );
758  return $status;
759  } elseif ( isset( $blockedLogins[$this->getName()] ) && $password == $blockedLogins[$this->getName()] ) {
760  $status->error( 'password-login-forbidden' );
761  return $status;
762  } else {
763  //it seems weird returning a Good status here, but this is because of the
764  //initialization of $result to false above. If the hook is never run or it
765  //doesn't modify $result, then we will likely get down into this if with
766  //a valid password.
767  return $status;
768  }
769  } elseif ( $result === true ) {
770  return $status;
771  } else {
772  $status->error( $result );
773  return $status; //the isValidPassword hook set a string $result and returned true
774  }
775  }
776 
782  public function expirePassword( $ts = 0 ) {
783  $this->load();
784  $timestamp = wfTimestamp( TS_MW, $ts );
785  $this->mPasswordExpires = $timestamp;
786  $this->saveSettings();
787  }
788 
794  public function resetPasswordExpiration( $load = true ) {
795  global $wgPasswordExpirationDays;
796  if ( $load ) {
797  $this->load();
798  }
799  $newExpire = null;
800  if ( $wgPasswordExpirationDays ) {
801  $newExpire = wfTimestamp(
802  TS_MW,
803  time() + ( $wgPasswordExpirationDays * 24 * 3600 )
804  );
805  }
806  // Give extensions a chance to force an expiration
807  wfRunHooks( 'ResetPasswordExpiration', array( $this, &$newExpire ) );
808  $this->mPasswordExpires = $newExpire;
809  }
810 
820  public function getPasswordExpired() {
821  global $wgPasswordExpireGrace;
822  $expired = false;
823  $now = wfTimestamp();
824  $expiration = $this->getPasswordExpireDate();
825  $expUnix = wfTimestamp( TS_UNIX, $expiration );
826  if ( $expiration !== null && $expUnix < $now ) {
827  $expired = ( $expUnix + $wgPasswordExpireGrace < $now ) ? 'hard' : 'soft';
828  }
829  return $expired;
830  }
831 
839  public function getPasswordExpireDate() {
840  $this->load();
842  }
843 
871  public static function isValidEmailAddr( $addr ) {
872  wfDeprecated( __METHOD__, '1.18' );
873  return Sanitizer::validateEmail( $addr );
874  }
875 
889  public static function getCanonicalName( $name, $validate = 'valid' ) {
890  // Force usernames to capital
892  $name = $wgContLang->ucfirst( $name );
893 
894  # Reject names containing '#'; these will be cleaned up
895  # with title normalisation, but then it's too late to
896  # check elsewhere
897  if ( strpos( $name, '#' ) !== false ) {
898  return false;
899  }
900 
901  // Clean up name according to title rules
902  $t = ( $validate === 'valid' ) ?
904  // Check for invalid titles
905  if ( is_null( $t ) ) {
906  return false;
907  }
908 
909  // Reject various classes of invalid names
910  global $wgAuth;
911  $name = $wgAuth->getCanonicalName( $t->getText() );
912 
913  switch ( $validate ) {
914  case false:
915  break;
916  case 'valid':
917  if ( !User::isValidUserName( $name ) ) {
918  $name = false;
919  }
920  break;
921  case 'usable':
922  if ( !User::isUsableName( $name ) ) {
923  $name = false;
924  }
925  break;
926  case 'creatable':
927  if ( !User::isCreatableName( $name ) ) {
928  $name = false;
929  }
930  break;
931  default:
932  throw new MWException( 'Invalid parameter value for $validate in ' . __METHOD__ );
933  }
934  return $name;
935  }
936 
945  public static function edits( $uid ) {
946  wfDeprecated( __METHOD__, '1.21' );
947  $user = self::newFromId( $uid );
948  return $user->getEditCount();
949  }
950 
956  public static function randomPassword() {
957  global $wgMinimalPasswordLength;
958  // Decide the final password length based on our min password length, stopping at a minimum of 10 chars
959  $length = max( 10, $wgMinimalPasswordLength );
960  // Multiply by 1.25 to get the number of hex characters we need
961  // Generate random hex chars
962  $hex = MWCryptRand::generateHex( ceil( $length * 1.25 ) );
963  // Convert from base 16 to base 32 to get a proper password like string
964  return substr( wfBaseConvert( $hex, 16, 32, $length ), -$length );
965  }
966 
975  public function loadDefaults( $name = false ) {
976  wfProfileIn( __METHOD__ );
977 
978  $this->mId = 0;
979  $this->mName = $name;
980  $this->mRealName = '';
981  $this->mPassword = $this->mNewpassword = '';
982  $this->mNewpassTime = null;
983  $this->mEmail = '';
984  $this->mOptionOverrides = null;
985  $this->mOptionsLoaded = false;
986 
987  $loggedOut = $this->getRequest()->getCookie( 'LoggedOut' );
988  if ( $loggedOut !== null ) {
989  $this->mTouched = wfTimestamp( TS_MW, $loggedOut );
990  } else {
991  $this->mTouched = '1'; # Allow any pages to be cached
992  }
993 
994  $this->mToken = null; // Don't run cryptographic functions till we need a token
995  $this->mEmailAuthenticated = null;
996  $this->mEmailToken = '';
997  $this->mEmailTokenExpires = null;
998  $this->mPasswordExpires = null;
999  $this->resetPasswordExpiration( false );
1000  $this->mRegistration = wfTimestamp( TS_MW );
1001  $this->mGroups = array();
1002 
1003  wfRunHooks( 'UserLoadDefaults', array( $this, $name ) );
1004 
1005  wfProfileOut( __METHOD__ );
1006  }
1007 
1020  public function isItemLoaded( $item, $all = 'all' ) {
1021  return ( $this->mLoadedItems === true && $all === 'all' ) ||
1022  ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] === true );
1023  }
1024 
1030  protected function setItemLoaded( $item ) {
1031  if ( is_array( $this->mLoadedItems ) ) {
1032  $this->mLoadedItems[$item] = true;
1033  }
1034  }
1040  private function loadFromSession() {
1041  $result = null;
1042  wfRunHooks( 'UserLoadFromSession', array( $this, &$result ) );
1043  if ( $result !== null ) {
1044  return $result;
1045  }
1046 
1047  $request = $this->getRequest();
1048 
1049  $cookieId = $request->getCookie( 'UserID' );
1050  $sessId = $request->getSessionData( 'wsUserID' );
1051 
1052  if ( $cookieId !== null ) {
1053  $sId = intval( $cookieId );
1054  if ( $sessId !== null && $cookieId != $sessId ) {
1055  wfDebugLog( 'loginSessions', "Session user ID ($sessId) and
1056  cookie user ID ($sId) don't match!" );
1057  return false;
1058  }
1059  $request->setSessionData( 'wsUserID', $sId );
1060  } elseif ( $sessId !== null && $sessId != 0 ) {
1061  $sId = $sessId;
1062  } else {
1063  return false;
1064  }
1065 
1066  if ( $request->getSessionData( 'wsUserName' ) !== null ) {
1067  $sName = $request->getSessionData( 'wsUserName' );
1068  } elseif ( $request->getCookie( 'UserName' ) !== null ) {
1069  $sName = $request->getCookie( 'UserName' );
1070  $request->setSessionData( 'wsUserName', $sName );
1071  } else {
1072  return false;
1073  }
1074 
1075  $proposedUser = User::newFromId( $sId );
1076  if ( !$proposedUser->isLoggedIn() ) {
1077  // Not a valid ID
1078  return false;
1079  }
1080 
1081  global $wgBlockDisablesLogin;
1082  if ( $wgBlockDisablesLogin && $proposedUser->isBlocked() ) {
1083  // User blocked and we've disabled blocked user logins
1084  return false;
1085  }
1086 
1087  if ( $request->getSessionData( 'wsToken' ) ) {
1088  $passwordCorrect = ( $proposedUser->getToken( false ) === $request->getSessionData( 'wsToken' ) );
1089  $from = 'session';
1090  } elseif ( $request->getCookie( 'Token' ) ) {
1091  # Get the token from DB/cache and clean it up to remove garbage padding.
1092  # This deals with historical problems with bugs and the default column value.
1093  $token = rtrim( $proposedUser->getToken( false ) ); // correct token
1094  // Make comparison in constant time (bug 61346)
1095  $passwordCorrect = strlen( $token ) && $this->compareSecrets( $token, $request->getCookie( 'Token' ) );
1096  $from = 'cookie';
1097  } else {
1098  // No session or persistent login cookie
1099  return false;
1100  }
1101 
1102  if ( ( $sName === $proposedUser->getName() ) && $passwordCorrect ) {
1103  $this->loadFromUserObject( $proposedUser );
1104  $request->setSessionData( 'wsToken', $this->mToken );
1105  wfDebug( "User: logged in from $from\n" );
1106  return true;
1107  } else {
1108  // Invalid credentials
1109  wfDebug( "User: can't log in from $from, invalid credentials\n" );
1110  return false;
1111  }
1112  }
1113 
1120  protected function compareSecrets( $answer, $test ) {
1121  if ( strlen( $answer ) !== strlen( $test ) ) {
1122  $passwordCorrect = false;
1123  } else {
1124  $result = 0;
1125  for ( $i = 0; $i < strlen( $answer ); $i++ ) {
1126  $result |= ord( $answer[$i] ) ^ ord( $test[$i] );
1127  }
1128  $passwordCorrect = ( $result == 0 );
1129  }
1130  return $passwordCorrect;
1131  }
1132 
1139  public function loadFromDatabase() {
1140  // Paranoia
1141  $this->mId = intval( $this->mId );
1142 
1143  // Anonymous user
1144  if ( !$this->mId ) {
1145  $this->loadDefaults();
1146  return false;
1147  }
1148 
1149  $dbr = wfGetDB( DB_MASTER );
1150  $s = $dbr->selectRow( 'user', self::selectFields(), array( 'user_id' => $this->mId ), __METHOD__ );
1151 
1152  wfRunHooks( 'UserLoadFromDatabase', array( $this, &$s ) );
1153 
1154  if ( $s !== false ) {
1155  // Initialise user table data
1156  $this->loadFromRow( $s );
1157  $this->mGroups = null; // deferred
1158  $this->getEditCount(); // revalidation for nulls
1159  return true;
1160  } else {
1161  // Invalid user_id
1162  $this->mId = 0;
1163  $this->loadDefaults();
1164  return false;
1165  }
1166  }
1167 
1177  public function loadFromRow( $row, $data = null ) {
1178  $all = true;
1179 
1180  $this->mGroups = null; // deferred
1181 
1182  if ( isset( $row->user_name ) ) {
1183  $this->mName = $row->user_name;
1184  $this->mFrom = 'name';
1185  $this->setItemLoaded( 'name' );
1186  } else {
1187  $all = false;
1188  }
1189 
1190  if ( isset( $row->user_real_name ) ) {
1191  $this->mRealName = $row->user_real_name;
1192  $this->setItemLoaded( 'realname' );
1193  } else {
1194  $all = false;
1195  }
1196 
1197  if ( isset( $row->user_id ) ) {
1198  $this->mId = intval( $row->user_id );
1199  $this->mFrom = 'id';
1200  $this->setItemLoaded( 'id' );
1201  } else {
1202  $all = false;
1203  }
1204 
1205  if ( isset( $row->user_editcount ) ) {
1206  $this->mEditCount = $row->user_editcount;
1207  } else {
1208  $all = false;
1209  }
1210 
1211  if ( isset( $row->user_password ) ) {
1212  $this->mPassword = $row->user_password;
1213  $this->mNewpassword = $row->user_newpassword;
1214  $this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time );
1215  $this->mEmail = $row->user_email;
1216  $this->mTouched = wfTimestamp( TS_MW, $row->user_touched );
1217  $this->mToken = $row->user_token;
1218  if ( $this->mToken == '' ) {
1219  $this->mToken = null;
1220  }
1221  $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
1222  $this->mEmailToken = $row->user_email_token;
1223  $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
1224  $this->mPasswordExpires = wfTimestampOrNull( TS_MW, $row->user_password_expires );
1225  $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
1226  } else {
1227  $all = false;
1228  }
1229 
1230  if ( $all ) {
1231  $this->mLoadedItems = true;
1232  }
1233 
1234  if ( is_array( $data ) ) {
1235  if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) {
1236  $this->mGroups = $data['user_groups'];
1237  }
1238  if ( isset( $data['user_properties'] ) && is_array( $data['user_properties'] ) ) {
1239  $this->loadOptions( $data['user_properties'] );
1240  }
1241  }
1242  }
1243 
1249  protected function loadFromUserObject( $user ) {
1250  $user->load();
1251  $user->loadGroups();
1252  $user->loadOptions();
1253  foreach ( self::$mCacheVars as $var ) {
1254  $this->$var = $user->$var;
1255  }
1256  }
1257 
1261  private function loadGroups() {
1262  if ( is_null( $this->mGroups ) ) {
1263  $dbr = wfGetDB( DB_MASTER );
1264  $res = $dbr->select( 'user_groups',
1265  array( 'ug_group' ),
1266  array( 'ug_user' => $this->mId ),
1267  __METHOD__ );
1268  $this->mGroups = array();
1269  foreach ( $res as $row ) {
1270  $this->mGroups[] = $row->ug_group;
1271  }
1272  }
1273  }
1274 
1289  public function addAutopromoteOnceGroups( $event ) {
1290  global $wgAutopromoteOnceLogInRC, $wgAuth;
1291 
1292  $toPromote = array();
1293  if ( $this->getId() ) {
1294  $toPromote = Autopromote::getAutopromoteOnceGroups( $this, $event );
1295  if ( count( $toPromote ) ) {
1296  $oldGroups = $this->getGroups(); // previous groups
1297 
1298  foreach ( $toPromote as $group ) {
1299  $this->addGroup( $group );
1300  }
1301  // update groups in external authentication database
1302  $wgAuth->updateExternalDBGroups( $this, $toPromote );
1303 
1304  $newGroups = array_merge( $oldGroups, $toPromote ); // all groups
1305 
1306  $logEntry = new ManualLogEntry( 'rights', 'autopromote' );
1307  $logEntry->setPerformer( $this );
1308  $logEntry->setTarget( $this->getUserPage() );
1309  $logEntry->setParameters( array(
1310  '4::oldgroups' => $oldGroups,
1311  '5::newgroups' => $newGroups,
1312  ) );
1313  $logid = $logEntry->insert();
1314  if ( $wgAutopromoteOnceLogInRC ) {
1315  $logEntry->publish( $logid );
1316  }
1317  }
1318  }
1319  return $toPromote;
1320  }
1321 
1330  public function clearInstanceCache( $reloadFrom = false ) {
1331  $this->mNewtalk = -1;
1332  $this->mDatePreference = null;
1333  $this->mBlockedby = -1; # Unset
1334  $this->mHash = false;
1335  $this->mRights = null;
1336  $this->mEffectiveGroups = null;
1337  $this->mImplicitGroups = null;
1338  $this->mGroups = null;
1339  $this->mOptions = null;
1340  $this->mOptionsLoaded = false;
1341  $this->mEditCount = null;
1342 
1343  if ( $reloadFrom ) {
1344  $this->mLoadedItems = array();
1345  $this->mFrom = $reloadFrom;
1346  }
1347  }
1348 
1355  public static function getDefaultOptions() {
1356  global $wgNamespacesToBeSearchedDefault, $wgDefaultUserOptions, $wgContLang, $wgDefaultSkin;
1357 
1358  static $defOpt = null;
1359  if ( !defined( 'MW_PHPUNIT_TEST' ) && $defOpt !== null ) {
1360  // Disabling this for the unit tests, as they rely on being able to change $wgContLang
1361  // mid-request and see that change reflected in the return value of this function.
1362  // Which is insane and would never happen during normal MW operation
1363  return $defOpt;
1364  }
1365 
1366  $defOpt = $wgDefaultUserOptions;
1367  // Default language setting
1368  $defOpt['language'] = $wgContLang->getCode();
1369  foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
1370  $defOpt[$langCode == $wgContLang->getCode() ? 'variant' : "variant-$langCode"] = $langCode;
1371  }
1372  foreach ( SearchEngine::searchableNamespaces() as $nsnum => $nsname ) {
1373  $defOpt['searchNs' . $nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
1374  }
1375  $defOpt['skin'] = $wgDefaultSkin;
1376 
1377  wfRunHooks( 'UserGetDefaultOptions', array( &$defOpt ) );
1378 
1379  return $defOpt;
1380  }
1381 
1388  public static function getDefaultOption( $opt ) {
1389  $defOpts = self::getDefaultOptions();
1390  if ( isset( $defOpts[$opt] ) ) {
1391  return $defOpts[$opt];
1392  } else {
1393  return null;
1394  }
1395  }
1396 
1404  private function getBlockedStatus( $bFromSlave = true ) {
1405  global $wgProxyWhitelist, $wgUser, $wgApplyIpBlocksToXff;
1406 
1407  if ( -1 != $this->mBlockedby ) {
1408  return;
1409  }
1410 
1411  wfProfileIn( __METHOD__ );
1412  wfDebug( __METHOD__ . ": checking...\n" );
1413 
1414  // Initialize data...
1415  // Otherwise something ends up stomping on $this->mBlockedby when
1416  // things get lazy-loaded later, causing false positive block hits
1417  // due to -1 !== 0. Probably session-related... Nothing should be
1418  // overwriting mBlockedby, surely?
1419  $this->load();
1420 
1421  # We only need to worry about passing the IP address to the Block generator if the
1422  # user is not immune to autoblocks/hardblocks, and they are the current user so we
1423  # know which IP address they're actually coming from
1424  if ( !$this->isAllowed( 'ipblock-exempt' ) && $this->getID() == $wgUser->getID() ) {
1425  $ip = $this->getRequest()->getIP();
1426  } else {
1427  $ip = null;
1428  }
1429 
1430  // User/IP blocking
1431  $block = Block::newFromTarget( $this, $ip, !$bFromSlave );
1432 
1433  // Proxy blocking
1434  if ( !$block instanceof Block && $ip !== null && !$this->isAllowed( 'proxyunbannable' )
1435  && !in_array( $ip, $wgProxyWhitelist )
1436  ) {
1437  // Local list
1438  if ( self::isLocallyBlockedProxy( $ip ) ) {
1439  $block = new Block;
1440  $block->setBlocker( wfMessage( 'proxyblocker' )->text() );
1441  $block->mReason = wfMessage( 'proxyblockreason' )->text();
1442  $block->setTarget( $ip );
1443  } elseif ( $this->isAnon() && $this->isDnsBlacklisted( $ip ) ) {
1444  $block = new Block;
1445  $block->setBlocker( wfMessage( 'sorbs' )->text() );
1446  $block->mReason = wfMessage( 'sorbsreason' )->text();
1447  $block->setTarget( $ip );
1448  }
1449  }
1450 
1451  // (bug 23343) Apply IP blocks to the contents of XFF headers, if enabled
1452  if ( !$block instanceof Block
1453  && $wgApplyIpBlocksToXff
1454  && $ip !== null
1455  && !$this->isAllowed( 'proxyunbannable' )
1456  && !in_array( $ip, $wgProxyWhitelist )
1457  ) {
1458  $xff = $this->getRequest()->getHeader( 'X-Forwarded-For' );
1459  $xff = array_map( 'trim', explode( ',', $xff ) );
1460  $xff = array_diff( $xff, array( $ip ) );
1461  $xffblocks = Block::getBlocksForIPList( $xff, $this->isAnon(), !$bFromSlave );
1462  $block = Block::chooseBlock( $xffblocks, $xff );
1463  if ( $block instanceof Block ) {
1464  # Mangle the reason to alert the user that the block
1465  # originated from matching the X-Forwarded-For header.
1466  $block->mReason = wfMessage( 'xffblockreason', $block->mReason )->text();
1467  }
1468  }
1469 
1470  if ( $block instanceof Block ) {
1471  wfDebug( __METHOD__ . ": Found block.\n" );
1472  $this->mBlock = $block;
1473  $this->mBlockedby = $block->getByName();
1474  $this->mBlockreason = $block->mReason;
1475  $this->mHideName = $block->mHideName;
1476  $this->mAllowUsertalk = !$block->prevents( 'editownusertalk' );
1477  } else {
1478  $this->mBlockedby = '';
1479  $this->mHideName = 0;
1480  $this->mAllowUsertalk = false;
1481  }
1482 
1483  // Extensions
1484  wfRunHooks( 'GetBlockedStatus', array( &$this ) );
1485 
1486  wfProfileOut( __METHOD__ );
1487  }
1488 
1496  public function isDnsBlacklisted( $ip, $checkWhitelist = false ) {
1497  global $wgEnableSorbs, $wgEnableDnsBlacklist,
1498  $wgSorbsUrl, $wgDnsBlacklistUrls, $wgProxyWhitelist;
1499 
1500  if ( !$wgEnableDnsBlacklist && !$wgEnableSorbs ) {
1501  return false;
1502  }
1503 
1504  if ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) ) {
1505  return false;
1506  }
1507 
1508  $urls = array_merge( $wgDnsBlacklistUrls, (array)$wgSorbsUrl );
1509  return $this->inDnsBlacklist( $ip, $urls );
1510  }
1511 
1519  public function inDnsBlacklist( $ip, $bases ) {
1520  wfProfileIn( __METHOD__ );
1521 
1522  $found = false;
1523  // @todo FIXME: IPv6 ??? (http://bugs.php.net/bug.php?id=33170)
1524  if ( IP::isIPv4( $ip ) ) {
1525  // Reverse IP, bug 21255
1526  $ipReversed = implode( '.', array_reverse( explode( '.', $ip ) ) );
1527 
1528  foreach ( (array)$bases as $base ) {
1529  // Make hostname
1530  // If we have an access key, use that too (ProjectHoneypot, etc.)
1531  if ( is_array( $base ) ) {
1532  if ( count( $base ) >= 2 ) {
1533  // Access key is 1, base URL is 0
1534  $host = "{$base[1]}.$ipReversed.{$base[0]}";
1535  } else {
1536  $host = "$ipReversed.{$base[0]}";
1537  }
1538  } else {
1539  $host = "$ipReversed.$base";
1540  }
1541 
1542  // Send query
1543  $ipList = gethostbynamel( $host );
1544 
1545  if ( $ipList ) {
1546  wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $base!" );
1547  $found = true;
1548  break;
1549  } else {
1550  wfDebugLog( 'dnsblacklist', "Requested $host, not found in $base." );
1551  }
1552  }
1553  }
1554 
1555  wfProfileOut( __METHOD__ );
1556  return $found;
1557  }
1558 
1566  public static function isLocallyBlockedProxy( $ip ) {
1567  global $wgProxyList;
1568 
1569  if ( !$wgProxyList ) {
1570  return false;
1571  }
1572  wfProfileIn( __METHOD__ );
1573 
1574  if ( !is_array( $wgProxyList ) ) {
1575  // Load from the specified file
1576  $wgProxyList = array_map( 'trim', file( $wgProxyList ) );
1577  }
1578 
1579  if ( !is_array( $wgProxyList ) ) {
1580  $ret = false;
1581  } elseif ( array_search( $ip, $wgProxyList ) !== false ) {
1582  $ret = true;
1583  } elseif ( array_key_exists( $ip, $wgProxyList ) ) {
1584  // Old-style flipped proxy list
1585  $ret = true;
1586  } else {
1587  $ret = false;
1588  }
1589  wfProfileOut( __METHOD__ );
1590  return $ret;
1591  }
1592 
1598  public function isPingLimitable() {
1599  global $wgRateLimitsExcludedIPs;
1600  if ( in_array( $this->getRequest()->getIP(), $wgRateLimitsExcludedIPs ) ) {
1601  // No other good way currently to disable rate limits
1602  // for specific IPs. :P
1603  // But this is a crappy hack and should die.
1604  return false;
1605  }
1606  return !$this->isAllowed( 'noratelimit' );
1607  }
1608 
1620  public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
1621  // Call the 'PingLimiter' hook
1622  $result = false;
1623  if ( !wfRunHooks( 'PingLimiter', array( &$this, $action, &$result, $incrBy ) ) ) {
1624  return $result;
1625  }
1626 
1627  global $wgRateLimits;
1628  if ( !isset( $wgRateLimits[$action] ) ) {
1629  return false;
1630  }
1631 
1632  // Some groups shouldn't trigger the ping limiter, ever
1633  if ( !$this->isPingLimitable() ) {
1634  return false;
1635  }
1636 
1637  global $wgMemc;
1638  wfProfileIn( __METHOD__ );
1639 
1640  $limits = $wgRateLimits[$action];
1641  $keys = array();
1642  $id = $this->getId();
1643  $userLimit = false;
1644 
1645  if ( isset( $limits['anon'] ) && $id == 0 ) {
1646  $keys[wfMemcKey( 'limiter', $action, 'anon' )] = $limits['anon'];
1647  }
1648 
1649  if ( isset( $limits['user'] ) && $id != 0 ) {
1650  $userLimit = $limits['user'];
1651  }
1652  if ( $this->isNewbie() ) {
1653  if ( isset( $limits['newbie'] ) && $id != 0 ) {
1654  $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $limits['newbie'];
1655  }
1656  if ( isset( $limits['ip'] ) ) {
1657  $ip = $this->getRequest()->getIP();
1658  $keys["mediawiki:limiter:$action:ip:$ip"] = $limits['ip'];
1659  }
1660  if ( isset( $limits['subnet'] ) ) {
1661  $ip = $this->getRequest()->getIP();
1662  $matches = array();
1663  $subnet = false;
1664  if ( IP::isIPv6( $ip ) ) {
1665  $parts = IP::parseRange( "$ip/64" );
1666  $subnet = $parts[0];
1667  } elseif ( preg_match( '/^(\d+\.\d+\.\d+)\.\d+$/', $ip, $matches ) ) {
1668  // IPv4
1669  $subnet = $matches[1];
1670  }
1671  if ( $subnet !== false ) {
1672  $keys["mediawiki:limiter:$action:subnet:$subnet"] = $limits['subnet'];
1673  }
1674  }
1675  }
1676  // Check for group-specific permissions
1677  // If more than one group applies, use the group with the highest limit
1678  foreach ( $this->getGroups() as $group ) {
1679  if ( isset( $limits[$group] ) ) {
1680  if ( $userLimit === false || $limits[$group] > $userLimit ) {
1681  $userLimit = $limits[$group];
1682  }
1683  }
1684  }
1685  // Set the user limit key
1686  if ( $userLimit !== false ) {
1687  list( $max, $period ) = $userLimit;
1688  wfDebug( __METHOD__ . ": effective user limit: $max in {$period}s\n" );
1689  $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $userLimit;
1690  }
1691 
1692  $triggered = false;
1693  foreach ( $keys as $key => $limit ) {
1694  list( $max, $period ) = $limit;
1695  $summary = "(limit $max in {$period}s)";
1696  $count = $wgMemc->get( $key );
1697  // Already pinged?
1698  if ( $count ) {
1699  if ( $count >= $max ) {
1700  wfDebugLog( 'ratelimit', $this->getName() . " tripped! $key at $count $summary" );
1701  $triggered = true;
1702  } else {
1703  wfDebug( __METHOD__ . ": ok. $key at $count $summary\n" );
1704  }
1705  } else {
1706  wfDebug( __METHOD__ . ": adding record for $key $summary\n" );
1707  if ( $incrBy > 0 ) {
1708  $wgMemc->add( $key, 0, intval( $period ) ); // first ping
1709  }
1710  }
1711  if ( $incrBy > 0 ) {
1712  $wgMemc->incr( $key, $incrBy );
1713  }
1714  }
1715 
1716  wfProfileOut( __METHOD__ );
1717  return $triggered;
1718  }
1719 
1726  public function isBlocked( $bFromSlave = true ) { // hacked from false due to horrible probs on site
1727  return $this->getBlock( $bFromSlave ) instanceof Block && $this->getBlock()->prevents( 'edit' );
1728  }
1729 
1736  public function getBlock( $bFromSlave = true ) {
1737  $this->getBlockedStatus( $bFromSlave );
1738  return $this->mBlock instanceof Block ? $this->mBlock : null;
1739  }
1740 
1748  public function isBlockedFrom( $title, $bFromSlave = false ) {
1749  global $wgBlockAllowsUTEdit;
1750  wfProfileIn( __METHOD__ );
1751 
1752  $blocked = $this->isBlocked( $bFromSlave );
1753  $allowUsertalk = ( $wgBlockAllowsUTEdit ? $this->mAllowUsertalk : false );
1754  // If a user's name is suppressed, they cannot make edits anywhere
1755  if ( !$this->mHideName && $allowUsertalk && $title->getText() === $this->getName()
1756  && $title->getNamespace() == NS_USER_TALK ) {
1757  $blocked = false;
1758  wfDebug( __METHOD__ . ": self-talk page, ignoring any blocks\n" );
1759  }
1760 
1761  wfRunHooks( 'UserIsBlockedFrom', array( $this, $title, &$blocked, &$allowUsertalk ) );
1762 
1763  wfProfileOut( __METHOD__ );
1764  return $blocked;
1765  }
1771  public function blockedBy() {
1772  $this->getBlockedStatus();
1773  return $this->mBlockedby;
1774  }
1780  public function blockedFor() {
1781  $this->getBlockedStatus();
1782  return $this->mBlockreason;
1783  }
1789  public function getBlockId() {
1790  $this->getBlockedStatus();
1791  return ( $this->mBlock ? $this->mBlock->getId() : false );
1792  }
1793 
1802  public function isBlockedGlobally( $ip = '' ) {
1803  if ( $this->mBlockedGlobally !== null ) {
1804  return $this->mBlockedGlobally;
1805  }
1806  // User is already an IP?
1807  if ( IP::isIPAddress( $this->getName() ) ) {
1808  $ip = $this->getName();
1809  } elseif ( !$ip ) {
1810  $ip = $this->getRequest()->getIP();
1811  }
1812  $blocked = false;
1813  wfRunHooks( 'UserIsBlockedGlobally', array( &$this, $ip, &$blocked ) );
1814  $this->mBlockedGlobally = (bool)$blocked;
1815  return $this->mBlockedGlobally;
1816  }
1817 
1823  public function isLocked() {
1824  if ( $this->mLocked !== null ) {
1825  return $this->mLocked;
1826  }
1827  global $wgAuth;
1828  StubObject::unstub( $wgAuth );
1829  $authUser = $wgAuth->getUserInstance( $this );
1830  $this->mLocked = (bool)$authUser->isLocked();
1831  return $this->mLocked;
1832  }
1833 
1839  public function isHidden() {
1840  if ( $this->mHideName !== null ) {
1841  return $this->mHideName;
1842  }
1843  $this->getBlockedStatus();
1844  if ( !$this->mHideName ) {
1845  global $wgAuth;
1846  StubObject::unstub( $wgAuth );
1847  $authUser = $wgAuth->getUserInstance( $this );
1848  $this->mHideName = (bool)$authUser->isHidden();
1849  }
1850  return $this->mHideName;
1851  }
1857  public function getId() {
1858  if ( $this->mId === null && $this->mName !== null && User::isIP( $this->mName ) ) {
1859  // Special case, we know the user is anonymous
1860  return 0;
1861  } elseif ( !$this->isItemLoaded( 'id' ) ) {
1862  // Don't load if this was initialized from an ID
1863  $this->load();
1864  }
1865  return $this->mId;
1866  }
1872  public function setId( $v ) {
1873  $this->mId = $v;
1874  $this->clearInstanceCache( 'id' );
1875  }
1881  public function getName() {
1882  if ( $this->isItemLoaded( 'name', 'only' ) ) {
1883  // Special case optimisation
1884  return $this->mName;
1885  } else {
1886  $this->load();
1887  if ( $this->mName === false ) {
1888  // Clean up IPs
1889  $this->mName = IP::sanitizeIP( $this->getRequest()->getIP() );
1890  }
1891  return $this->mName;
1892  }
1893  }
1894 
1908  public function setName( $str ) {
1909  $this->load();
1910  $this->mName = $str;
1911  }
1917  public function getTitleKey() {
1918  return str_replace( ' ', '_', $this->getName() );
1919  }
1925  public function getNewtalk() {
1926  $this->load();
1927 
1928  // Load the newtalk status if it is unloaded (mNewtalk=-1)
1929  if ( $this->mNewtalk === -1 ) {
1930  $this->mNewtalk = false; # reset talk page status
1931 
1932  // Check memcached separately for anons, who have no
1933  // entire User object stored in there.
1934  if ( !$this->mId ) {
1935  global $wgDisableAnonTalk;
1936  if ( $wgDisableAnonTalk ) {
1937  // Anon newtalk disabled by configuration.
1938  $this->mNewtalk = false;
1939  } else {
1940  global $wgMemc;
1941  $key = wfMemcKey( 'newtalk', 'ip', $this->getName() );
1942  $newtalk = $wgMemc->get( $key );
1943  if ( strval( $newtalk ) !== '' ) {
1944  $this->mNewtalk = (bool)$newtalk;
1945  } else {
1946  // Since we are caching this, make sure it is up to date by getting it
1947  // from the master
1948  $this->mNewtalk = $this->checkNewtalk( 'user_ip', $this->getName(), true );
1949  $wgMemc->set( $key, (int)$this->mNewtalk, 1800 );
1950  }
1951  }
1952  } else {
1953  $this->mNewtalk = $this->checkNewtalk( 'user_id', $this->mId );
1954  }
1955  }
1956 
1957  return (bool)$this->mNewtalk;
1958  }
1959 
1973  public function getNewMessageLinks() {
1974  $talks = array();
1975  if ( !wfRunHooks( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) {
1976  return $talks;
1977  } elseif ( !$this->getNewtalk() ) {
1978  return array();
1979  }
1980  $utp = $this->getTalkPage();
1981  $dbr = wfGetDB( DB_SLAVE );
1982  // Get the "last viewed rev" timestamp from the oldest message notification
1983  $timestamp = $dbr->selectField( 'user_newtalk',
1984  'MIN(user_last_timestamp)',
1985  $this->isAnon() ? array( 'user_ip' => $this->getName() ) : array( 'user_id' => $this->getID() ),
1986  __METHOD__ );
1988  return array( array( 'wiki' => wfWikiID(), 'link' => $utp->getLocalURL(), 'rev' => $rev ) );
1989  }
1990 
1996  public function getNewMessageRevisionId() {
1997  $newMessageRevisionId = null;
1998  $newMessageLinks = $this->getNewMessageLinks();
1999  if ( $newMessageLinks ) {
2000  // Note: getNewMessageLinks() never returns more than a single link
2001  // and it is always for the same wiki, but we double-check here in
2002  // case that changes some time in the future.
2003  if ( count( $newMessageLinks ) === 1
2004  && $newMessageLinks[0]['wiki'] === wfWikiID()
2005  && $newMessageLinks[0]['rev']
2006  ) {
2007  $newMessageRevision = $newMessageLinks[0]['rev'];
2008  $newMessageRevisionId = $newMessageRevision->getId();
2009  }
2010  }
2011  return $newMessageRevisionId;
2012  }
2013 
2023  protected function checkNewtalk( $field, $id, $fromMaster = false ) {
2024  if ( $fromMaster ) {
2025  $db = wfGetDB( DB_MASTER );
2026  } else {
2027  $db = wfGetDB( DB_SLAVE );
2028  }
2029  $ok = $db->selectField( 'user_newtalk', $field,
2030  array( $field => $id ), __METHOD__ );
2031  return $ok !== false;
2032  }
2033 
2041  protected function updateNewtalk( $field, $id, $curRev = null ) {
2042  // Get timestamp of the talk page revision prior to the current one
2043  $prevRev = $curRev ? $curRev->getPrevious() : false;
2044  $ts = $prevRev ? $prevRev->getTimestamp() : null;
2045  // Mark the user as having new messages since this revision
2046  $dbw = wfGetDB( DB_MASTER );
2047  $dbw->insert( 'user_newtalk',
2048  array( $field => $id, 'user_last_timestamp' => $dbw->timestampOrNull( $ts ) ),
2049  __METHOD__,
2050  'IGNORE' );
2051  if ( $dbw->affectedRows() ) {
2052  wfDebug( __METHOD__ . ": set on ($field, $id)\n" );
2053  return true;
2054  } else {
2055  wfDebug( __METHOD__ . " already set ($field, $id)\n" );
2056  return false;
2057  }
2058  }
2059 
2066  protected function deleteNewtalk( $field, $id ) {
2067  $dbw = wfGetDB( DB_MASTER );
2068  $dbw->delete( 'user_newtalk',
2069  array( $field => $id ),
2070  __METHOD__ );
2071  if ( $dbw->affectedRows() ) {
2072  wfDebug( __METHOD__ . ": killed on ($field, $id)\n" );
2073  return true;
2074  } else {
2075  wfDebug( __METHOD__ . ": already gone ($field, $id)\n" );
2076  return false;
2077  }
2078  }
2079 
2085  public function setNewtalk( $val, $curRev = null ) {
2086  if ( wfReadOnly() ) {
2087  return;
2088  }
2089 
2090  $this->load();
2091  $this->mNewtalk = $val;
2092 
2093  if ( $this->isAnon() ) {
2094  $field = 'user_ip';
2095  $id = $this->getName();
2096  } else {
2097  $field = 'user_id';
2098  $id = $this->getId();
2099  }
2100  global $wgMemc;
2101 
2102  if ( $val ) {
2103  $changed = $this->updateNewtalk( $field, $id, $curRev );
2104  } else {
2105  $changed = $this->deleteNewtalk( $field, $id );
2106  }
2107 
2108  if ( $this->isAnon() ) {
2109  // Anons have a separate memcached space, since
2110  // user records aren't kept for them.
2111  $key = wfMemcKey( 'newtalk', 'ip', $id );
2112  $wgMemc->set( $key, $val ? 1 : 0, 1800 );
2113  }
2114  if ( $changed ) {
2115  $this->invalidateCache();
2116  }
2117  }
2118 
2124  private static function newTouchedTimestamp() {
2125  global $wgClockSkewFudge;
2126  return wfTimestamp( TS_MW, time() + $wgClockSkewFudge );
2127  }
2128 
2136  private function clearSharedCache() {
2137  $this->load();
2138  if ( $this->mId ) {
2139  global $wgMemc;
2140  $wgMemc->delete( wfMemcKey( 'user', 'id', $this->mId ) );
2141  }
2142  }
2143 
2149  public function invalidateCache() {
2150  if ( wfReadOnly() ) {
2151  return;
2152  }
2153  $this->load();
2154  if ( $this->mId ) {
2155  $this->mTouched = self::newTouchedTimestamp();
2156 
2157  $dbw = wfGetDB( DB_MASTER );
2158  $userid = $this->mId;
2159  $touched = $this->mTouched;
2160  $method = __METHOD__;
2161  $dbw->onTransactionIdle( function() use ( $dbw, $userid, $touched, $method ) {
2162  // Prevent contention slams by checking user_touched first
2163  $encTouched = $dbw->addQuotes( $dbw->timestamp( $touched ) );
2164  $needsPurge = $dbw->selectField( 'user', '1',
2165  array( 'user_id' => $userid, 'user_touched < ' . $encTouched ) );
2166  if ( $needsPurge ) {
2167  $dbw->update( 'user',
2168  array( 'user_touched' => $dbw->timestamp( $touched ) ),
2169  array( 'user_id' => $userid, 'user_touched < ' . $encTouched ),
2170  $method
2171  );
2172  }
2173  } );
2174  $this->clearSharedCache();
2175  }
2176  }
2177 
2183  public function validateCache( $timestamp ) {
2184  $this->load();
2185  return ( $timestamp >= $this->mTouched );
2186  }
2192  public function getTouched() {
2193  $this->load();
2194  return $this->mTouched;
2195  }
2196 
2213  public function setPassword( $str ) {
2214  global $wgAuth;
2215 
2216  if ( $str !== null ) {
2217  if ( !$wgAuth->allowPasswordChange() ) {
2218  throw new PasswordError( wfMessage( 'password-change-forbidden' )->text() );
2219  }
2220 
2221  if ( !$this->isValidPassword( $str ) ) {
2222  global $wgMinimalPasswordLength;
2223  $valid = $this->getPasswordValidity( $str );
2224  if ( is_array( $valid ) ) {
2225  $message = array_shift( $valid );
2226  $params = $valid;
2227  } else {
2228  $message = $valid;
2229  $params = array( $wgMinimalPasswordLength );
2230  }
2231  throw new PasswordError( wfMessage( $message, $params )->text() );
2232  }
2233  }
2234 
2235  if ( !$wgAuth->setPassword( $this, $str ) ) {
2236  throw new PasswordError( wfMessage( 'externaldberror' )->text() );
2237  }
2238 
2239  $this->setInternalPassword( $str );
2240 
2241  return true;
2242  }
2243 
2251  public function setInternalPassword( $str ) {
2252  $this->load();
2253  $this->setToken();
2254 
2255  if ( $str === null ) {
2256  // Save an invalid hash...
2257  $this->mPassword = '';
2258  } else {
2259  $this->mPassword = self::crypt( $str );
2260  }
2261  $this->mNewpassword = '';
2262  $this->mNewpassTime = null;
2263  }
2264 
2270  public function getToken( $forceCreation = true ) {
2271  $this->load();
2272  if ( !$this->mToken && $forceCreation ) {
2273  $this->setToken();
2274  }
2275  return $this->mToken;
2276  }
2277 
2284  public function setToken( $token = false ) {
2285  $this->load();
2286  if ( !$token ) {
2287  $this->mToken = MWCryptRand::generateHex( USER_TOKEN_LENGTH );
2288  } else {
2289  $this->mToken = $token;
2290  }
2291  }
2292 
2300  public function setNewpassword( $str, $throttle = true ) {
2301  $this->load();
2302 
2303  if ( $str === null ) {
2304  $this->mNewpassword = '';
2305  $this->mNewpassTime = null;
2306  } else {
2307  $this->mNewpassword = self::crypt( $str );
2308  if ( $throttle ) {
2309  $this->mNewpassTime = wfTimestampNow();
2310  }
2311  }
2312  }
2313 
2319  public function isPasswordReminderThrottled() {
2320  global $wgPasswordReminderResendTime;
2321  $this->load();
2322  if ( !$this->mNewpassTime || !$wgPasswordReminderResendTime ) {
2323  return false;
2324  }
2325  $expiry = wfTimestamp( TS_UNIX, $this->mNewpassTime ) + $wgPasswordReminderResendTime * 3600;
2326  return time() < $expiry;
2327  }
2333  public function getEmail() {
2334  $this->load();
2335  wfRunHooks( 'UserGetEmail', array( $this, &$this->mEmail ) );
2336  return $this->mEmail;
2337  }
2343  public function getEmailAuthenticationTimestamp() {
2344  $this->load();
2345  wfRunHooks( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
2347  }
2353  public function setEmail( $str ) {
2354  $this->load();
2355  if ( $str == $this->mEmail ) {
2356  return;
2357  }
2358  $this->mEmail = $str;
2359  $this->invalidateEmail();
2360  wfRunHooks( 'UserSetEmail', array( $this, &$this->mEmail ) );
2361  }
2362 
2370  public function setEmailWithConfirmation( $str ) {
2371  global $wgEnableEmail, $wgEmailAuthentication;
2372 
2373  if ( !$wgEnableEmail ) {
2374  return Status::newFatal( 'emaildisabled' );
2375  }
2376 
2377  $oldaddr = $this->getEmail();
2378  if ( $str === $oldaddr ) {
2379  return Status::newGood( true );
2380  }
2381 
2382  $this->setEmail( $str );
2383 
2384  if ( $str !== '' && $wgEmailAuthentication ) {
2385  // Send a confirmation request to the new address if needed
2386  $type = $oldaddr != '' ? 'changed' : 'set';
2387  $result = $this->sendConfirmationMail( $type );
2388  if ( $result->isGood() ) {
2389  // Say the the caller that a confirmation mail has been sent
2390  $result->value = 'eauth';
2391  }
2392  } else {
2393  $result = Status::newGood( true );
2394  }
2395 
2396  return $result;
2397  }
2403  public function getRealName() {
2404  if ( !$this->isItemLoaded( 'realname' ) ) {
2405  $this->load();
2406  }
2407 
2408  return $this->mRealName;
2409  }
2415  public function setRealName( $str ) {
2416  $this->load();
2417  $this->mRealName = $str;
2418  }
2419 
2430  public function getOption( $oname, $defaultOverride = null, $ignoreHidden = false ) {
2431  global $wgHiddenPrefs;
2432  $this->loadOptions();
2433 
2434  # We want 'disabled' preferences to always behave as the default value for
2435  # users, even if they have set the option explicitly in their settings (ie they
2436  # set it, and then it was disabled removing their ability to change it). But
2437  # we don't want to erase the preferences in the database in case the preference
2438  # is re-enabled again. So don't touch $mOptions, just override the returned value
2439  if ( !$ignoreHidden && in_array( $oname, $wgHiddenPrefs ) ) {
2440  return self::getDefaultOption( $oname );
2441  }
2442 
2443  if ( array_key_exists( $oname, $this->mOptions ) ) {
2444  return $this->mOptions[$oname];
2445  } else {
2446  return $defaultOverride;
2447  }
2448  }
2449 
2455  public function getOptions() {
2456  global $wgHiddenPrefs;
2457  $this->loadOptions();
2459 
2460  # We want 'disabled' preferences to always behave as the default value for
2461  # users, even if they have set the option explicitly in their settings (ie they
2462  # set it, and then it was disabled removing their ability to change it). But
2463  # we don't want to erase the preferences in the database in case the preference
2464  # is re-enabled again. So don't touch $mOptions, just override the returned value
2465  foreach ( $wgHiddenPrefs as $pref ) {
2466  $default = self::getDefaultOption( $pref );
2467  if ( $default !== null ) {
2468  $options[$pref] = $default;
2469  }
2470  }
2471 
2472  return $options;
2473  }
2474 
2482  public function getBoolOption( $oname ) {
2483  return (bool)$this->getOption( $oname );
2484  }
2485 
2494  public function getIntOption( $oname, $defaultOverride = 0 ) {
2495  $val = $this->getOption( $oname );
2496  if ( $val == '' ) {
2497  $val = $defaultOverride;
2498  }
2499  return intval( $val );
2500  }
2501 
2508  public function setOption( $oname, $val ) {
2509  $this->loadOptions();
2510 
2511  // Explicitly NULL values should refer to defaults
2512  if ( is_null( $val ) ) {
2513  $val = self::getDefaultOption( $oname );
2514  }
2515 
2516  $this->mOptions[$oname] = $val;
2517  }
2518 
2528  public function getTokenFromOption( $oname ) {
2529  global $wgHiddenPrefs;
2530  if ( in_array( $oname, $wgHiddenPrefs ) ) {
2531  return false;
2532  }
2533 
2534  $token = $this->getOption( $oname );
2535  if ( !$token ) {
2536  $token = $this->resetTokenFromOption( $oname );
2537  $this->saveSettings();
2538  }
2539  return $token;
2540  }
2541 
2551  public function resetTokenFromOption( $oname ) {
2552  global $wgHiddenPrefs;
2553  if ( in_array( $oname, $wgHiddenPrefs ) ) {
2554  return false;
2555  }
2556 
2557  $token = MWCryptRand::generateHex( 40 );
2558  $this->setOption( $oname, $token );
2559  return $token;
2560  }
2561 
2585  public static function listOptionKinds() {
2586  return array(
2587  'registered',
2588  'registered-multiselect',
2589  'registered-checkmatrix',
2590  'userjs',
2591  'special',
2592  'unused'
2593  );
2594  }
2595 
2607  public function getOptionKinds( IContextSource $context, $options = null ) {
2608  $this->loadOptions();
2609  if ( $options === null ) {
2611  }
2612 
2613  $prefs = Preferences::getPreferences( $this, $context );
2614  $mapping = array();
2615 
2616  // Pull out the "special" options, so they don't get converted as
2617  // multiselect or checkmatrix.
2618  $specialOptions = array_fill_keys( Preferences::getSaveBlacklist(), true );
2619  foreach ( $specialOptions as $name => $value ) {
2620  unset( $prefs[$name] );
2621  }
2622 
2623  // Multiselect and checkmatrix options are stored in the database with
2624  // one key per option, each having a boolean value. Extract those keys.
2625  $multiselectOptions = array();
2626  foreach ( $prefs as $name => $info ) {
2627  if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) ||
2628  ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) {
2629  $opts = HTMLFormField::flattenOptions( $info['options'] );
2630  $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
2631 
2632  foreach ( $opts as $value ) {
2633  $multiselectOptions["$prefix$value"] = true;
2634  }
2635 
2636  unset( $prefs[$name] );
2637  }
2638  }
2639  $checkmatrixOptions = array();
2640  foreach ( $prefs as $name => $info ) {
2641  if ( ( isset( $info['type'] ) && $info['type'] == 'checkmatrix' ) ||
2642  ( isset( $info['class'] ) && $info['class'] == 'HTMLCheckMatrix' ) ) {
2643  $columns = HTMLFormField::flattenOptions( $info['columns'] );
2644  $rows = HTMLFormField::flattenOptions( $info['rows'] );
2645  $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
2646 
2647  foreach ( $columns as $column ) {
2648  foreach ( $rows as $row ) {
2649  $checkmatrixOptions["$prefix-$column-$row"] = true;
2650  }
2651  }
2652 
2653  unset( $prefs[$name] );
2654  }
2655  }
2656 
2657  // $value is ignored
2658  foreach ( $options as $key => $value ) {
2659  if ( isset( $prefs[$key] ) ) {
2660  $mapping[$key] = 'registered';
2661  } elseif ( isset( $multiselectOptions[$key] ) ) {
2662  $mapping[$key] = 'registered-multiselect';
2663  } elseif ( isset( $checkmatrixOptions[$key] ) ) {
2664  $mapping[$key] = 'registered-checkmatrix';
2665  } elseif ( isset( $specialOptions[$key] ) ) {
2666  $mapping[$key] = 'special';
2667  } elseif ( substr( $key, 0, 7 ) === 'userjs-' ) {
2668  $mapping[$key] = 'userjs';
2669  } else {
2670  $mapping[$key] = 'unused';
2671  }
2672  }
2673 
2674  return $mapping;
2675  }
2676 
2691  public function resetOptions(
2692  $resetKinds = array( 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused' ),
2693  IContextSource $context = null
2694  ) {
2695  $this->load();
2697 
2698  if ( !is_array( $resetKinds ) ) {
2699  $resetKinds = array( $resetKinds );
2700  }
2701 
2702  if ( in_array( 'all', $resetKinds ) ) {
2703  $newOptions = $defaultOptions;
2704  } else {
2705  if ( $context === null ) {
2706  $context = RequestContext::getMain();
2707  }
2708 
2709  $optionKinds = $this->getOptionKinds( $context );
2710  $resetKinds = array_intersect( $resetKinds, self::listOptionKinds() );
2711  $newOptions = array();
2712 
2713  // Use default values for the options that should be deleted, and
2714  // copy old values for the ones that shouldn't.
2715  foreach ( $this->mOptions as $key => $value ) {
2716  if ( in_array( $optionKinds[$key], $resetKinds ) ) {
2717  if ( array_key_exists( $key, $defaultOptions ) ) {
2718  $newOptions[$key] = $defaultOptions[$key];
2719  }
2720  } else {
2721  $newOptions[$key] = $value;
2722  }
2723  }
2724  }
2725 
2726  $this->mOptions = $newOptions;
2727  $this->mOptionsLoaded = true;
2728  }
2734  public function getDatePreference() {
2735  // Important migration for old data rows
2736  if ( is_null( $this->mDatePreference ) ) {
2737  global $wgLang;
2738  $value = $this->getOption( 'date' );
2739  $map = $wgLang->getDatePreferenceMigrationMap();
2740  if ( isset( $map[$value] ) ) {
2741  $value = $map[$value];
2742  }
2743  $this->mDatePreference = $value;
2744  }
2745  return $this->mDatePreference;
2746  }
2747 
2754  public function requiresHTTPS() {
2755  global $wgSecureLogin;
2756  if ( !$wgSecureLogin ) {
2757  return false;
2758  } else {
2759  $https = $this->getBoolOption( 'prefershttps' );
2760  wfRunHooks( 'UserRequiresHTTPS', array( $this, &$https ) );
2761  if ( $https ) {
2762  $https = wfCanIPUseHTTPS( $this->getRequest()->getIP() );
2763  }
2764  return $https;
2765  }
2766  }
2767 
2773  public function getStubThreshold() {
2774  global $wgMaxArticleSize; # Maximum article size, in Kb
2775  $threshold = $this->getIntOption( 'stubthreshold' );
2776  if ( $threshold > $wgMaxArticleSize * 1024 ) {
2777  // If they have set an impossible value, disable the preference
2778  // so we can use the parser cache again.
2779  $threshold = 0;
2780  }
2781  return $threshold;
2782  }
2788  public function getRights() {
2789  if ( is_null( $this->mRights ) ) {
2790  $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() );
2791  wfRunHooks( 'UserGetRights', array( $this, &$this->mRights ) );
2792  // Force reindexation of rights when a hook has unset one of them
2793  $this->mRights = array_values( array_unique( $this->mRights ) );
2794 
2795  // If block disables login, we should also remove any
2796  // extra rights blocked users might have, in case the
2797  // blocked user has a pre-existing session (T129738).
2798  // This is checked here for cases where people only call
2799  // $user->isAllowed(). It is also checked in Title::checkUserBlock()
2800  // to give a better error message in the common case.
2801  $config = RequestContext::getMain()->getConfig();
2802  if (
2803  $this->isLoggedIn() &&
2804  $config->get( 'BlockDisablesLogin' ) &&
2805  $this->isBlocked()
2806  ) {
2807  $anon = new User;
2808  $this->mRights = array_intersect( $this->mRights, $anon->getRights() );
2809  }
2810  }
2811  return $this->mRights;
2812  }
2813 
2819  public function getGroups() {
2820  $this->load();
2821  $this->loadGroups();
2822  return $this->mGroups;
2823  }
2824 
2832  public function getEffectiveGroups( $recache = false ) {
2833  if ( $recache || is_null( $this->mEffectiveGroups ) ) {
2834  wfProfileIn( __METHOD__ );
2835  $this->mEffectiveGroups = array_unique( array_merge(
2836  $this->getGroups(), // explicit groups
2837  $this->getAutomaticGroups( $recache ) // implicit groups
2838  ) );
2839  // Hook for additional groups
2840  wfRunHooks( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) );
2841  // Force reindexation of groups when a hook has unset one of them
2842  $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
2843  wfProfileOut( __METHOD__ );
2844  }
2845  return $this->mEffectiveGroups;
2846  }
2847 
2855  public function getAutomaticGroups( $recache = false ) {
2856  if ( $recache || is_null( $this->mImplicitGroups ) ) {
2857  wfProfileIn( __METHOD__ );
2858  $this->mImplicitGroups = array( '*' );
2859  if ( $this->getId() ) {
2860  $this->mImplicitGroups[] = 'user';
2861 
2862  $this->mImplicitGroups = array_unique( array_merge(
2863  $this->mImplicitGroups,
2865  ) );
2866  }
2867  if ( $recache ) {
2868  // Assure data consistency with rights/groups,
2869  // as getEffectiveGroups() depends on this function
2870  $this->mEffectiveGroups = null;
2871  }
2872  wfProfileOut( __METHOD__ );
2873  }
2874  return $this->mImplicitGroups;
2875  }
2876 
2886  public function getFormerGroups() {
2887  if ( is_null( $this->mFormerGroups ) ) {
2888  $dbr = wfGetDB( DB_MASTER );
2889  $res = $dbr->select( 'user_former_groups',
2890  array( 'ufg_group' ),
2891  array( 'ufg_user' => $this->mId ),
2892  __METHOD__ );
2893  $this->mFormerGroups = array();
2894  foreach ( $res as $row ) {
2895  $this->mFormerGroups[] = $row->ufg_group;
2896  }
2897  }
2898  return $this->mFormerGroups;
2899  }
2905  public function getEditCount() {
2906  if ( !$this->getId() ) {
2907  return null;
2908  }
2909 
2910  if ( !isset( $this->mEditCount ) ) {
2911  /* Populate the count, if it has not been populated yet */
2912  wfProfileIn( __METHOD__ );
2913  $dbr = wfGetDB( DB_SLAVE );
2914  // check if the user_editcount field has been initialized
2915  $count = $dbr->selectField(
2916  'user', 'user_editcount',
2917  array( 'user_id' => $this->mId ),
2918  __METHOD__
2919  );
2920 
2921  if ( $count === null ) {
2922  // it has not been initialized. do so.
2923  $count = $this->initEditCount();
2924  }
2925  $this->mEditCount = $count;
2926  wfProfileOut( __METHOD__ );
2927  }
2928  return (int)$this->mEditCount;
2929  }
2930 
2936  public function addGroup( $group ) {
2937  if ( wfRunHooks( 'UserAddGroup', array( $this, &$group ) ) ) {
2938  $dbw = wfGetDB( DB_MASTER );
2939  if ( $this->getId() ) {
2940  $dbw->insert( 'user_groups',
2941  array(
2942  'ug_user' => $this->getID(),
2943  'ug_group' => $group,
2944  ),
2945  __METHOD__,
2946  array( 'IGNORE' ) );
2947  }
2948  }
2949  $this->loadGroups();
2950  $this->mGroups[] = $group;
2951  // In case loadGroups was not called before, we now have the right twice.
2952  // Get rid of the duplicate.
2953  $this->mGroups = array_unique( $this->mGroups );
2954 
2955  // Refresh the groups caches, and clear the rights cache so it will be
2956  // refreshed on the next call to $this->getRights().
2957  $this->getEffectiveGroups( true );
2958  $this->mRights = null;
2959 
2960  $this->invalidateCache();
2961  }
2962 
2968  public function removeGroup( $group ) {
2969  $this->load();
2970  if ( wfRunHooks( 'UserRemoveGroup', array( $this, &$group ) ) ) {
2971  $dbw = wfGetDB( DB_MASTER );
2972  $dbw->delete( 'user_groups',
2973  array(
2974  'ug_user' => $this->getID(),
2975  'ug_group' => $group,
2976  ), __METHOD__ );
2977  // Remember that the user was in this group
2978  $dbw->insert( 'user_former_groups',
2979  array(
2980  'ufg_user' => $this->getID(),
2981  'ufg_group' => $group,
2982  ),
2983  __METHOD__,
2984  array( 'IGNORE' ) );
2985  }
2986  $this->loadGroups();
2987  $this->mGroups = array_diff( $this->mGroups, array( $group ) );
2988 
2989  // Refresh the groups caches, and clear the rights cache so it will be
2990  // refreshed on the next call to $this->getRights().
2991  $this->getEffectiveGroups( true );
2992  $this->mRights = null;
2993 
2994  $this->invalidateCache();
2995  }
3001  public function isLoggedIn() {
3002  return $this->getID() != 0;
3003  }
3009  public function isAnon() {
3010  return !$this->isLoggedIn();
3011  }
3012 
3021  public function isAllowedAny( /*...*/ ) {
3022  $permissions = func_get_args();
3023  foreach ( $permissions as $permission ) {
3024  if ( $this->isAllowed( $permission ) ) {
3025  return true;
3026  }
3027  }
3028  return false;
3029  }
3030 
3036  public function isAllowedAll( /*...*/ ) {
3037  $permissions = func_get_args();
3038  foreach ( $permissions as $permission ) {
3039  if ( !$this->isAllowed( $permission ) ) {
3040  return false;
3041  }
3042  }
3043  return true;
3044  }
3045 
3051  public function isAllowed( $action = '' ) {
3052  if ( $action === '' ) {
3053  return true; // In the spirit of DWIM
3054  }
3055  // Patrolling may not be enabled
3056  if ( $action === 'patrol' || $action === 'autopatrol' ) {
3057  global $wgUseRCPatrol, $wgUseNPPatrol;
3058  if ( !$wgUseRCPatrol && !$wgUseNPPatrol ) {
3059  return false;
3060  }
3061  }
3062  // Use strict parameter to avoid matching numeric 0 accidentally inserted
3063  // by misconfiguration: 0 == 'foo'
3064  return in_array( $action, $this->getRights(), true );
3065  }
3071  public function useRCPatrol() {
3072  global $wgUseRCPatrol;
3073  return $wgUseRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
3074  }
3080  public function useNPPatrol() {
3081  global $wgUseRCPatrol, $wgUseNPPatrol;
3082  return (
3083  ( $wgUseRCPatrol || $wgUseNPPatrol )
3084  && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
3085  );
3086  }
3087 
3093  public function getRequest() {
3094  if ( $this->mRequest ) {
3095  return $this->mRequest;
3096  } else {
3097  global $wgRequest;
3098  return $wgRequest;
3099  }
3100  }
3101 
3108  public function getSkin() {
3109  wfDeprecated( __METHOD__, '1.18' );
3110  return RequestContext::getMain()->getSkin();
3111  }
3112 
3122  public function getWatchedItem( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3123  $key = $checkRights . ':' . $title->getNamespace() . ':' . $title->getDBkey();
3124 
3125  if ( isset( $this->mWatchedItems[$key] ) ) {
3126  return $this->mWatchedItems[$key];
3127  }
3128 
3129  if ( count( $this->mWatchedItems ) >= self::MAX_WATCHED_ITEMS_CACHE ) {
3130  $this->mWatchedItems = array();
3131  }
3132 
3133  $this->mWatchedItems[$key] = WatchedItem::fromUserTitle( $this, $title, $checkRights );
3134  return $this->mWatchedItems[$key];
3135  }
3136 
3145  public function isWatched( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3146  return $this->getWatchedItem( $title, $checkRights )->isWatched();
3147  }
3148 
3156  public function addWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3157  $this->getWatchedItem( $title, $checkRights )->addWatch();
3158  $this->invalidateCache();
3159  }
3160 
3168  public function removeWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3169  $this->getWatchedItem( $title, $checkRights )->removeWatch();
3170  $this->invalidateCache();
3171  }
3172 
3181  public function clearNotification( &$title, $oldid = 0 ) {
3182  global $wgUseEnotif, $wgShowUpdatedMarker;
3183 
3184  // Do nothing if the database is locked to writes
3185  if ( wfReadOnly() ) {
3186  return;
3187  }
3188 
3189  // Do nothing if not allowed to edit the watchlist
3190  if ( !$this->isAllowed( 'editmywatchlist' ) ) {
3191  return;
3192  }
3193 
3194  // If we're working on user's talk page, we should update the talk page message indicator
3195  if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
3196  if ( !wfRunHooks( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
3197  return;
3198  }
3199 
3200  $nextid = $oldid ? $title->getNextRevisionID( $oldid ) : null;
3201 
3202  if ( !$oldid || !$nextid ) {
3203  // If we're looking at the latest revision, we should definitely clear it
3204  $this->setNewtalk( false );
3205  } else {
3206  // Otherwise we should update its revision, if it's present
3207  if ( $this->getNewtalk() ) {
3208  // Naturally the other one won't clear by itself
3209  $this->setNewtalk( false );
3210  $this->setNewtalk( true, Revision::newFromId( $nextid ) );
3211  }
3212  }
3213  }
3214 
3215  if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3216  return;
3217  }
3218 
3219  if ( $this->isAnon() ) {
3220  // Nothing else to do...
3221  return;
3222  }
3223 
3224  // Only update the timestamp if the page is being watched.
3225  // The query to find out if it is watched is cached both in memcached and per-invocation,
3226  // and when it does have to be executed, it can be on a slave
3227  // If this is the user's newtalk page, we always update the timestamp
3228  $force = '';
3229  if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
3230  $force = 'force';
3231  }
3232 
3233  $this->getWatchedItem( $title )->resetNotificationTimestamp( $force, $oldid );
3234  }
3235 
3242  public function clearAllNotifications() {
3243  if ( wfReadOnly() ) {
3244  return;
3245  }
3246 
3247  // Do nothing if not allowed to edit the watchlist
3248  if ( !$this->isAllowed( 'editmywatchlist' ) ) {
3249  return;
3250  }
3251 
3252  global $wgUseEnotif, $wgShowUpdatedMarker;
3253  if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3254  $this->setNewtalk( false );
3255  return;
3256  }
3257  $id = $this->getId();
3258  if ( $id != 0 ) {
3259  $dbw = wfGetDB( DB_MASTER );
3260  $dbw->update( 'watchlist',
3261  array( /* SET */ 'wl_notificationtimestamp' => null ),
3262  array( /* WHERE */ 'wl_user' => $id ),
3263  __METHOD__
3264  );
3265  // We also need to clear here the "you have new message" notification for the own user_talk page;
3266  // it's cleared one page view later in WikiPage::doViewUpdates().
3267  }
3268  }
3269 
3283  protected function setCookie( $name, $value, $exp = 0, $secure = null, $params = array() ) {
3284  $params['secure'] = $secure;
3285  $this->getRequest()->response()->setcookie( $name, $value, $exp, $params );
3286  }
3287 
3297  protected function clearCookie( $name, $secure = null, $params = array() ) {
3298  $this->setCookie( $name, '', time() - 86400, $secure, $params );
3299  }
3300 
3309  public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
3310  if ( $request === null ) {
3311  $request = $this->getRequest();
3312  }
3313 
3314  $this->load();
3315  if ( 0 == $this->mId ) {
3316  return;
3317  }
3318  if ( !$this->mToken ) {
3319  // When token is empty or NULL generate a new one and then save it to the database
3320  // This allows a wiki to re-secure itself after a leak of it's user table or $wgSecretKey
3321  // Simply by setting every cell in the user_token column to NULL and letting them be
3322  // regenerated as users log back into the wiki.
3323  $this->setToken();
3324  $this->saveSettings();
3325  }
3326  $session = array(
3327  'wsUserID' => $this->mId,
3328  'wsToken' => $this->mToken,
3329  'wsUserName' => $this->getName()
3330  );
3331  $cookies = array(
3332  'UserID' => $this->mId,
3333  'UserName' => $this->getName(),
3334  );
3335  if ( $rememberMe ) {
3336  $cookies['Token'] = $this->mToken;
3337  } else {
3338  $cookies['Token'] = false;
3339  }
3340 
3341  wfRunHooks( 'UserSetCookies', array( $this, &$session, &$cookies ) );
3342 
3343  foreach ( $session as $name => $value ) {
3344  $request->setSessionData( $name, $value );
3345  }
3346  foreach ( $cookies as $name => $value ) {
3347  if ( $value === false ) {
3348  $this->clearCookie( $name );
3349  } else {
3350  $this->setCookie( $name, $value, 0, $secure );
3351  }
3352  }
3353 
3361  if ( $request->getCheck( 'wpStickHTTPS' ) || $this->requiresHTTPS() ) {
3362  $this->setCookie(
3363  'forceHTTPS',
3364  'true',
3365  $rememberMe ? 0 : null,
3366  false,
3367  array( 'prefix' => '' ) // no prefix
3368  );
3369  }
3370  }
3371 
3375  public function logout() {
3376  if ( wfRunHooks( 'UserLogout', array( &$this ) ) ) {
3377  $this->doLogout();
3378  }
3379  }
3385  public function doLogout() {
3386  $this->clearInstanceCache( 'defaults' );
3387 
3388  $this->getRequest()->setSessionData( 'wsUserID', 0 );
3389  $this->getRequest()->setSessionData( 'wsEditToken', null );
3390 
3391  $this->clearCookie( 'UserID' );
3392  $this->clearCookie( 'Token' );
3393  $this->clearCookie( 'forceHTTPS', false, array( 'prefix' => '' ) );
3394 
3395  wfResetSessionID();
3396 
3397  // Remember when user logged out, to prevent seeing cached pages
3398  $this->setCookie( 'LoggedOut', time(), time() + 86400 );
3399  }
3405  public function saveSettings() {
3406  global $wgAuth;
3407 
3408  $this->load();
3409  if ( wfReadOnly() ) {
3410  return;
3411  }
3412  if ( 0 == $this->mId ) {
3413  return;
3414  }
3415 
3416  $this->mTouched = self::newTouchedTimestamp();
3417  if ( !$wgAuth->allowSetLocalPassword() ) {
3418  $this->mPassword = '';
3419  }
3420 
3421  $dbw = wfGetDB( DB_MASTER );
3422  $dbw->update( 'user',
3423  array( /* SET */
3424  'user_name' => $this->mName,
3425  'user_password' => $this->mPassword,
3426  'user_newpassword' => $this->mNewpassword,
3427  'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
3428  'user_real_name' => $this->mRealName,
3429  'user_email' => $this->mEmail,
3430  'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3431  'user_touched' => $dbw->timestamp( $this->mTouched ),
3432  'user_token' => strval( $this->mToken ),
3433  'user_email_token' => $this->mEmailToken,
3434  'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
3435  'user_password_expires' => $dbw->timestampOrNull( $this->mPasswordExpires ),
3436  ), array( /* WHERE */
3437  'user_id' => $this->mId
3438  ), __METHOD__
3439  );
3440 
3441  $this->saveOptions();
3442 
3443  wfRunHooks( 'UserSaveSettings', array( $this ) );
3444  $this->clearSharedCache();
3445  $this->getUserPage()->invalidateCache();
3446  }
3452  public function idForName() {
3453  $s = trim( $this->getName() );
3454  if ( $s === '' ) {
3455  return 0;
3456  }
3457 
3458  $dbr = wfGetDB( DB_SLAVE );
3459  $id = $dbr->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__ );
3460  if ( $id === false ) {
3461  $id = 0;
3462  }
3463  return $id;
3464  }
3465 
3482  public static function createNew( $name, $params = array() ) {
3483  $user = new User;
3484  $user->load();
3485  $user->setToken(); // init token
3486  if ( isset( $params['options'] ) ) {
3487  $user->mOptions = $params['options'] + (array)$user->mOptions;
3488  unset( $params['options'] );
3489  }
3490  $dbw = wfGetDB( DB_MASTER );
3491  $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
3492 
3493  $fields = array(
3494  'user_id' => $seqVal,
3495  'user_name' => $name,
3496  'user_password' => $user->mPassword,
3497  'user_newpassword' => $user->mNewpassword,
3498  'user_newpass_time' => $dbw->timestampOrNull( $user->mNewpassTime ),
3499  'user_email' => $user->mEmail,
3500  'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
3501  'user_real_name' => $user->mRealName,
3502  'user_token' => strval( $user->mToken ),
3503  'user_registration' => $dbw->timestamp( $user->mRegistration ),
3504  'user_editcount' => 0,
3505  'user_touched' => $dbw->timestamp( self::newTouchedTimestamp() ),
3506  );
3507  foreach ( $params as $name => $value ) {
3508  $fields["user_$name"] = $value;
3509  }
3510  $dbw->insert( 'user', $fields, __METHOD__, array( 'IGNORE' ) );
3511  if ( $dbw->affectedRows() ) {
3512  $newUser = User::newFromId( $dbw->insertId() );
3513  } else {
3514  $newUser = null;
3515  }
3516  return $newUser;
3517  }
3518 
3545  public function addToDatabase() {
3546  $this->load();
3547  if ( !$this->mToken ) {
3548  $this->setToken(); // init token
3549  }
3550 
3551  $this->mTouched = self::newTouchedTimestamp();
3552 
3553  $dbw = wfGetDB( DB_MASTER );
3554  $inWrite = $dbw->writesOrCallbacksPending();
3555  $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
3556  $dbw->insert( 'user',
3557  array(
3558  'user_id' => $seqVal,
3559  'user_name' => $this->mName,
3560  'user_password' => $this->mPassword,
3561  'user_newpassword' => $this->mNewpassword,
3562  'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
3563  'user_email' => $this->mEmail,
3564  'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3565  'user_real_name' => $this->mRealName,
3566  'user_token' => strval( $this->mToken ),
3567  'user_registration' => $dbw->timestamp( $this->mRegistration ),
3568  'user_editcount' => 0,
3569  'user_touched' => $dbw->timestamp( $this->mTouched ),
3570  ), __METHOD__,
3571  array( 'IGNORE' )
3572  );
3573  if ( !$dbw->affectedRows() ) {
3574  if ( !$inWrite ) {
3575  // XXX: Get out of REPEATABLE-READ so the SELECT below works.
3576  // Often this case happens early in views before any writes.
3577  // This shows up at least with CentralAuth.
3578  $dbw->commit( __METHOD__, 'flush' );
3579  }
3580  $this->mId = $dbw->selectField( 'user', 'user_id',
3581  array( 'user_name' => $this->mName ), __METHOD__ );
3582  $loaded = false;
3583  if ( $this->mId ) {
3584  if ( $this->loadFromDatabase() ) {
3585  $loaded = true;
3586  }
3587  }
3588  if ( !$loaded ) {
3589  throw new MWException( __METHOD__ . ": hit a key conflict attempting " .
3590  "to insert user '{$this->mName}' row, but it was not present in select!" );
3591  }
3592  return Status::newFatal( 'userexists' );
3593  }
3594  $this->mId = $dbw->insertId();
3595 
3596  // Clear instance cache other than user table data, which is already accurate
3597  $this->clearInstanceCache();
3598 
3599  $this->saveOptions();
3600  return Status::newGood();
3601  }
3602 
3608  public function spreadAnyEditBlock() {
3609  if ( $this->isLoggedIn() && $this->isBlocked() ) {
3610  return $this->spreadBlock();
3611  }
3612  return false;
3613  }
3614 
3620  protected function spreadBlock() {
3621  wfDebug( __METHOD__ . "()\n" );
3622  $this->load();
3623  if ( $this->mId == 0 ) {
3624  return false;
3625  }
3626 
3627  $userblock = Block::newFromTarget( $this->getName() );
3628  if ( !$userblock ) {
3629  return false;
3630  }
3631 
3632  return (bool)$userblock->doAutoblock( $this->getRequest()->getIP() );
3633  }
3639  public function isBlockedFromCreateAccount() {
3640  $this->getBlockedStatus();
3641  if ( $this->mBlock && $this->mBlock->prevents( 'createaccount' ) ) {
3642  return $this->mBlock;
3643  }
3644 
3645  # bug 13611: if the IP address the user is trying to create an account from is
3646  # blocked with createaccount disabled, prevent new account creation there even
3647  # when the user is logged in
3648  if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
3649  $this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
3650  }
3651  return $this->mBlockedFromCreateAccount instanceof Block && $this->mBlockedFromCreateAccount->prevents( 'createaccount' )
3652  ? $this->mBlockedFromCreateAccount
3653  : false;
3654  }
3660  public function isBlockedFromEmailuser() {
3661  $this->getBlockedStatus();
3662  return $this->mBlock && $this->mBlock->prevents( 'sendemail' );
3663  }
3669  public function isAllowedToCreateAccount() {
3670  return $this->isAllowed( 'createaccount' ) && !$this->isBlockedFromCreateAccount();
3671  }
3672 
3678  public function getUserPage() {
3679  return Title::makeTitle( NS_USER, $this->getName() );
3680  }
3681 
3687  public function getTalkPage() {
3688  $title = $this->getUserPage();
3689  return $title->getTalkPage();
3690  }
3691 
3697  public function isNewbie() {
3698  return !$this->isAllowed( 'autoconfirmed' );
3699  }
3700 
3706  public function checkPassword( $password ) {
3707  global $wgAuth, $wgLegacyEncoding;
3708  $this->load();
3709 
3710  // Certain authentication plugins do NOT want to save
3711  // domain passwords in a mysql database, so we should
3712  // check this (in case $wgAuth->strict() is false).
3713 
3714  if ( $wgAuth->authenticate( $this->getName(), $password ) ) {
3715  return true;
3716  } elseif ( $wgAuth->strict() ) {
3717  // Auth plugin doesn't allow local authentication
3718  return false;
3719  } elseif ( $wgAuth->strictUserAuth( $this->getName() ) ) {
3720  // Auth plugin doesn't allow local authentication for this user name
3721  return false;
3722  }
3723  if ( self::comparePasswords( $this->mPassword, $password, $this->mId ) ) {
3724  return true;
3725  } elseif ( $wgLegacyEncoding ) {
3726  // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
3727  // Check for this with iconv
3728  $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
3729  if ( $cp1252Password != $password
3730  && self::comparePasswords( $this->mPassword, $cp1252Password, $this->mId )
3731  ) {
3732  return true;
3733  }
3734  }
3735  return false;
3736  }
3737 
3746  public function checkTemporaryPassword( $plaintext ) {
3747  global $wgNewPasswordExpiry;
3748 
3749  $this->load();
3750  if ( self::comparePasswords( $this->mNewpassword, $plaintext, $this->getId() ) ) {
3751  if ( is_null( $this->mNewpassTime ) ) {
3752  return true;
3753  }
3754  $expiry = wfTimestamp( TS_UNIX, $this->mNewpassTime ) + $wgNewPasswordExpiry;
3755  return ( time() < $expiry );
3756  } else {
3757  return false;
3758  }
3759  }
3760 
3769  public function editToken( $salt = '', $request = null ) {
3770  wfDeprecated( __METHOD__, '1.19' );
3771  return $this->getEditToken( $salt, $request );
3772  }
3773 
3786  public function getEditToken( $salt = '', $request = null ) {
3787  if ( $request == null ) {
3788  $request = $this->getRequest();
3789  }
3790 
3791  if ( $this->isAnon() ) {
3792  return EDIT_TOKEN_SUFFIX;
3793  } else {
3794  $token = $request->getSessionData( 'wsEditToken' );
3795  if ( $token === null ) {
3796  $token = MWCryptRand::generateHex( 32 );
3797  $request->setSessionData( 'wsEditToken', $token );
3798  }
3799  if ( is_array( $salt ) ) {
3800  $salt = implode( '|', $salt );
3801  }
3802  return md5( $token . $salt ) . EDIT_TOKEN_SUFFIX;
3803  }
3804  }
3805 
3812  public static function generateToken() {
3813  return MWCryptRand::generateHex( 32 );
3814  }
3815 
3827  public function matchEditToken( $val, $salt = '', $request = null ) {
3828  $sessionToken = $this->getEditToken( $salt, $request );
3829  $equals = hash_equals( $sessionToken, $val );
3830  if ( !$equals ) {
3831  wfDebug( "User::matchEditToken: broken session data\n" );
3832  }
3833  return $equals;
3834  }
3835 
3845  public function matchEditTokenNoSuffix( $val, $salt = '', $request = null ) {
3846  $sessionToken = $this->getEditToken( $salt, $request );
3847  return hash_equals( substr( $sessionToken, 0, 32 ), substr( $val, 0, 32 ) );
3848  }
3849 
3857  public function sendConfirmationMail( $type = 'created' ) {
3858  global $wgLang;
3859  $expiration = null; // gets passed-by-ref and defined in next line.
3860  $token = $this->confirmationToken( $expiration );
3861  $url = $this->confirmationTokenUrl( $token );
3862  $invalidateURL = $this->invalidationTokenUrl( $token );
3863  $this->saveSettings();
3864 
3865  if ( $type == 'created' || $type === false ) {
3866  $message = 'confirmemail_body';
3867  } elseif ( $type === true ) {
3868  $message = 'confirmemail_body_changed';
3869  } else {
3870  // Messages: confirmemail_body_changed, confirmemail_body_set
3871  $message = 'confirmemail_body_' . $type;
3872  }
3873 
3874  return $this->sendMail( wfMessage( 'confirmemail_subject' )->text(),
3875  wfMessage( $message,
3876  $this->getRequest()->getIP(),
3877  $this->getName(),
3878  $url,
3879  $wgLang->timeanddate( $expiration, false ),
3880  $invalidateURL,
3881  $wgLang->date( $expiration, false ),
3882  $wgLang->time( $expiration, false ) )->text() );
3883  }
3884 
3895  public function sendMail( $subject, $body, $from = null, $replyto = null ) {
3896  if ( is_null( $from ) ) {
3897  global $wgPasswordSender;
3898  $sender = new MailAddress( $wgPasswordSender,
3899  wfMessage( 'emailsender' )->inContentLanguage()->text() );
3900  } else {
3901  $sender = new MailAddress( $from );
3902  }
3903 
3904  $to = new MailAddress( $this );
3905  return UserMailer::send( $to, $sender, $subject, $body, $replyto );
3906  }
3907 
3918  protected function confirmationToken( &$expiration ) {
3919  global $wgUserEmailConfirmationTokenExpiry;
3920  $now = time();
3921  $expires = $now + $wgUserEmailConfirmationTokenExpiry;
3922  $expiration = wfTimestamp( TS_MW, $expires );
3923  $this->load();
3924  $token = MWCryptRand::generateHex( 32 );
3925  $hash = md5( $token );
3926  $this->mEmailToken = $hash;
3927  $this->mEmailTokenExpires = $expiration;
3928  return $token;
3929  }
3930 
3936  protected function confirmationTokenUrl( $token ) {
3937  return $this->getTokenUrl( 'ConfirmEmail', $token );
3938  }
3939 
3945  protected function invalidationTokenUrl( $token ) {
3946  return $this->getTokenUrl( 'InvalidateEmail', $token );
3947  }
3948 
3963  protected function getTokenUrl( $page, $token ) {
3964  // Hack to bypass localization of 'Special:'
3965  $title = Title::makeTitle( NS_MAIN, "Special:$page/$token" );
3966  return $title->getCanonicalURL();
3967  }
3968 
3976  public function confirmEmail() {
3977  // Check if it's already confirmed, so we don't touch the database
3978  // and fire the ConfirmEmailComplete hook on redundant confirmations.
3979  if ( !$this->isEmailConfirmed() ) {
3981  wfRunHooks( 'ConfirmEmailComplete', array( $this ) );
3982  }
3983  return true;
3984  }
3985 
3993  public function invalidateEmail() {
3994  $this->load();
3995  $this->mEmailToken = null;
3996  $this->mEmailTokenExpires = null;
3997  $this->setEmailAuthenticationTimestamp( null );
3998  wfRunHooks( 'InvalidateEmailComplete', array( $this ) );
3999  return true;
4000  }
4006  public function setEmailAuthenticationTimestamp( $timestamp ) {
4007  $this->load();
4008  $this->mEmailAuthenticated = $timestamp;
4009  wfRunHooks( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
4010  }
4011 
4017  public function canSendEmail() {
4018  global $wgEnableEmail, $wgEnableUserEmail;
4019  if ( !$wgEnableEmail || !$wgEnableUserEmail || !$this->isAllowed( 'sendemail' ) ) {
4020  return false;
4021  }
4022  $canSend = $this->isEmailConfirmed();
4023  wfRunHooks( 'UserCanSendEmail', array( &$this, &$canSend ) );
4024  return $canSend;
4025  }
4026 
4032  public function canReceiveEmail() {
4033  return $this->isEmailConfirmed() && !$this->getOption( 'disablemail' );
4034  }
4035 
4046  public function isEmailConfirmed() {
4047  global $wgEmailAuthentication;
4048  $this->load();
4049  $confirmed = true;
4050  if ( wfRunHooks( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
4051  if ( $this->isAnon() ) {
4052  return false;
4053  }
4054  if ( !Sanitizer::validateEmail( $this->mEmail ) ) {
4055  return false;
4056  }
4057  if ( $wgEmailAuthentication && !$this->getEmailAuthenticationTimestamp() ) {
4058  return false;
4059  }
4060  return true;
4061  } else {
4062  return $confirmed;
4063  }
4064  }
4070  public function isEmailConfirmationPending() {
4071  global $wgEmailAuthentication;
4072  return $wgEmailAuthentication &&
4073  !$this->isEmailConfirmed() &&
4074  $this->mEmailToken &&
4075  $this->mEmailTokenExpires > wfTimestamp();
4076  }
4077 
4085  public function getRegistration() {
4086  if ( $this->isAnon() ) {
4087  return false;
4088  }
4089  $this->load();
4090  return $this->mRegistration;
4091  }
4092 
4099  public function getFirstEditTimestamp() {
4100  if ( $this->getId() == 0 ) {
4101  return false; // anons
4102  }
4103  $dbr = wfGetDB( DB_SLAVE );
4104  $time = $dbr->selectField( 'revision', 'rev_timestamp',
4105  array( 'rev_user' => $this->getId() ),
4106  __METHOD__,
4107  array( 'ORDER BY' => 'rev_timestamp ASC' )
4108  );
4109  if ( !$time ) {
4110  return false; // no edits
4111  }
4112  return wfTimestamp( TS_MW, $time );
4113  }
4114 
4121  public static function getGroupPermissions( $groups ) {
4122  global $wgGroupPermissions, $wgRevokePermissions;
4123  $rights = array();
4124  // grant every granted permission first
4125  foreach ( $groups as $group ) {
4126  if ( isset( $wgGroupPermissions[$group] ) ) {
4127  $rights = array_merge( $rights,
4128  // array_filter removes empty items
4129  array_keys( array_filter( $wgGroupPermissions[$group] ) ) );
4130  }
4131  }
4132  // now revoke the revoked permissions
4133  foreach ( $groups as $group ) {
4134  if ( isset( $wgRevokePermissions[$group] ) ) {
4135  $rights = array_diff( $rights,
4136  array_keys( array_filter( $wgRevokePermissions[$group] ) ) );
4137  }
4138  }
4139  return array_unique( $rights );
4140  }
4141 
4148  public static function getGroupsWithPermission( $role ) {
4149  global $wgGroupPermissions;
4150  $allowedGroups = array();
4151  foreach ( array_keys( $wgGroupPermissions ) as $group ) {
4152  if ( self::groupHasPermission( $group, $role ) ) {
4153  $allowedGroups[] = $group;
4154  }
4155  }
4156  return $allowedGroups;
4157  }
4158 
4171  public static function groupHasPermission( $group, $role ) {
4172  global $wgGroupPermissions, $wgRevokePermissions;
4173  return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
4174  && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
4175  }
4176 
4184  public static function isEveryoneAllowed( $right ) {
4185  global $wgGroupPermissions, $wgRevokePermissions;
4186  static $cache = array();
4187 
4188  // Use the cached results, except in unit tests which rely on
4189  // being able change the permission mid-request
4190  if ( isset( $cache[$right] ) && !defined( 'MW_PHPUNIT_TEST' ) ) {
4191  return $cache[$right];
4192  }
4193 
4194  if ( !isset( $wgGroupPermissions['*'][$right] ) || !$wgGroupPermissions['*'][$right] ) {
4195  $cache[$right] = false;
4196  return false;
4197  }
4198 
4199  // If it's revoked anywhere, then everyone doesn't have it
4200  foreach ( $wgRevokePermissions as $rights ) {
4201  if ( isset( $rights[$right] ) && $rights[$right] ) {
4202  $cache[$right] = false;
4203  return false;
4204  }
4205  }
4206 
4207  // Allow extensions (e.g. OAuth) to say false
4208  if ( !wfRunHooks( 'UserIsEveryoneAllowed', array( $right ) ) ) {
4209  $cache[$right] = false;
4210  return false;
4211  }
4212 
4213  $cache[$right] = true;
4214  return true;
4215  }
4216 
4223  public static function getGroupName( $group ) {
4224  $msg = wfMessage( "group-$group" );
4225  return $msg->isBlank() ? $group : $msg->text();
4226  }
4227 
4235  public static function getGroupMember( $group, $username = '#' ) {
4236  $msg = wfMessage( "group-$group-member", $username );
4237  return $msg->isBlank() ? $group : $msg->text();
4238  }
4239 
4246  public static function getAllGroups() {
4247  global $wgGroupPermissions, $wgRevokePermissions;
4248  return array_diff(
4249  array_merge( array_keys( $wgGroupPermissions ), array_keys( $wgRevokePermissions ) ),
4250  self::getImplicitGroups()
4251  );
4252  }
4258  public static function getAllRights() {
4259  if ( self::$mAllRights === false ) {
4260  global $wgAvailableRights;
4261  if ( count( $wgAvailableRights ) ) {
4262  self::$mAllRights = array_unique( array_merge( self::$mCoreRights, $wgAvailableRights ) );
4263  } else {
4264  self::$mAllRights = self::$mCoreRights;
4265  }
4266  wfRunHooks( 'UserGetAllRights', array( &self::$mAllRights ) );
4267  }
4268  return self::$mAllRights;
4269  }
4275  public static function getImplicitGroups() {
4276  global $wgImplicitGroups;
4277  $groups = $wgImplicitGroups;
4278  wfRunHooks( 'UserGetImplicitGroups', array( &$groups ) ); #deprecated, use $wgImplictGroups instead
4279  return $groups;
4280  }
4281 
4288  public static function getGroupPage( $group ) {
4289  $msg = wfMessage( 'grouppage-' . $group )->inContentLanguage();
4290  if ( $msg->exists() ) {
4291  $title = Title::newFromText( $msg->text() );
4292  if ( is_object( $title ) ) {
4293  return $title;
4294  }
4295  }
4296  return false;
4297  }
4298 
4307  public static function makeGroupLinkHTML( $group, $text = '' ) {
4308  if ( $text == '' ) {
4309  $text = self::getGroupName( $group );
4310  }
4311  $title = self::getGroupPage( $group );
4312  if ( $title ) {
4313  return Linker::link( $title, htmlspecialchars( $text ) );
4314  } else {
4315  return $text;
4316  }
4317  }
4318 
4327  public static function makeGroupLinkWiki( $group, $text = '' ) {
4328  if ( $text == '' ) {
4329  $text = self::getGroupName( $group );
4330  }
4331  $title = self::getGroupPage( $group );
4332  if ( $title ) {
4333  $page = $title->getPrefixedText();
4334  return "[[$page|$text]]";
4335  } else {
4336  return $text;
4337  }
4338  }
4339 
4349  public static function changeableByGroup( $group ) {
4350  global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
4351 
4352  $groups = array( 'add' => array(), 'remove' => array(), 'add-self' => array(), 'remove-self' => array() );
4353  if ( empty( $wgAddGroups[$group] ) ) {
4354  // Don't add anything to $groups
4355  } elseif ( $wgAddGroups[$group] === true ) {
4356  // You get everything
4357  $groups['add'] = self::getAllGroups();
4358  } elseif ( is_array( $wgAddGroups[$group] ) ) {
4359  $groups['add'] = $wgAddGroups[$group];
4360  }
4361 
4362  // Same thing for remove
4363  if ( empty( $wgRemoveGroups[$group] ) ) {
4364  } elseif ( $wgRemoveGroups[$group] === true ) {
4365  $groups['remove'] = self::getAllGroups();
4366  } elseif ( is_array( $wgRemoveGroups[$group] ) ) {
4367  $groups['remove'] = $wgRemoveGroups[$group];
4368  }
4369 
4370  // Re-map numeric keys of AddToSelf/RemoveFromSelf to the 'user' key for backwards compatibility
4371  if ( empty( $wgGroupsAddToSelf['user'] ) || $wgGroupsAddToSelf['user'] !== true ) {
4372  foreach ( $wgGroupsAddToSelf as $key => $value ) {
4373  if ( is_int( $key ) ) {
4374  $wgGroupsAddToSelf['user'][] = $value;
4375  }
4376  }
4377  }
4378 
4379  if ( empty( $wgGroupsRemoveFromSelf['user'] ) || $wgGroupsRemoveFromSelf['user'] !== true ) {
4380  foreach ( $wgGroupsRemoveFromSelf as $key => $value ) {
4381  if ( is_int( $key ) ) {
4382  $wgGroupsRemoveFromSelf['user'][] = $value;
4383  }
4384  }
4385  }
4386 
4387  // Now figure out what groups the user can add to him/herself
4388  if ( empty( $wgGroupsAddToSelf[$group] ) ) {
4389  } elseif ( $wgGroupsAddToSelf[$group] === true ) {
4390  // No idea WHY this would be used, but it's there
4391  $groups['add-self'] = User::getAllGroups();
4392  } elseif ( is_array( $wgGroupsAddToSelf[$group] ) ) {
4393  $groups['add-self'] = $wgGroupsAddToSelf[$group];
4394  }
4395 
4396  if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
4397  } elseif ( $wgGroupsRemoveFromSelf[$group] === true ) {
4398  $groups['remove-self'] = User::getAllGroups();
4399  } elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {
4400  $groups['remove-self'] = $wgGroupsRemoveFromSelf[$group];
4401  }
4402 
4403  return $groups;
4404  }
4405 
4413  public function changeableGroups() {
4414  if ( $this->isAllowed( 'userrights' ) ) {
4415  // This group gives the right to modify everything (reverse-
4416  // compatibility with old "userrights lets you change
4417  // everything")
4418  // Using array_merge to make the groups reindexed
4419  $all = array_merge( User::getAllGroups() );
4420  return array(
4421  'add' => $all,
4422  'remove' => $all,
4423  'add-self' => array(),
4424  'remove-self' => array()
4425  );
4426  }
4427 
4428  // Okay, it's not so simple, we will have to go through the arrays
4429  $groups = array(
4430  'add' => array(),
4431  'remove' => array(),
4432  'add-self' => array(),
4433  'remove-self' => array()
4434  );
4435  $addergroups = $this->getEffectiveGroups();
4436 
4437  foreach ( $addergroups as $addergroup ) {
4438  $groups = array_merge_recursive(
4439  $groups, $this->changeableByGroup( $addergroup )
4440  );
4441  $groups['add'] = array_unique( $groups['add'] );
4442  $groups['remove'] = array_unique( $groups['remove'] );
4443  $groups['add-self'] = array_unique( $groups['add-self'] );
4444  $groups['remove-self'] = array_unique( $groups['remove-self'] );
4445  }
4446  return $groups;
4447  }
4453  public function incEditCount() {
4454  if ( !$this->isAnon() ) {
4455  $dbw = wfGetDB( DB_MASTER );
4456  $dbw->update(
4457  'user',
4458  array( 'user_editcount=user_editcount+1' ),
4459  array( 'user_id' => $this->getId() ),
4460  __METHOD__
4461  );
4462 
4463  // Lazy initialization check...
4464  if ( $dbw->affectedRows() == 0 ) {
4465  // Now here's a goddamn hack...
4466  $dbr = wfGetDB( DB_SLAVE );
4467  if ( $dbr !== $dbw ) {
4468  // If we actually have a slave server, the count is
4469  // at least one behind because the current transaction
4470  // has not been committed and replicated.
4471  $this->initEditCount( 1 );
4472  } else {
4473  // But if DB_SLAVE is selecting the master, then the
4474  // count we just read includes the revision that was
4475  // just added in the working transaction.
4476  $this->initEditCount();
4477  }
4478  }
4479  }
4480  // edit count in user cache too
4481  $this->invalidateCache();
4482  }
4483 
4490  protected function initEditCount( $add = 0 ) {
4491  // Pull from a slave to be less cruel to servers
4492  // Accuracy isn't the point anyway here
4493  $dbr = wfGetDB( DB_SLAVE );
4494  $count = (int)$dbr->selectField(
4495  'revision',
4496  'COUNT(rev_user)',
4497  array( 'rev_user' => $this->getId() ),
4498  __METHOD__
4499  );
4500  $count = $count + $add;
4501 
4502  $dbw = wfGetDB( DB_MASTER );
4503  $dbw->update(
4504  'user',
4505  array( 'user_editcount' => $count ),
4506  array( 'user_id' => $this->getId() ),
4507  __METHOD__
4508  );
4509 
4510  return $count;
4511  }
4512 
4519  public static function getRightDescription( $right ) {
4520  $key = "right-$right";
4521  $msg = wfMessage( $key );
4522  return $msg->isBlank() ? $right : $msg->text();
4523  }
4524 
4532  public static function oldCrypt( $password, $userId ) {
4533  global $wgPasswordSalt;
4534  if ( $wgPasswordSalt ) {
4535  return md5( $userId . '-' . md5( $password ) );
4536  } else {
4537  return md5( $password );
4538  }
4539  }
4540 
4549  public static function crypt( $password, $salt = false ) {
4550  global $wgPasswordSalt;
4551 
4552  $hash = '';
4553  if ( !wfRunHooks( 'UserCryptPassword', array( &$password, &$salt, &$wgPasswordSalt, &$hash ) ) ) {
4554  return $hash;
4555  }
4556 
4557  if ( $wgPasswordSalt ) {
4558  if ( $salt === false ) {
4559  $salt = MWCryptRand::generateHex( 8 );
4560  }
4561  return ':B:' . $salt . ':' . md5( $salt . '-' . md5( $password ) );
4562  } else {
4563  return ':A:' . md5( $password );
4564  }
4565  }
4566 
4577  public static function comparePasswords( $hash, $password, $userId = false ) {
4578  $type = substr( $hash, 0, 3 );
4579 
4580  $result = false;
4581  if ( !wfRunHooks( 'UserComparePasswords', array( &$hash, &$password, &$userId, &$result ) ) ) {
4582  return $result;
4583  }
4584 
4585  if ( $type == ':A:' ) {
4586  // Unsalted
4587  return md5( $password ) === substr( $hash, 3 );
4588  } elseif ( $type == ':B:' ) {
4589  // Salted
4590  list( $salt, $realHash ) = explode( ':', substr( $hash, 3 ), 2 );
4591  return md5( $salt . '-' . md5( $password ) ) === $realHash;
4592  } else {
4593  // Old-style
4594  return self::oldCrypt( $password, $userId ) === $hash;
4595  }
4596  }
4597 
4619  public function addNewUserLogEntry( $action = false, $reason = '' ) {
4620  global $wgUser, $wgNewUserLog;
4621  if ( empty( $wgNewUserLog ) ) {
4622  return true; // disabled
4623  }
4624 
4625  if ( $action === true ) {
4626  $action = 'byemail';
4627  } elseif ( $action === false ) {
4628  if ( $this->getName() == $wgUser->getName() ) {
4629  $action = 'create';
4630  } else {
4631  $action = 'create2';
4632  }
4633  }
4634 
4635  if ( $action === 'create' || $action === 'autocreate' ) {
4636  $performer = $this;
4637  } else {
4638  $performer = $wgUser;
4639  }
4640 
4641  $logEntry = new ManualLogEntry( 'newusers', $action );
4642  $logEntry->setPerformer( $performer );
4643  $logEntry->setTarget( $this->getUserPage() );
4644  $logEntry->setComment( $reason );
4645  $logEntry->setParameters( array(
4646  '4::userid' => $this->getId(),
4647  ) );
4648  $logid = $logEntry->insert();
4649 
4650  if ( $action !== 'autocreate' ) {
4651  $logEntry->publish( $logid );
4652  }
4653 
4654  return (int)$logid;
4655  }
4656 
4664  public function addNewUserLogEntryAutoCreate() {
4665  $this->addNewUserLogEntry( 'autocreate' );
4666 
4667  return true;
4668  }
4669 
4675  protected function loadOptions( $data = null ) {
4677 
4678  $this->load();
4679 
4680  if ( $this->mOptionsLoaded ) {
4681  return;
4682  }
4683 
4684  $this->mOptions = self::getDefaultOptions();
4685 
4686  if ( !$this->getId() ) {
4687  // For unlogged-in users, load language/variant options from request.
4688  // There's no need to do it for logged-in users: they can set preferences,
4689  // and handling of page content is done by $pageLang->getPreferredVariant() and such,
4690  // so don't override user's choice (especially when the user chooses site default).
4691  $variant = $wgContLang->getDefaultVariant();
4692  $this->mOptions['variant'] = $variant;
4693  $this->mOptions['language'] = $variant;
4694  $this->mOptionsLoaded = true;
4695  return;
4696  }
4697 
4698  // Maybe load from the object
4699  if ( !is_null( $this->mOptionOverrides ) ) {
4700  wfDebug( "User: loading options for user " . $this->getId() . " from override cache.\n" );
4701  foreach ( $this->mOptionOverrides as $key => $value ) {
4702  $this->mOptions[$key] = $value;
4703  }
4704  } else {
4705  if ( !is_array( $data ) ) {
4706  wfDebug( "User: loading options for user " . $this->getId() . " from database.\n" );
4707  // Load from database
4708  $dbr = wfGetDB( DB_SLAVE );
4709 
4710  $res = $dbr->select(
4711  'user_properties',
4712  array( 'up_property', 'up_value' ),
4713  array( 'up_user' => $this->getId() ),
4714  __METHOD__
4715  );
4716 
4717  $this->mOptionOverrides = array();
4718  $data = array();
4719  foreach ( $res as $row ) {
4720  $data[$row->up_property] = $row->up_value;
4721  }
4722  }
4723  foreach ( $data as $property => $value ) {
4724  $this->mOptionOverrides[$property] = $value;
4725  $this->mOptions[$property] = $value;
4726  }
4727  }
4728 
4729  $this->mOptionsLoaded = true;
4730 
4731  wfRunHooks( 'UserLoadOptions', array( $this, &$this->mOptions ) );
4732  }
4733 
4737  protected function saveOptions() {
4738  $this->loadOptions();
4739 
4740  // Not using getOptions(), to keep hidden preferences in database
4741  $saveOptions = $this->mOptions;
4742 
4743  // Allow hooks to abort, for instance to save to a global profile.
4744  // Reset options to default state before saving.
4745  if ( !wfRunHooks( 'UserSaveOptions', array( $this, &$saveOptions ) ) ) {
4746  return;
4747  }
4748 
4749  $userId = $this->getId();
4750  $insert_rows = array();
4751  foreach ( $saveOptions as $key => $value ) {
4752  // Don't bother storing default values
4753  $defaultOption = self::getDefaultOption( $key );
4754  if ( ( is_null( $defaultOption ) &&
4755  !( $value === false || is_null( $value ) ) ) ||
4756  $value != $defaultOption
4757  ) {
4758  $insert_rows[] = array(
4759  'up_user' => $userId,
4760  'up_property' => $key,
4761  'up_value' => $value,
4762  );
4763  }
4764  }
4765 
4766  $dbw = wfGetDB( DB_MASTER );
4767  // Find and delete any prior preference rows...
4768  $res = $dbw->select( 'user_properties',
4769  array( 'up_property' ), array( 'up_user' => $userId ), __METHOD__ );
4770  $priorKeys = array();
4771  foreach ( $res as $row ) {
4772  $priorKeys[] = $row->up_property;
4773  }
4774  if ( count( $priorKeys ) ) {
4775  // Do the DELETE by PRIMARY KEY for prior rows.
4776  // In the past a very large portion of calls to this function are for setting
4777  // 'rememberpassword' for new accounts (a preference that has since been removed).
4778  // Doing a blanket per-user DELETE for new accounts with no rows in the table
4779  // caused gap locks on [max user ID,+infinity) which caused high contention since
4780  // updates would pile up on each other as they are for higher (newer) user IDs.
4781  // It might not be necessary these days, but it shouldn't hurt either.
4782  $dbw->delete( 'user_properties',
4783  array( 'up_user' => $userId, 'up_property' => $priorKeys ), __METHOD__ );
4784  }
4785  // Insert the new preference rows
4786  $dbw->insert( 'user_properties', $insert_rows, __METHOD__, array( 'IGNORE' ) );
4787  }
4788 
4812  public static function passwordChangeInputAttribs() {
4813  global $wgMinimalPasswordLength;
4814 
4815  if ( $wgMinimalPasswordLength == 0 ) {
4816  return array();
4817  }
4818 
4819  # Note that the pattern requirement will always be satisfied if the
4820  # input is empty, so we need required in all cases.
4821  #
4822  # @todo FIXME: Bug 23769: This needs to not claim the password is required
4823  # if e-mail confirmation is being used. Since HTML5 input validation
4824  # is b0rked anyway in some browsers, just return nothing. When it's
4825  # re-enabled, fix this code to not output required for e-mail
4826  # registration.
4827  #$ret = array( 'required' );
4828  $ret = array();
4829 
4830  # We can't actually do this right now, because Opera 9.6 will print out
4831  # the entered password visibly in its error message! When other
4832  # browsers add support for this attribute, or Opera fixes its support,
4833  # we can add support with a version check to avoid doing this on Opera
4834  # versions where it will be a problem. Reported to Opera as
4835  # DSK-262266, but they don't have a public bug tracker for us to follow.
4836  /*
4837  if ( $wgMinimalPasswordLength > 1 ) {
4838  $ret['pattern'] = '.{' . intval( $wgMinimalPasswordLength ) . ',}';
4839  $ret['title'] = wfMessage( 'passwordtooshort' )
4840  ->numParams( $wgMinimalPasswordLength )->text();
4841  }
4842  */
4843 
4844  return $ret;
4845  }
4846 
4852  public static function selectFields() {
4853  return array(
4854  'user_id',
4855  'user_name',
4856  'user_real_name',
4857  'user_password',
4858  'user_newpassword',
4859  'user_newpass_time',
4860  'user_email',
4861  'user_touched',
4862  'user_token',
4863  'user_email_authenticated',
4864  'user_email_token',
4865  'user_email_token_expires',
4866  'user_password_expires',
4867  'user_registration',
4868  'user_editcount',
4869  );
4870  }
4871 
4879  static function newFatalPermissionDeniedStatus( $permission ) {
4880  global $wgLang;
4881 
4882  $groups = array_map(
4883  array( 'User', 'makeGroupLinkWiki' ),
4884  User::getGroupsWithPermission( $permission )
4885  );
4886 
4887  if ( $groups ) {
4888  return Status::newFatal( 'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
4889  } else {
4890  return Status::newFatal( 'badaccess-group0' );
4891  }
4892  }
4893 }
User\getDefaultOption
static getDefaultOption( $opt)
Get a given default option value.
Definition: User.php:1383
User\addWatch
addWatch( $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Watch an article.
Definition: User.php:3151
User\$mHash
$mHash
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\saveOptions
saveOptions()
Definition: User.php:4732
User\$mBlockreason
$mBlockreason
Bool Whether the cache variables have been loaded.
Definition: User.php:220
Block\prevents
prevents( $action, $x=null)
Get/set whether the Block prevents a given action.
Definition: Block.php:892
User\load
load()
Load the user table data for this object from the source given by mFrom.
Definition: User.php:270
User\passwordChangeInputAttribs
static passwordChangeInputAttribs()
Provide an array of HTML5 attributes to put on an input element intended for the user to enter a new ...
Definition: User.php:4807
User\loadFromId
loadFromId()
Load user table data, given mId has already been set.
Definition: User.php:313
Preferences\getPreferences
static getPreferences( $user, IContextSource $context)
Definition: Preferences.php:78
User\updateNewtalk
updateNewtalk( $field, $id, $curRev=null)
Add or update the new messages flag.
Definition: User.php:2036
User\$mEmailToken
$mEmailToken
Bool Whether the cache variables have been loaded.
Definition: User.php:186
Title\makeTitle
static & makeTitle( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:398
User\getNewtalk
getNewtalk()
Check if the user has new messages.
Definition: User.php:1920
User\addGroup
addGroup( $group)
Add the user to the given group.
Definition: User.php:2931
UserMailer\send
static send( $to, $from, $subject, $body, $replyto=null, $contentType='text/plain;charset=UTF-8')
This function will perform a direct (authenticated) login to a SMTP Server to use for mail relaying i...
Definition: UserMailer.php:163
User\$mOptionsLoaded
$mOptionsLoaded
Bool Whether the cache variables have been loaded.
Definition: User.php:198
$wgUser
$wgUser
Definition: Setup.php:572
User\inDnsBlacklist
inDnsBlacklist( $ip, $bases)
Whether the given IP is in a given DNS blacklist.
Definition: User.php:1514
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. $reader:XMLReader object $logInfo:Array of information Return false to stop further processing of the tag 'ImportHandlePageXMLTag':When parsing a XML tag in a page. $reader:XMLReader object $pageInfo:Array of information Return false to stop further processing of the tag 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information Return false to stop further processing of the tag 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. $reader:XMLReader object Return false to stop further processing of the tag 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. $reader:XMLReader object $revisionInfo:Array of information Return false to stop further processing of the tag 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. $title:Title object for the current page $request:WebRequest $ignoreRedirect:boolean to skip redirect check $target:Title/string of redirect target $article:Article object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) $article:article(object) being checked 'IsTrustedProxy':Override the result of wfIsTrustedProxy() $ip:IP being check $result:Change this value to override the result of wfIsTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of User::isValidEmailAddr(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetMagic':DEPRECATED, use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetSpecialPageAliases':DEPRECATED, use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Associative array mapping language codes to prefixed links of the form "language:title". & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LinkBegin':Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1528
User\newFromId
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition: User.php:412
Title\newFromText
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:189
User\$mEditCount
$mEditCount
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\confirmationTokenUrl
confirmationTokenUrl( $token)
Return a URL the user can use to confirm their email address.
Definition: User.php:3931
DB_MASTER
const DB_MASTER
Definition: Defines.php:56
$request
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled also a ContextSource error or success you ll probably need to make sure the header is varied on WebRequest $request
Definition: hooks.txt:1961
wfCanIPUseHTTPS
wfCanIPUseHTTPS( $ip)
Determine whether the client at a given source IP is likely to be able to access the wiki via HTTPS.
Definition: GlobalFunctions.php:4194
php
skin txt MediaWiki includes four core it has been set as the default in MediaWiki since the replacing Monobook it had been been the default skin since before being replaced by Vector largely rewritten in while keeping its appearance Several legacy skins were removed in the as the burden of supporting them became too heavy to bear Those in etc for skin dependent CSS etc for skin dependent JavaScript These can also be customised on a per user by etc This feature has led to a wide variety of user styles becoming that gallery is a good place to ending in php
Definition: skin.txt:62
User\isValidPassword
isValidPassword( $password)
Is the input a valid password for this user?
Definition: User.php:691
User\getId
getId()
Get the user's ID.
Definition: User.php:1852
Revision\newFromId
static newFromId( $id, $flags=0)
Load a page revision from a given revision ID number.
Definition: Revision.php:88
User\makeGroupLinkWiki
static makeGroupLinkWiki( $group, $text='')
Create a link to the group in Wikitext, if available; else return the group name.
Definition: User.php:4322
User\isAnon
isAnon()
Get whether the user is anonymous.
Definition: User.php:3004
User\$mBlock
Block $mBlock
Bool Whether the cache variables have been loaded.
Definition: User.php:230
User\$mEffectiveGroups
$mEffectiveGroups
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\getTokenUrl
getTokenUrl( $page, $token)
Internal function to format the e-mail validation/invalidation URLs.
Definition: User.php:3958
User\MAX_WATCHED_ITEMS_CACHE
const MAX_WATCHED_ITEMS_CACHE
Maximum items in $mWatchedItems.
Definition: User.php:71
User\isLocallyBlockedProxy
static isLocallyBlockedProxy( $ip)
Check if an IP address is in the local proxy list.
Definition: User.php:1561
User\resetTokenFromOption
resetTokenFromOption( $oname)
Reset a token stored in the preferences (like the watchlist one).
Definition: User.php:2546
User\loadFromUserObject
loadFromUserObject( $user)
Load the data for this user object from another user object.
Definition: User.php:1244
User\newFatalPermissionDeniedStatus
static newFatalPermissionDeniedStatus( $permission)
Factory function for fatal permission-denied errors.
Definition: User.php:4874
User\getPasswordExpireDate
getPasswordExpireDate()
Get this user's password expiration date.
Definition: User.php:834
User\isValidEmailAddr
static isValidEmailAddr( $addr)
Does a string look like an e-mail address?
Definition: User.php:866
User\getEditCount
getEditCount()
Get the user's edit count.
Definition: User.php:2900
User\spreadBlock
spreadBlock()
If this (non-anonymous) user is blocked, block the IP address they've successfully logged in from.
Definition: User.php:3615
User\incEditCount
incEditCount()
Increment the user's edit-count field.
Definition: User.php:4448
User\newFromSession
static newFromSession(WebRequest $request=null)
Create a new user object using data from session or cookies.
Definition: User.php:450
$wgMemc
globals will be eliminated from MediaWiki replaced by an application object which would be passed to constructors Whether that would be an convenient solution remains to be but certainly PHP makes such object oriented programming models easier than they were in previous versions For the time being MediaWiki programmers will have to work in an environment with some global context At the time of globals were initialised on startup by MediaWiki of these were configuration which are documented in DefaultSettings php There is no comprehensive documentation for the remaining however some of the most important ones are listed below They are typically initialised either in index php or in Setup php For a description of the see design txt $wgTitle Title object created from the request URL $wgOut OutputPage object for HTTP response $wgUser User object for the user associated with the current request $wgLang Language object selected by user preferences $wgContLang Language object associated with the wiki being viewed $wgParser Parser object Parser extensions register their hooks here $wgRequest WebRequest to get request data $wgMemc
Definition: globals.txt:25
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:2602
Block\chooseBlock
static chooseBlock(array $blocks, array $ipChain)
From a list of multiple blocks, find the most exact and strongest Block.
Definition: Block.php:1106
User\getBlock
getBlock( $bFromSlave=true)
Get the block affecting the user, or null if the user is not blocked.
Definition: User.php:1731
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3714
text
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add text
Definition: design.txt:12
User\isEmailConfirmationPending
isEmailConfirmationPending()
Check whether there is an outstanding request for e-mail confirmation.
Definition: User.php:4065
$timestamp
if( $limit) $timestamp
Definition: importImages.php:104
User\getBlockId
getBlockId()
If user is blocked, return the ID for the block.
Definition: User.php:1784
User\getIntOption
getIntOption( $oname, $defaultOverride=0)
Get the user's current setting for a given option, as an integer value.
Definition: User.php:2489
SearchEngine\searchableNamespaces
static searchableNamespaces()
Make a list of searchable namespaces and their canonical names.
Definition: SearchEngine.php:334
User\__construct
__construct()
Lightweight constructor for an anonymous user.
Definition: User.php:256
User\editToken
editToken( $salt='', $request=null)
Alias for getEditToken.
Definition: User.php:3764
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:2530
User\getToken
getToken( $forceCreation=true)
Get the user's current token.
Definition: User.php:2265
User\spreadAnyEditBlock
spreadAnyEditBlock()
If this user is logged-in and blocked, block any IP address they've successfully logged in from.
Definition: User.php:3603
User\$mEmail
$mEmail
Bool Whether the cache variables have been loaded.
Definition: User.php:186
wfDebugLog
wfDebugLog( $logGroup, $text, $dest='all')
Send a line to a supplementary debug log file, if configured, or main debug log if not.
Definition: GlobalFunctions.php:1087
User\getNewMessageRevisionId
getNewMessageRevisionId()
Get the revision ID for the last talk page revision viewed by the talk page owner.
Definition: User.php:1991
User\loadDefaults
loadDefaults( $name=false)
Set cached properties to default.
Definition: User.php:970
User\$mAllowUsertalk
bool $mAllowUsertalk
Bool Whether the cache variables have been loaded.
Definition: User.php:234
wfProfileIn
wfProfileIn( $functionname)
Begin profiling of a function.
Definition: Profiler.php:33
$defaultOptions
return false to override stock group addition can be modified try getUserPermissionsErrors userCan checks are continued by internal code can override on output return false to not delete it return false to override the default password checks this Boolean value will be checked to determine if the password was valid return false to implement your own hashing method this String will be used as the hash which may be added to this hook is run right before returning the options to the caller which means it s potentially called dozens or hundreds of times You may want to cache the results of non trivial operations in your hook function for this reason & $defaultOptions
Definition: hooks.txt:2708
User\$mNewtalk
$mNewtalk
Lazy-initialized variables, invalidated with clearInstanceCache.
Definition: User.php:220
User\loadOptions
loadOptions( $data=null)
Load the user options either from cache, the database or an array.
Definition: User.php:4670
User\makeGroupLinkHTML
static makeGroupLinkHTML( $group, $text='')
Create a link to the group in HTML, if available; else return the group name.
Definition: User.php:4302
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1530
$from
$from
Definition: importImages.php:90
User\setNewpassword
setNewpassword( $str, $throttle=true)
Set the password for a password reminder or new account email.
Definition: User.php:2295
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1358
Autopromote\getAutopromoteGroups
static getAutopromoteGroups(User $user)
Get the groups for the given user based on $wgAutopromote.
Definition: Autopromote.php:35
$right
return false if a UserGetRights hook might remove the named right $right
Definition: hooks.txt:2809
User\edits
static edits( $uid)
Count the number of edits of a user.
Definition: User.php:940
User\setEmailWithConfirmation
setEmailWithConfirmation( $str)
Set the user's e-mail address and a confirmation mail if needed.
Definition: User.php:2365
Status\newGood
static newGood( $value=null)
Factory function for good results.
Definition: Status.php:77
User\getStubThreshold
getStubThreshold()
Get the user preferred stub threshold.
Definition: User.php:2768
Sanitizer\validateEmail
static validateEmail( $addr)
Does a string look like an e-mail address?
Definition: Sanitizer.php:1848
User\comparePasswords
static comparePasswords( $hash, $password, $userId=false)
Compare a password hash with a plain-text password.
Definition: User.php:4572
$params
$params
Definition: styleTest.css.php:40
$limit
if( $sleep) $limit
Definition: importImages.php:99
Block\newFromTarget
static newFromTarget( $specificTarget, $vagueTarget=null, $fromMaster=false)
Given a target and the target's type, get an existing Block object if possible.
Definition: Block.php:987
wfReadOnly
wfReadOnly()
Check whether the wiki is in read-only mode.
Definition: GlobalFunctions.php:1360
PasswordError
Thrown by User::setPassword() on error.
Definition: User.php:45
User\newFromName
static newFromName( $name, $validate='valid')
Static factory method for creation from username.
Definition: User.php:389
User\loadFromRow
loadFromRow( $row, $data=null)
Initialize this object from a row from the user table.
Definition: User.php:1172
User\setEmailAuthenticationTimestamp
setEmailAuthenticationTimestamp( $timestamp)
Set the e-mail authentication timestamp.
Definition: User.php:4001
IP\isIPv6
static isIPv6( $ip)
Given a string, determine if it as valid IP in IPv6 only.
Definition: IP.php:85
User\clearCookie
clearCookie( $name, $secure=null, $params=array())
Clear a cookie on the user's client.
Definition: User.php:3292
User\getUserPage
getUserPage()
Get this user's personal page title.
Definition: User.php:3673
User\USER_TOKEN_LENGTH
const USER_TOKEN_LENGTH
Global constants made accessible as class constants so that autoloader magic can be used.
Definition: User.php:64
User\getGroups
getGroups()
Get the list of explicit group memberships this user has.
Definition: User.php:2814
$s
$s
Definition: mergeMessageFileList.php:156
User\$mOptionOverrides
$mOptionOverrides
Bool Whether the cache variables have been loaded.
Definition: User.php:186
MWCryptRand\generateHex
static generateHex( $chars, $forceStrong=false)
Generate a run of (ideally) cryptographically random data and return it in hexadecimal string format.
Definition: MWCryptRand.php:514
User\useNPPatrol
useNPPatrol()
Check whether to enable new pages patrol features for this user.
Definition: User.php:3075
User\$mToken
$mToken
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\getDatePreference
getDatePreference()
Get the user's preferred date format.
Definition: User.php:2729
User\setEmail
setEmail( $str)
Set the user's e-mail address.
Definition: User.php:2348
$wgContLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the content language as $wgContLang
Definition: design.txt:56
User\isValidUserName
static isValidUserName( $name)
Is the input a valid username?
Definition: User.php:570
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:3852
User\groupHasPermission
static groupHasPermission( $group, $role)
Check, if the given group has the given permission.
Definition: User.php:4166
User\getEmailAuthenticationTimestamp
getEmailAuthenticationTimestamp()
Get the timestamp of the user's e-mail authentication.
Definition: User.php:2338
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:1615
User\$mFrom
$mFrom
String Initialization data source if mLoadedItems!==true.
Definition: User.php:215
User\initEditCount
initEditCount( $add=0)
Initialize user_editcount from data out of the revision table.
Definition: User.php:4485
User\useRCPatrol
useRCPatrol()
Check whether to enable recent changes patrol features for this user.
Definition: User.php:3066
User\invalidateEmail
invalidateEmail()
Invalidate the user's e-mail confirmation, and unauthenticate the e-mail address if it was already co...
Definition: User.php:3988
$messages
$messages
Definition: LogTests.i18n.php:8
User\newFromRow
static newFromRow( $row, $data=null)
Create a new user object from a user row.
Definition: User.php:471
User\loadGroups
loadGroups()
Load the groups from the database if they aren't already loaded.
Definition: User.php:1256
User\$mNewpassTime
$mNewpassTime
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\compareSecrets
compareSecrets( $answer, $test)
A comparison of two strings, not vulnerable to timing attacks.
Definition: User.php:1115
User\deleteNewtalk
deleteNewtalk( $field, $id)
Clear the new messages flag for the given user.
Definition: User.php:2061
true
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
Definition: hooks.txt:1530
User\$mCacheVars
static $mCacheVars
Array of Strings List of member variables which are saved to the shared cache (memcached).
Definition: User.php:79
pages
The ContentHandler facility adds support for arbitrary content types on wiki pages
Definition: contenthandler.txt:1
User\getRights
getRights()
Get the permissions this user has.
Definition: User.php:2783
User\getRequest
getRequest()
Get the WebRequest object to use with this object.
Definition: User.php:3088
Preferences\getSaveBlacklist
static getSaveBlacklist()
Definition: Preferences.php:68
User\getAutomaticGroups
getAutomaticGroups( $recache=false)
Get the list of implicit group memberships this user has.
Definition: User.php:2850
User\generateToken
static generateToken()
Generate a looking random token for various uses.
Definition: User.php:3807
User\setPassword
setPassword( $str)
Set the password and reset the random token.
Definition: User.php:2208
User\$mRights
$mRights
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\$mNewpassword
$mNewpassword
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\getDefaultOptions
static getDefaultOptions()
Combine the language default options with any site-specific options and add the default language vari...
Definition: User.php:1350
$dbr
$dbr
Definition: testCompression.php:48
Linker\link
static link( $target, $html=null, $customAttribs=array(), $query=array(), $options=array())
This function returns an HTML link to the given target.
Definition: Linker.php:192
User\isBlockedFrom
isBlockedFrom( $title, $bFromSlave=false)
Check if user is blocked from editing a particular article.
Definition: User.php:1743
User\resetOptions
resetOptions( $resetKinds=array( 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused'), IContextSource $context=null)
Reset certain (or all) options to the site defaults.
Definition: User.php:2686
NS_MAIN
const NS_MAIN
Definition: Defines.php:79
MailAddress
Stores a single person's name and email address.
Definition: UserMailer.php:32
User\getEmail
getEmail()
Get the user's e-mail address.
Definition: User.php:2328
file
We ve cleaned up the code here by removing clumps of infrequently used code and moving them off somewhere else It s much easier for someone working with this code to see what s _really_ going and make changes or fix bugs In we can take all the code that deals with the little used title reversing we can concentrate it all in an extension file
Definition: hooks.txt:93
article
design txt This is a brief overview of the new design More thorough and up to date information is available on the documentation wiki at etc Handles the details of getting and saving to the user table of the and dealing with sessions and cookies OutputPage Encapsulates the entire HTML page that will be sent in response to any server request It is used by calling its functions to add in any and then calling but I prefer the flexibility This should also do the output encoding The system allocates a global one in $wgOut Title Represents the title of an article
Definition: design.txt:25
User\getTalkPage
getTalkPage()
Get this user's talk page title.
Definition: User.php:3682
$test
$test
Definition: Utf8Test.php:89
User\$mName
$mName
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\matchEditToken
matchEditToken( $val, $salt='', $request=null)
Check given value against the token value stored in the session.
Definition: User.php:3822
User\$mBlockedby
$mBlockedby
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\addToDatabase
addToDatabase()
Add this existing user object to the database.
Definition: User.php:3540
User\clearSharedCache
clearSharedCache()
Clear user data from memcached.
Definition: User.php:2131
User\invalidateCache
invalidateCache()
Immediately touch the user data cache for this account.
Definition: User.php:2144
User\setInternalPassword
setInternalPassword( $str)
Set the password and reset the random token unconditionally.
Definition: User.php:2246
User\getWatchedItem
getWatchedItem( $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Get a WatchedItem for this user and $title.
Definition: User.php:3117
MWException
MediaWiki exception.
Definition: MWException.php:26
User\invalidationTokenUrl
invalidationTokenUrl( $token)
Return a URL the user can use to invalidate their email address.
Definition: User.php:3940
wfMemcKey
wfMemcKey()
Get a cache key.
Definition: GlobalFunctions.php:3635
User\isLocked
isLocked()
Check if user account is locked.
Definition: User.php:1818
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1174
WatchedItem\fromUserTitle
static fromUserTitle( $user, $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Create a WatchedItem object with the given user and title.
Definition: WatchedItem.php:56
$property
$property
Definition: styleTest.css.php:44
User\checkPasswordValidity
checkPasswordValidity( $password)
Check if this is a valid password for this user.
Definition: User.php:730
User\$mOptions
$mOptions
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\confirmEmail
confirmEmail()
Mark the e-mail address confirmed.
Definition: User.php:3971
User\setItemLoaded
setItemLoaded( $item)
Set that an item has been loaded.
Definition: User.php:1025
User\blockedFor
blockedFor()
If user is blocked, return the specified reason for the block.
Definition: User.php:1775
User\$mImplicitGroups
$mImplicitGroups
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\MW_USER_VERSION
const MW_USER_VERSION
Definition: User.php:65
User\getOptions
getOptions()
Get all user's options.
Definition: User.php:2450
User\setNewtalk
setNewtalk( $val, $curRev=null)
Update the 'You have new messages!' status.
Definition: User.php:2080
User\isWatched
isWatched( $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Check the watched status of an article.
Definition: User.php:3140
User\$mBlockedFromCreateAccount
Block $mBlockedFromCreateAccount
Bool Whether the cache variables have been loaded.
Definition: User.php:238
User\isAllowedToCreateAccount
isAllowedToCreateAccount()
Get whether the user is allowed to create an account.
Definition: User.php:3664
User\logout
logout()
Log this user out.
Definition: User.php:3370
User\confirmationToken
confirmationToken(&$expiration)
Generate, store, and return a new e-mail confirmation code.
Definition: User.php:3913
wfTimestampOrNull
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
Definition: GlobalFunctions.php:2548
User\getImplicitGroups
static getImplicitGroups()
Get a list of implicit groups.
Definition: User.php:4270
User\$mPasswordExpires
$mPasswordExpires
Bool Whether the cache variables have been loaded.
Definition: User.php:191
wfProfileOut
wfProfileOut( $functionname='missing')
Stop profiling of a function.
Definition: Profiler.php:46
User\isHidden
isHidden()
Check if user account is hidden.
Definition: User.php:1834
User\randomPassword
static randomPassword()
Return a random password.
Definition: User.php:951
wfMessage
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned and may include noclasses after processing after in associative array form externallinks including delete and has completed for all link tables default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message additional optional elements are parameters for the key that are processed with wfMessage() -> params() ->parseAsBlock() - offset Set to overwrite offset parameter in $wgRequest set to '' to unset offset - wrap String Wrap the message in html(usually something like "&lt
User\isBlockedFromEmailuser
isBlockedFromEmailuser()
Get whether the user is blocked from using Special:Emailuser.
Definition: User.php:3655
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4066
User\isIP
static isIP( $name)
Does the string match an anonymous IPv4 address?
Definition: User.php:555
User\validateCache
validateCache( $timestamp)
Validate the cache for this account.
Definition: User.php:2178
User\getEffectiveGroups
getEffectiveGroups( $recache=false)
Get the list of implicit group memberships this user has.
Definition: User.php:2827
User\isPingLimitable
isPingLimitable()
Is this user subject to rate limiting?
Definition: User.php:1593
User\removeGroup
removeGroup( $group)
Remove the user from the given group.
Definition: User.php:2963
User\newFromConfirmationCode
static newFromConfirmationCode( $code)
Factory method to fetch whichever user has a given email confirmation code.
Definition: User.php:430
User\canReceiveEmail
canReceiveEmail()
Is this user allowed to receive e-mails within limits of current site configuration?
Definition: User.php:4027
User\isNewbie
isNewbie()
Determine whether the user is a newbie.
Definition: User.php:3692
User\isAllowedAll
isAllowedAll()
Is the input a valid password for this user?
Definition: User.php:3031
array
the array() calling protocol came about after MediaWiki 1.4rc1.
List of Api Query prop modules.
User\checkNewtalk
checkNewtalk( $field, $id, $fromMaster=false)
Internal uncached check for new messages.
Definition: User.php:2018
User\clearInstanceCache
clearInstanceCache( $reloadFrom=false)
Clear various cached data stored in this object.
Definition: User.php:1325
global
when a variable name is used in a it is silently declared as a new masking the global
Definition: design.txt:93
wfTimestampNow
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
Definition: GlobalFunctions.php:2561
$cookies
return false to override stock group removal can be modified modifiable will be added to $_SESSION & $cookies
Definition: hooks.txt:2849
$columns
if(! $in) $columns
Definition: Utf8Test.php:50
User\$mId
$mId
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\setName
setName( $str)
Set the user name.
Definition: User.php:1903
User\setCookie
setCookie( $name, $value, $exp=0, $secure=null, $params=array())
Set a cookie on the user's client.
Definition: User.php:3278
User\createNew
static createNew( $name, $params=array())
Add a user to the database, return the user object.
Definition: User.php:3477
User\$mLoadedItems
$mLoadedItems
Array with already loaded items or true if all items have been loaded.
Definition: User.php:203
$allowUsertalk
return false to override stock group addition can be modified try getUserPermissionsErrors userCan checks are continued by internal code can override on output return false to not delete it return false to override the default password checks this Boolean value will be checked to determine if the password was valid return false to implement your own hashing method this String will be used as the hash which may be added to this hook is run right before returning the options to the caller which means it s potentially called dozens or hundreds of times You may want to cache the results of non trivial operations in your hook function for this reason change this to override email change this to override email authentication timestamp whether or not the user is blocked from that page & $allowUsertalk
Definition: hooks.txt:2708
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:188
User\clearNotification
clearNotification(&$title, $oldid=0)
Clear the user's notification timestamp for the given title.
Definition: User.php:3176
User\saveSettings
saveSettings()
Save this user's settings into the database.
Definition: User.php:3400
User\$mGroups
$mGroups
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\addNewUserLogEntry
addNewUserLogEntry( $action=false, $reason='')
Add a newuser log entry for this user.
Definition: User.php:4614
User\$mPassword
$mPassword
Bool Whether the cache variables have been loaded.
Definition: User.php:186
Block\getBlocksForIPList
static getBlocksForIPList(array $ipChain, $isAnon, $fromMaster=false)
Get all blocks that match any IP from an array of IP addresses.
Definition: Block.php:1027
User\$mCoreRights
static $mCoreRights
Array of Strings Core rights.
Definition: User.php:108
User\getFirstEditTimestamp
getFirstEditTimestamp()
Get the timestamp of the first edit.
Definition: User.php:4094
User\expirePassword
expirePassword( $ts=0)
Expire a user's password.
Definition: User.php:777
$options
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1530
User\setRealName
setRealName( $str)
Set the user's real name.
Definition: User.php:2410
$ok
$ok
Definition: UtfNormalTest.php:71
User\EDIT_TOKEN_SUFFIX
const EDIT_TOKEN_SUFFIX
Definition: User.php:66
User\getNewMessageLinks
getNewMessageLinks()
Return the data needed to construct links for new talk page message alerts.
Definition: User.php:1968
TS_MW
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Definition: GlobalFunctions.php:2478
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:980
User\getBlockedStatus
getBlockedStatus( $bFromSlave=true)
Get blocking information.
Definition: User.php:1399
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:422
wfWikiID
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
Definition: GlobalFunctions.php:3668
User\idForName
idForName()
If only this user's username is known, and it exists, return the user ID.
Definition: User.php:3447
$title
presenting them properly to the user as errors is done by the caller $title
Definition: hooks.txt:1324
NS_USER_TALK
const NS_USER_TALK
Definition: Defines.php:82
User\getFormerGroups
getFormerGroups()
Returns the groups the user has belonged to.
Definition: User.php:2881
User\loadFromDatabase
loadFromDatabase()
Load user and user_group data from the database.
Definition: User.php:1134
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:336
User\whoIs
static whoIs( $id)
Get the username corresponding to a given user ID.
Definition: User.php:484
$matches
if(!defined( 'MEDIAWIKI')) if(!isset( $wgVersion)) $matches
Definition: NoLocalSettings.php:33
User\newTouchedTimestamp
static newTouchedTimestamp()
Generate a current or new-future timestamp to be stored in the user_touched field when we update thin...
Definition: User.php:2119
$value
$value
Definition: styleTest.css.php:45
User\loadFromSession
loadFromSession()
Load user data from the session or login cookie.
Definition: User.php:1035
User\isBlockedGlobally
isBlockedGlobally( $ip='')
Check if user is blocked on all wikis.
Definition: User.php:1797
User\getOption
getOption( $oname, $defaultOverride=null, $ignoreHidden=false)
Get the user's current setting for a given option.
Definition: User.php:2425
User\isDnsBlacklisted
isDnsBlacklisted( $ip, $checkWhitelist=false)
Whether the given IP is in a DNS blacklist.
Definition: User.php:1491
User\getTouched
getTouched()
Get the user touched timestamp.
Definition: User.php:2187
IP\parseRange
static parseRange( $range)
Given a string range in a number of formats, return the start and end of the range in hexadecimal.
Definition: IP.php:574
User\__toString
__toString()
Definition: User.php:263
User\$mRegistration
$mRegistration
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\getRealName
getRealName()
Get the user's real name.
Definition: User.php:2398
User\$idCacheByName
static $idCacheByName
Bool Whether the cache variables have been loaded.
Definition: User.php:244
Block\setBlocker
setBlocker( $user)
Set the user who implemented (or will implement) this block.
Definition: Block.php:1323
User\setCookies
setCookies( $request=null, $secure=null, $rememberMe=false)
Set the default cookies for this session on the user's client.
Definition: User.php:3304
User\getGroupPermissions
static getGroupPermissions( $groups)
Get the permissions associated with a given list of groups.
Definition: User.php:4116
User\getGroupPage
static getGroupPage( $group)
Get the title of a page describing a particular group.
Definition: User.php:4283
User\matchEditTokenNoSuffix
matchEditTokenNoSuffix( $val, $salt='', $request=null)
Check given value against the token value stored in the session, ignoring the suffix.
Definition: User.php:3840
User\changeableGroups
changeableGroups()
Returns an array of groups that this user can add and remove.
Definition: User.php:4408
User\clearAllNotifications
clearAllNotifications()
Resets all of the given user's page-change notification timestamps.
Definition: User.php:3237
WatchedItem\CHECK_USER_RIGHTS
const CHECK_USER_RIGHTS
Constant to specify that user rights 'editmywatchlist' and 'viewmywatchlist' should be checked.
Definition: WatchedItem.php:42
User\isPasswordReminderThrottled
isPasswordReminderThrottled()
Has password reminder email been sent within the last $wgPasswordReminderResendTime hours?
Definition: User.php:2314
User\crypt
static crypt( $password, $salt=false)
Make a new-style password hash.
Definition: User.php:4544
User\checkPassword
checkPassword( $password)
Check to see if the given clear-text password is one of the accepted passwords.
Definition: User.php:3701
User\getAllGroups
static getAllGroups()
Return the set of defined explicit groups.
Definition: User.php:4241
User\getAllRights
static getAllRights()
Get a list of all available permissions.
Definition: User.php:4253
User\$mTouched
$mTouched
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\$mEmailAuthenticated
$mEmailAuthenticated
Bool Whether the cache variables have been loaded.
Definition: User.php:186
RequestContext\getMain
static getMain()
Static methods.
Definition: RequestContext.php:420
User\blockedBy
blockedBy()
If user is blocked, return the name of the user who placed the block.
Definition: User.php:1766
$user
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a account $user
Definition: hooks.txt:237
User\getGroupMember
static getGroupMember( $group, $username='#')
Get the localized descriptive name for a member of a group, if it exists.
Definition: User.php:4230
IP\isIPv4
static isIPv4( $ip)
Given a string, determine if it as valid IP in IPv4 only.
Definition: IP.php:96
IContextSource
Interface for objects which can provide a context on request.
Definition: IContextSource.php:29
WebRequest
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...
Definition: WebRequest.php:38
$hash
return false to override stock group addition can be modified try getUserPermissionsErrors userCan checks are continued by internal code can override on output return false to not delete it return false to override the default password checks & $hash
Definition: hooks.txt:2708
$password
return false to override stock group addition can be modified try getUserPermissionsErrors userCan checks are continued by internal code can override on output return false to not delete it return false to override the default password checks this Boolean value will be checked to determine if the password was valid return false to implement your own hashing method & $password
Definition: hooks.txt:2708
$summary
$summary
Definition: importImages.php:120
User\changeableByGroup
static changeableByGroup( $group)
Returns an array of the groups that a particular group can add/remove.
Definition: User.php:4344
User\$mWatchedItems
Array $mWatchedItems
Bool Whether the cache variables have been loaded.
Definition: User.php:242
User\getGroupName
static getGroupName( $group)
Get the localized descriptive name for a group, if it exists.
Definition: User.php:4218
User\resetPasswordExpiration
resetPasswordExpiration( $load=true)
Clear the password expiration for a user.
Definition: User.php:789
$count
$count
Definition: UtfNormalTest2.php:96
$wgUseEnotif
$wgUseEnotif
Definition: Setup.php:286
Autopromote\getAutopromoteOnceGroups
static getAutopromoteOnceGroups(User $user, $event)
Get the groups for the given user based on the given criteria.
Definition: Autopromote.php:63
$rev
presenting them properly to the user as errors is done by the caller return true use this to change the list i e etc $rev
Definition: hooks.txt:1337
User\setId
setId( $v)
Set the user and reload all fields according to a given ID.
Definition: User.php:1867
User\getRegistration
getRegistration()
Get the timestamp of account creation.
Definition: User.php:4080
IP\sanitizeIP
static sanitizeIP( $ip)
Convert an IP into a verbose, uppercase, normalized form.
Definition: IP.php:135
User\isEveryoneAllowed
static isEveryoneAllowed( $right)
Check if all users have the given permission.
Definition: User.php:4179
DB_SLAVE
const DB_SLAVE
Definition: Defines.php:55
$wgLang
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as $wgLang
Definition: design.txt:56
User\idFromName
static idFromName( $name)
Get database id given a user name.
Definition: User.php:503
User\isAllowedAny
isAllowedAny()
Check if user is allowed to access a feature / make an action.
Definition: User.php:3016
User\getRightDescription
static getRightDescription( $right)
Get the description of a given right.
Definition: User.php:4514
$cache
$cache
Definition: mcc.php:32
User\isLoggedIn
isLoggedIn()
Get whether the user is logged in.
Definition: User.php:2996
User\checkTemporaryPassword
checkTemporaryPassword( $plaintext)
Check if the given clear-text password matches the temporary password sent by e-mail for password res...
Definition: User.php:3741
User\getTitleKey
getTitleKey()
Get the user's name escaped by underscores.
Definition: User.php:1912
User\saveToCache
saveToCache()
Save user data to the shared cache.
Definition: User.php:352
User\setToken
setToken( $token=false)
Set the random token (used for persistent authentication) Called from loadDefaults() among other plac...
Definition: User.php:2279
in
Prior to maintenance scripts were a hodgepodge of code that had no cohesion or formal method of action Beginning in
Definition: maintenance.txt:1
wfBaseConvert
wfBaseConvert( $input, $sourceBase, $destBase, $pad=1, $lowercase=true, $engine='auto')
Convert an arbitrarily-long digit string from one numeric base to another, optionally zero-padding to...
Definition: GlobalFunctions.php:3432
User\resetIdByNameCache
static resetIdByNameCache()
Reset the cache used in idFromName().
Definition: User.php:535
TS_UNIX
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
Definition: GlobalFunctions.php:2473
User\$mEmailTokenExpires
$mEmailTokenExpires
Bool Whether the cache variables have been loaded.
Definition: User.php:186
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:884
User\isEmailConfirmed
isEmailConfirmed()
Is this user's e-mail address valid-looking and confirmed within limits of the current site configura...
Definition: User.php:4041
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
Block
Definition: Block.php:22
UserCache\singleton
static singleton()
Definition: UserCache.php:34
StubObject\unstub
static unstub( $obj)
Unstubs an object, if it is a stub object.
Definition: StubObject.php:80
$incrBy
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled $incrBy
Definition: hooks.txt:1961
Revision\loadFromTimestamp
static loadFromTimestamp( $db, $title, $timestamp)
Load the revision for the given title with the given timestamp.
Definition: Revision.php:277
User\getPasswordExpired
getPasswordExpired()
Check if the user's password is expired.
Definition: User.php:815
User
User
Definition: All_system_messages.txt:425
$keys
$keys
Definition: testCompression.php:63
NS_USER
const NS_USER
Definition: Defines.php:81
User\addAutopromoteOnceGroups
addAutopromoteOnceGroups( $event)
Add the user to the group if he/she meets given criteria.
Definition: User.php:1284
User\sendMail
sendMail( $subject, $body, $from=null, $replyto=null)
Send an e-mail to this user's account.
Definition: User.php:3890
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:2523
ManualLogEntry
Class for creating log entries manually, for example to inject them into the database.
Definition: LogEntry.php:339
User\$mFormerGroups
$mFormerGroups
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\getSkin
getSkin()
Get the current skin, loading it if required.
Definition: User.php:3103
User\$mBlockedGlobally
$mBlockedGlobally
Bool Whether the cache variables have been loaded.
Definition: User.php:220
HTMLFormField\flattenOptions
static flattenOptions( $options)
flatten an array of options to a single array, for instance, a set of "<options>" inside "<optgroups>...
Definition: HTMLFormField.php:601
User\selectFields
static selectFields()
Return the list of user fields that should be selected to create a new user object.
Definition: User.php:4847
$t
$t
Definition: testCompression.php:65
User\addNewUserLogEntryAutoCreate
addNewUserLogEntryAutoCreate()
Add an autocreate newuser log entry for this user Used by things like CentralAuth and perhaps other a...
Definition: User.php:4659
User\$mRequest
WebRequest $mRequest
Bool Whether the cache variables have been loaded.
Definition: User.php:226
User\getBoolOption
getBoolOption( $oname)
Get the user's current setting for a given option, as a boolean value.
Definition: User.php:2477
User\removeWatch
removeWatch( $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Stop watching an article.
Definition: User.php:3163
$error
usually copyright or history_copyright This message must be in HTML not wikitext $subpages will be ignored and the rest of subPageSubtitle() will run. 'SkinTemplateBuildNavUrlsNav_urlsAfterPermalink' whether MediaWiki currently thinks this is a CSS JS page Hooks may change this value to override the return value of Title::isCssOrJsPage(). 'TitleIsAlwaysKnown' whether MediaWiki currently thinks this page is known isMovable() always returns false. $title whether MediaWiki currently thinks this page is movable Hooks may change this value to override the return value of Title::isMovable(). 'TitleIsWikitextPage' whether MediaWiki currently thinks this is a wikitext page Hooks may change this value to override the return value of Title::isWikitextPage() 'TitleMove' use UploadVerification and UploadVerifyFile instead where the first element is the message key and the remaining elements are used as parameters to the message based on mime etc Preferred in most cases over UploadVerification object with all info about the upload string as detected by MediaWiki Handlers will typically only apply for specific mime types object & $error
Definition: hooks.txt:2584
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:624
User\$mDatePreference
$mDatePreference
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\isBlocked
isBlocked( $bFromSlave=true)
Check if user is blocked.
Definition: User.php:1721
User\$mRealName
$mRealName
Bool Whether the cache variables have been loaded.
Definition: User.php:186
User\isBlockedFromCreateAccount
isBlockedFromCreateAccount()
Get whether the user is explicitly blocked from account creation.
Definition: User.php:3634
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:3781
User\requiresHTTPS
requiresHTTPS()
Determine based on the wiki configuration and the user's options, whether this user must be over HTTP...
Definition: User.php:2749
User\$mAllRights
static $mAllRights
String Cached results of getAllRights()
Definition: User.php:182
User\isItemLoaded
isItemLoaded( $item, $all='all')
Return whether an item has been loaded.
Definition: User.php:1015
User
The User object encapsulates all of the user-specific settings (user_id, name, rights,...
Definition: User.php:59
User\setOption
setOption( $oname, $val)
Set the given option for a user.
Definition: User.php:2503
$res
$res
Definition: database.txt:21
User\getPasswordValidity
getPasswordValidity( $password)
Given unvalidated password input, return error message on failure.
Definition: User.php:703
wfResetSessionID
wfResetSessionID()
Reset the session_id.
Definition: GlobalFunctions.php:3566
User\whoIsReal
static whoIsReal( $id)
Get the real name of a user given their user ID.
Definition: User.php:494
User\getName
getName()
Get the user name, or the IP of an anonymous user.
Definition: User.php:1876
User\doLogout
doLogout()
Clear the user's cookies and session, and reset the instance cache.
Definition: User.php:3380
User\canSendEmail
canSendEmail()
Is this user allowed to send e-mails within limits of current site configuration?
Definition: User.php:4012
User\isCreatableName
static isCreatableName( $name)
Usernames which fail to pass this function will be blocked from new account registrations,...
Definition: User.php:661
User\$mHideName
$mHideName
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\oldCrypt
static oldCrypt( $password, $userId)
Make an old-style password hash.
Definition: User.php:4527
User\$mLocked
$mLocked
Bool Whether the cache variables have been loaded.
Definition: User.php:220
IP\isIPAddress
static isIPAddress( $ip)
Determine if a string is as valid IP address or network (CIDR prefix).
Definition: IP.php:74
User\getGroupsWithPermission
static getGroupsWithPermission( $role)
Get all the groups who have a given permission.
Definition: User.php:4143
User\isAllowed
isAllowed( $action='')
Internal mechanics of testing a permission.
Definition: User.php:3046
Status\newFatal
static newFatal( $message)
Factory function for fatal errors.
Definition: Status.php:63
User\listOptionKinds
static listOptionKinds()
Return a list of the types of user options currently returned by User::getOptionKinds().
Definition: User.php:2580
$changed
$changed
Definition: UtfNormalGenerate.php:130
page
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values my talk page
Definition: hooks.txt:1961
$type
$type
Definition: testCompression.php:46