MediaWiki  1.23.13
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  return $this->mRights;
2796  }
2797 
2803  public function getGroups() {
2804  $this->load();
2805  $this->loadGroups();
2806  return $this->mGroups;
2807  }
2808 
2816  public function getEffectiveGroups( $recache = false ) {
2817  if ( $recache || is_null( $this->mEffectiveGroups ) ) {
2818  wfProfileIn( __METHOD__ );
2819  $this->mEffectiveGroups = array_unique( array_merge(
2820  $this->getGroups(), // explicit groups
2821  $this->getAutomaticGroups( $recache ) // implicit groups
2822  ) );
2823  // Hook for additional groups
2824  wfRunHooks( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) );
2825  // Force reindexation of groups when a hook has unset one of them
2826  $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
2827  wfProfileOut( __METHOD__ );
2828  }
2829  return $this->mEffectiveGroups;
2830  }
2831 
2839  public function getAutomaticGroups( $recache = false ) {
2840  if ( $recache || is_null( $this->mImplicitGroups ) ) {
2841  wfProfileIn( __METHOD__ );
2842  $this->mImplicitGroups = array( '*' );
2843  if ( $this->getId() ) {
2844  $this->mImplicitGroups[] = 'user';
2845 
2846  $this->mImplicitGroups = array_unique( array_merge(
2847  $this->mImplicitGroups,
2849  ) );
2850  }
2851  if ( $recache ) {
2852  // Assure data consistency with rights/groups,
2853  // as getEffectiveGroups() depends on this function
2854  $this->mEffectiveGroups = null;
2855  }
2856  wfProfileOut( __METHOD__ );
2857  }
2858  return $this->mImplicitGroups;
2859  }
2860 
2870  public function getFormerGroups() {
2871  if ( is_null( $this->mFormerGroups ) ) {
2872  $dbr = wfGetDB( DB_MASTER );
2873  $res = $dbr->select( 'user_former_groups',
2874  array( 'ufg_group' ),
2875  array( 'ufg_user' => $this->mId ),
2876  __METHOD__ );
2877  $this->mFormerGroups = array();
2878  foreach ( $res as $row ) {
2879  $this->mFormerGroups[] = $row->ufg_group;
2880  }
2881  }
2882  return $this->mFormerGroups;
2883  }
2889  public function getEditCount() {
2890  if ( !$this->getId() ) {
2891  return null;
2892  }
2893 
2894  if ( !isset( $this->mEditCount ) ) {
2895  /* Populate the count, if it has not been populated yet */
2896  wfProfileIn( __METHOD__ );
2897  $dbr = wfGetDB( DB_SLAVE );
2898  // check if the user_editcount field has been initialized
2899  $count = $dbr->selectField(
2900  'user', 'user_editcount',
2901  array( 'user_id' => $this->mId ),
2902  __METHOD__
2903  );
2904 
2905  if ( $count === null ) {
2906  // it has not been initialized. do so.
2907  $count = $this->initEditCount();
2908  }
2909  $this->mEditCount = $count;
2910  wfProfileOut( __METHOD__ );
2911  }
2912  return (int)$this->mEditCount;
2913  }
2914 
2920  public function addGroup( $group ) {
2921  if ( wfRunHooks( 'UserAddGroup', array( $this, &$group ) ) ) {
2922  $dbw = wfGetDB( DB_MASTER );
2923  if ( $this->getId() ) {
2924  $dbw->insert( 'user_groups',
2925  array(
2926  'ug_user' => $this->getID(),
2927  'ug_group' => $group,
2928  ),
2929  __METHOD__,
2930  array( 'IGNORE' ) );
2931  }
2932  }
2933  $this->loadGroups();
2934  $this->mGroups[] = $group;
2935  // In case loadGroups was not called before, we now have the right twice.
2936  // Get rid of the duplicate.
2937  $this->mGroups = array_unique( $this->mGroups );
2938 
2939  // Refresh the groups caches, and clear the rights cache so it will be
2940  // refreshed on the next call to $this->getRights().
2941  $this->getEffectiveGroups( true );
2942  $this->mRights = null;
2943 
2944  $this->invalidateCache();
2945  }
2946 
2952  public function removeGroup( $group ) {
2953  $this->load();
2954  if ( wfRunHooks( 'UserRemoveGroup', array( $this, &$group ) ) ) {
2955  $dbw = wfGetDB( DB_MASTER );
2956  $dbw->delete( 'user_groups',
2957  array(
2958  'ug_user' => $this->getID(),
2959  'ug_group' => $group,
2960  ), __METHOD__ );
2961  // Remember that the user was in this group
2962  $dbw->insert( 'user_former_groups',
2963  array(
2964  'ufg_user' => $this->getID(),
2965  'ufg_group' => $group,
2966  ),
2967  __METHOD__,
2968  array( 'IGNORE' ) );
2969  }
2970  $this->loadGroups();
2971  $this->mGroups = array_diff( $this->mGroups, array( $group ) );
2972 
2973  // Refresh the groups caches, and clear the rights cache so it will be
2974  // refreshed on the next call to $this->getRights().
2975  $this->getEffectiveGroups( true );
2976  $this->mRights = null;
2977 
2978  $this->invalidateCache();
2979  }
2985  public function isLoggedIn() {
2986  return $this->getID() != 0;
2987  }
2993  public function isAnon() {
2994  return !$this->isLoggedIn();
2995  }
2996 
3005  public function isAllowedAny( /*...*/ ) {
3006  $permissions = func_get_args();
3007  foreach ( $permissions as $permission ) {
3008  if ( $this->isAllowed( $permission ) ) {
3009  return true;
3010  }
3011  }
3012  return false;
3013  }
3014 
3020  public function isAllowedAll( /*...*/ ) {
3021  $permissions = func_get_args();
3022  foreach ( $permissions as $permission ) {
3023  if ( !$this->isAllowed( $permission ) ) {
3024  return false;
3025  }
3026  }
3027  return true;
3028  }
3029 
3035  public function isAllowed( $action = '' ) {
3036  if ( $action === '' ) {
3037  return true; // In the spirit of DWIM
3038  }
3039  // Patrolling may not be enabled
3040  if ( $action === 'patrol' || $action === 'autopatrol' ) {
3041  global $wgUseRCPatrol, $wgUseNPPatrol;
3042  if ( !$wgUseRCPatrol && !$wgUseNPPatrol ) {
3043  return false;
3044  }
3045  }
3046  // Use strict parameter to avoid matching numeric 0 accidentally inserted
3047  // by misconfiguration: 0 == 'foo'
3048  return in_array( $action, $this->getRights(), true );
3049  }
3055  public function useRCPatrol() {
3056  global $wgUseRCPatrol;
3057  return $wgUseRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
3058  }
3064  public function useNPPatrol() {
3065  global $wgUseRCPatrol, $wgUseNPPatrol;
3066  return (
3067  ( $wgUseRCPatrol || $wgUseNPPatrol )
3068  && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
3069  );
3070  }
3071 
3077  public function getRequest() {
3078  if ( $this->mRequest ) {
3079  return $this->mRequest;
3080  } else {
3081  global $wgRequest;
3082  return $wgRequest;
3083  }
3084  }
3085 
3092  public function getSkin() {
3093  wfDeprecated( __METHOD__, '1.18' );
3094  return RequestContext::getMain()->getSkin();
3095  }
3096 
3106  public function getWatchedItem( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3107  $key = $checkRights . ':' . $title->getNamespace() . ':' . $title->getDBkey();
3108 
3109  if ( isset( $this->mWatchedItems[$key] ) ) {
3110  return $this->mWatchedItems[$key];
3111  }
3112 
3113  if ( count( $this->mWatchedItems ) >= self::MAX_WATCHED_ITEMS_CACHE ) {
3114  $this->mWatchedItems = array();
3115  }
3116 
3117  $this->mWatchedItems[$key] = WatchedItem::fromUserTitle( $this, $title, $checkRights );
3118  return $this->mWatchedItems[$key];
3119  }
3120 
3129  public function isWatched( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3130  return $this->getWatchedItem( $title, $checkRights )->isWatched();
3131  }
3132 
3140  public function addWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3141  $this->getWatchedItem( $title, $checkRights )->addWatch();
3142  $this->invalidateCache();
3143  }
3144 
3152  public function removeWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3153  $this->getWatchedItem( $title, $checkRights )->removeWatch();
3154  $this->invalidateCache();
3155  }
3156 
3165  public function clearNotification( &$title, $oldid = 0 ) {
3166  global $wgUseEnotif, $wgShowUpdatedMarker;
3167 
3168  // Do nothing if the database is locked to writes
3169  if ( wfReadOnly() ) {
3170  return;
3171  }
3172 
3173  // Do nothing if not allowed to edit the watchlist
3174  if ( !$this->isAllowed( 'editmywatchlist' ) ) {
3175  return;
3176  }
3177 
3178  // If we're working on user's talk page, we should update the talk page message indicator
3179  if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
3180  if ( !wfRunHooks( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
3181  return;
3182  }
3183 
3184  $nextid = $oldid ? $title->getNextRevisionID( $oldid ) : null;
3185 
3186  if ( !$oldid || !$nextid ) {
3187  // If we're looking at the latest revision, we should definitely clear it
3188  $this->setNewtalk( false );
3189  } else {
3190  // Otherwise we should update its revision, if it's present
3191  if ( $this->getNewtalk() ) {
3192  // Naturally the other one won't clear by itself
3193  $this->setNewtalk( false );
3194  $this->setNewtalk( true, Revision::newFromId( $nextid ) );
3195  }
3196  }
3197  }
3198 
3199  if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3200  return;
3201  }
3202 
3203  if ( $this->isAnon() ) {
3204  // Nothing else to do...
3205  return;
3206  }
3207 
3208  // Only update the timestamp if the page is being watched.
3209  // The query to find out if it is watched is cached both in memcached and per-invocation,
3210  // and when it does have to be executed, it can be on a slave
3211  // If this is the user's newtalk page, we always update the timestamp
3212  $force = '';
3213  if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
3214  $force = 'force';
3215  }
3216 
3217  $this->getWatchedItem( $title )->resetNotificationTimestamp( $force, $oldid );
3218  }
3219 
3226  public function clearAllNotifications() {
3227  if ( wfReadOnly() ) {
3228  return;
3229  }
3230 
3231  // Do nothing if not allowed to edit the watchlist
3232  if ( !$this->isAllowed( 'editmywatchlist' ) ) {
3233  return;
3234  }
3235 
3236  global $wgUseEnotif, $wgShowUpdatedMarker;
3237  if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3238  $this->setNewtalk( false );
3239  return;
3240  }
3241  $id = $this->getId();
3242  if ( $id != 0 ) {
3243  $dbw = wfGetDB( DB_MASTER );
3244  $dbw->update( 'watchlist',
3245  array( /* SET */ 'wl_notificationtimestamp' => null ),
3246  array( /* WHERE */ 'wl_user' => $id ),
3247  __METHOD__
3248  );
3249  // We also need to clear here the "you have new message" notification for the own user_talk page;
3250  // it's cleared one page view later in WikiPage::doViewUpdates().
3251  }
3252  }
3253 
3267  protected function setCookie( $name, $value, $exp = 0, $secure = null, $params = array() ) {
3268  $params['secure'] = $secure;
3269  $this->getRequest()->response()->setcookie( $name, $value, $exp, $params );
3270  }
3271 
3281  protected function clearCookie( $name, $secure = null, $params = array() ) {
3282  $this->setCookie( $name, '', time() - 86400, $secure, $params );
3283  }
3284 
3293  public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
3294  if ( $request === null ) {
3295  $request = $this->getRequest();
3296  }
3297 
3298  $this->load();
3299  if ( 0 == $this->mId ) {
3300  return;
3301  }
3302  if ( !$this->mToken ) {
3303  // When token is empty or NULL generate a new one and then save it to the database
3304  // This allows a wiki to re-secure itself after a leak of it's user table or $wgSecretKey
3305  // Simply by setting every cell in the user_token column to NULL and letting them be
3306  // regenerated as users log back into the wiki.
3307  $this->setToken();
3308  $this->saveSettings();
3309  }
3310  $session = array(
3311  'wsUserID' => $this->mId,
3312  'wsToken' => $this->mToken,
3313  'wsUserName' => $this->getName()
3314  );
3315  $cookies = array(
3316  'UserID' => $this->mId,
3317  'UserName' => $this->getName(),
3318  );
3319  if ( $rememberMe ) {
3320  $cookies['Token'] = $this->mToken;
3321  } else {
3322  $cookies['Token'] = false;
3323  }
3324 
3325  wfRunHooks( 'UserSetCookies', array( $this, &$session, &$cookies ) );
3326 
3327  foreach ( $session as $name => $value ) {
3328  $request->setSessionData( $name, $value );
3329  }
3330  foreach ( $cookies as $name => $value ) {
3331  if ( $value === false ) {
3332  $this->clearCookie( $name );
3333  } else {
3334  $this->setCookie( $name, $value, 0, $secure );
3335  }
3336  }
3337 
3345  if ( $request->getCheck( 'wpStickHTTPS' ) || $this->requiresHTTPS() ) {
3346  $this->setCookie(
3347  'forceHTTPS',
3348  'true',
3349  $rememberMe ? 0 : null,
3350  false,
3351  array( 'prefix' => '' ) // no prefix
3352  );
3353  }
3354  }
3355 
3359  public function logout() {
3360  if ( wfRunHooks( 'UserLogout', array( &$this ) ) ) {
3361  $this->doLogout();
3362  }
3363  }
3369  public function doLogout() {
3370  $this->clearInstanceCache( 'defaults' );
3371 
3372  $this->getRequest()->setSessionData( 'wsUserID', 0 );
3373 
3374  $this->clearCookie( 'UserID' );
3375  $this->clearCookie( 'Token' );
3376  $this->clearCookie( 'forceHTTPS', false, array( 'prefix' => '' ) );
3377 
3378  // Remember when user logged out, to prevent seeing cached pages
3379  $this->setCookie( 'LoggedOut', time(), time() + 86400 );
3380  }
3386  public function saveSettings() {
3387  global $wgAuth;
3388 
3389  $this->load();
3390  if ( wfReadOnly() ) {
3391  return;
3392  }
3393  if ( 0 == $this->mId ) {
3394  return;
3395  }
3396 
3397  $this->mTouched = self::newTouchedTimestamp();
3398  if ( !$wgAuth->allowSetLocalPassword() ) {
3399  $this->mPassword = '';
3400  }
3401 
3402  $dbw = wfGetDB( DB_MASTER );
3403  $dbw->update( 'user',
3404  array( /* SET */
3405  'user_name' => $this->mName,
3406  'user_password' => $this->mPassword,
3407  'user_newpassword' => $this->mNewpassword,
3408  'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
3409  'user_real_name' => $this->mRealName,
3410  'user_email' => $this->mEmail,
3411  'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3412  'user_touched' => $dbw->timestamp( $this->mTouched ),
3413  'user_token' => strval( $this->mToken ),
3414  'user_email_token' => $this->mEmailToken,
3415  'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
3416  'user_password_expires' => $dbw->timestampOrNull( $this->mPasswordExpires ),
3417  ), array( /* WHERE */
3418  'user_id' => $this->mId
3419  ), __METHOD__
3420  );
3421 
3422  $this->saveOptions();
3423 
3424  wfRunHooks( 'UserSaveSettings', array( $this ) );
3425  $this->clearSharedCache();
3426  $this->getUserPage()->invalidateCache();
3427  }
3433  public function idForName() {
3434  $s = trim( $this->getName() );
3435  if ( $s === '' ) {
3436  return 0;
3437  }
3438 
3439  $dbr = wfGetDB( DB_SLAVE );
3440  $id = $dbr->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__ );
3441  if ( $id === false ) {
3442  $id = 0;
3443  }
3444  return $id;
3445  }
3446 
3463  public static function createNew( $name, $params = array() ) {
3464  $user = new User;
3465  $user->load();
3466  $user->setToken(); // init token
3467  if ( isset( $params['options'] ) ) {
3468  $user->mOptions = $params['options'] + (array)$user->mOptions;
3469  unset( $params['options'] );
3470  }
3471  $dbw = wfGetDB( DB_MASTER );
3472  $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
3473 
3474  $fields = array(
3475  'user_id' => $seqVal,
3476  'user_name' => $name,
3477  'user_password' => $user->mPassword,
3478  'user_newpassword' => $user->mNewpassword,
3479  'user_newpass_time' => $dbw->timestampOrNull( $user->mNewpassTime ),
3480  'user_email' => $user->mEmail,
3481  'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
3482  'user_real_name' => $user->mRealName,
3483  'user_token' => strval( $user->mToken ),
3484  'user_registration' => $dbw->timestamp( $user->mRegistration ),
3485  'user_editcount' => 0,
3486  'user_touched' => $dbw->timestamp( self::newTouchedTimestamp() ),
3487  );
3488  foreach ( $params as $name => $value ) {
3489  $fields["user_$name"] = $value;
3490  }
3491  $dbw->insert( 'user', $fields, __METHOD__, array( 'IGNORE' ) );
3492  if ( $dbw->affectedRows() ) {
3493  $newUser = User::newFromId( $dbw->insertId() );
3494  } else {
3495  $newUser = null;
3496  }
3497  return $newUser;
3498  }
3499 
3526  public function addToDatabase() {
3527  $this->load();
3528  if ( !$this->mToken ) {
3529  $this->setToken(); // init token
3530  }
3531 
3532  $this->mTouched = self::newTouchedTimestamp();
3533 
3534  $dbw = wfGetDB( DB_MASTER );
3535  $inWrite = $dbw->writesOrCallbacksPending();
3536  $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
3537  $dbw->insert( 'user',
3538  array(
3539  'user_id' => $seqVal,
3540  'user_name' => $this->mName,
3541  'user_password' => $this->mPassword,
3542  'user_newpassword' => $this->mNewpassword,
3543  'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
3544  'user_email' => $this->mEmail,
3545  'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3546  'user_real_name' => $this->mRealName,
3547  'user_token' => strval( $this->mToken ),
3548  'user_registration' => $dbw->timestamp( $this->mRegistration ),
3549  'user_editcount' => 0,
3550  'user_touched' => $dbw->timestamp( $this->mTouched ),
3551  ), __METHOD__,
3552  array( 'IGNORE' )
3553  );
3554  if ( !$dbw->affectedRows() ) {
3555  if ( !$inWrite ) {
3556  // XXX: Get out of REPEATABLE-READ so the SELECT below works.
3557  // Often this case happens early in views before any writes.
3558  // This shows up at least with CentralAuth.
3559  $dbw->commit( __METHOD__, 'flush' );
3560  }
3561  $this->mId = $dbw->selectField( 'user', 'user_id',
3562  array( 'user_name' => $this->mName ), __METHOD__ );
3563  $loaded = false;
3564  if ( $this->mId ) {
3565  if ( $this->loadFromDatabase() ) {
3566  $loaded = true;
3567  }
3568  }
3569  if ( !$loaded ) {
3570  throw new MWException( __METHOD__ . ": hit a key conflict attempting " .
3571  "to insert user '{$this->mName}' row, but it was not present in select!" );
3572  }
3573  return Status::newFatal( 'userexists' );
3574  }
3575  $this->mId = $dbw->insertId();
3576 
3577  // Clear instance cache other than user table data, which is already accurate
3578  $this->clearInstanceCache();
3579 
3580  $this->saveOptions();
3581  return Status::newGood();
3582  }
3583 
3589  public function spreadAnyEditBlock() {
3590  if ( $this->isLoggedIn() && $this->isBlocked() ) {
3591  return $this->spreadBlock();
3592  }
3593  return false;
3594  }
3595 
3601  protected function spreadBlock() {
3602  wfDebug( __METHOD__ . "()\n" );
3603  $this->load();
3604  if ( $this->mId == 0 ) {
3605  return false;
3606  }
3607 
3608  $userblock = Block::newFromTarget( $this->getName() );
3609  if ( !$userblock ) {
3610  return false;
3611  }
3612 
3613  return (bool)$userblock->doAutoblock( $this->getRequest()->getIP() );
3614  }
3620  public function isBlockedFromCreateAccount() {
3621  $this->getBlockedStatus();
3622  if ( $this->mBlock && $this->mBlock->prevents( 'createaccount' ) ) {
3623  return $this->mBlock;
3624  }
3625 
3626  # bug 13611: if the IP address the user is trying to create an account from is
3627  # blocked with createaccount disabled, prevent new account creation there even
3628  # when the user is logged in
3629  if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
3630  $this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
3631  }
3632  return $this->mBlockedFromCreateAccount instanceof Block && $this->mBlockedFromCreateAccount->prevents( 'createaccount' )
3633  ? $this->mBlockedFromCreateAccount
3634  : false;
3635  }
3641  public function isBlockedFromEmailuser() {
3642  $this->getBlockedStatus();
3643  return $this->mBlock && $this->mBlock->prevents( 'sendemail' );
3644  }
3650  public function isAllowedToCreateAccount() {
3651  return $this->isAllowed( 'createaccount' ) && !$this->isBlockedFromCreateAccount();
3652  }
3653 
3659  public function getUserPage() {
3660  return Title::makeTitle( NS_USER, $this->getName() );
3661  }
3662 
3668  public function getTalkPage() {
3669  $title = $this->getUserPage();
3670  return $title->getTalkPage();
3671  }
3672 
3678  public function isNewbie() {
3679  return !$this->isAllowed( 'autoconfirmed' );
3680  }
3681 
3687  public function checkPassword( $password ) {
3688  global $wgAuth, $wgLegacyEncoding;
3689  $this->load();
3690 
3691  // Certain authentication plugins do NOT want to save
3692  // domain passwords in a mysql database, so we should
3693  // check this (in case $wgAuth->strict() is false).
3694 
3695  if ( $wgAuth->authenticate( $this->getName(), $password ) ) {
3696  return true;
3697  } elseif ( $wgAuth->strict() ) {
3698  // Auth plugin doesn't allow local authentication
3699  return false;
3700  } elseif ( $wgAuth->strictUserAuth( $this->getName() ) ) {
3701  // Auth plugin doesn't allow local authentication for this user name
3702  return false;
3703  }
3704  if ( self::comparePasswords( $this->mPassword, $password, $this->mId ) ) {
3705  return true;
3706  } elseif ( $wgLegacyEncoding ) {
3707  // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
3708  // Check for this with iconv
3709  $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
3710  if ( $cp1252Password != $password
3711  && self::comparePasswords( $this->mPassword, $cp1252Password, $this->mId )
3712  ) {
3713  return true;
3714  }
3715  }
3716  return false;
3717  }
3718 
3727  public function checkTemporaryPassword( $plaintext ) {
3728  global $wgNewPasswordExpiry;
3729 
3730  $this->load();
3731  if ( self::comparePasswords( $this->mNewpassword, $plaintext, $this->getId() ) ) {
3732  if ( is_null( $this->mNewpassTime ) ) {
3733  return true;
3734  }
3735  $expiry = wfTimestamp( TS_UNIX, $this->mNewpassTime ) + $wgNewPasswordExpiry;
3736  return ( time() < $expiry );
3737  } else {
3738  return false;
3739  }
3740  }
3741 
3750  public function editToken( $salt = '', $request = null ) {
3751  wfDeprecated( __METHOD__, '1.19' );
3752  return $this->getEditToken( $salt, $request );
3753  }
3754 
3767  public function getEditToken( $salt = '', $request = null ) {
3768  if ( $request == null ) {
3769  $request = $this->getRequest();
3770  }
3771 
3772  if ( $this->isAnon() ) {
3773  return EDIT_TOKEN_SUFFIX;
3774  } else {
3775  $token = $request->getSessionData( 'wsEditToken' );
3776  if ( $token === null ) {
3777  $token = MWCryptRand::generateHex( 32 );
3778  $request->setSessionData( 'wsEditToken', $token );
3779  }
3780  if ( is_array( $salt ) ) {
3781  $salt = implode( '|', $salt );
3782  }
3783  return md5( $token . $salt ) . EDIT_TOKEN_SUFFIX;
3784  }
3785  }
3786 
3793  public static function generateToken() {
3794  return MWCryptRand::generateHex( 32 );
3795  }
3796 
3808  public function matchEditToken( $val, $salt = '', $request = null ) {
3809  $sessionToken = $this->getEditToken( $salt, $request );
3810  $equals = hash_equals( $sessionToken, $val );
3811  if ( !$equals ) {
3812  wfDebug( "User::matchEditToken: broken session data\n" );
3813  }
3814  return $equals;
3815  }
3816 
3826  public function matchEditTokenNoSuffix( $val, $salt = '', $request = null ) {
3827  $sessionToken = $this->getEditToken( $salt, $request );
3828  return hash_equals( substr( $sessionToken, 0, 32 ), substr( $val, 0, 32 ) );
3829  }
3830 
3838  public function sendConfirmationMail( $type = 'created' ) {
3839  global $wgLang;
3840  $expiration = null; // gets passed-by-ref and defined in next line.
3841  $token = $this->confirmationToken( $expiration );
3842  $url = $this->confirmationTokenUrl( $token );
3843  $invalidateURL = $this->invalidationTokenUrl( $token );
3844  $this->saveSettings();
3845 
3846  if ( $type == 'created' || $type === false ) {
3847  $message = 'confirmemail_body';
3848  } elseif ( $type === true ) {
3849  $message = 'confirmemail_body_changed';
3850  } else {
3851  // Messages: confirmemail_body_changed, confirmemail_body_set
3852  $message = 'confirmemail_body_' . $type;
3853  }
3854 
3855  return $this->sendMail( wfMessage( 'confirmemail_subject' )->text(),
3856  wfMessage( $message,
3857  $this->getRequest()->getIP(),
3858  $this->getName(),
3859  $url,
3860  $wgLang->timeanddate( $expiration, false ),
3861  $invalidateURL,
3862  $wgLang->date( $expiration, false ),
3863  $wgLang->time( $expiration, false ) )->text() );
3864  }
3865 
3876  public function sendMail( $subject, $body, $from = null, $replyto = null ) {
3877  if ( is_null( $from ) ) {
3878  global $wgPasswordSender;
3879  $sender = new MailAddress( $wgPasswordSender,
3880  wfMessage( 'emailsender' )->inContentLanguage()->text() );
3881  } else {
3882  $sender = new MailAddress( $from );
3883  }
3884 
3885  $to = new MailAddress( $this );
3886  return UserMailer::send( $to, $sender, $subject, $body, $replyto );
3887  }
3888 
3899  protected function confirmationToken( &$expiration ) {
3900  global $wgUserEmailConfirmationTokenExpiry;
3901  $now = time();
3902  $expires = $now + $wgUserEmailConfirmationTokenExpiry;
3903  $expiration = wfTimestamp( TS_MW, $expires );
3904  $this->load();
3905  $token = MWCryptRand::generateHex( 32 );
3906  $hash = md5( $token );
3907  $this->mEmailToken = $hash;
3908  $this->mEmailTokenExpires = $expiration;
3909  return $token;
3910  }
3911 
3917  protected function confirmationTokenUrl( $token ) {
3918  return $this->getTokenUrl( 'ConfirmEmail', $token );
3919  }
3920 
3926  protected function invalidationTokenUrl( $token ) {
3927  return $this->getTokenUrl( 'InvalidateEmail', $token );
3928  }
3929 
3944  protected function getTokenUrl( $page, $token ) {
3945  // Hack to bypass localization of 'Special:'
3946  $title = Title::makeTitle( NS_MAIN, "Special:$page/$token" );
3947  return $title->getCanonicalURL();
3948  }
3949 
3957  public function confirmEmail() {
3958  // Check if it's already confirmed, so we don't touch the database
3959  // and fire the ConfirmEmailComplete hook on redundant confirmations.
3960  if ( !$this->isEmailConfirmed() ) {
3962  wfRunHooks( 'ConfirmEmailComplete', array( $this ) );
3963  }
3964  return true;
3965  }
3966 
3974  public function invalidateEmail() {
3975  $this->load();
3976  $this->mEmailToken = null;
3977  $this->mEmailTokenExpires = null;
3978  $this->setEmailAuthenticationTimestamp( null );
3979  wfRunHooks( 'InvalidateEmailComplete', array( $this ) );
3980  return true;
3981  }
3987  public function setEmailAuthenticationTimestamp( $timestamp ) {
3988  $this->load();
3989  $this->mEmailAuthenticated = $timestamp;
3990  wfRunHooks( 'UserSetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
3991  }
3992 
3998  public function canSendEmail() {
3999  global $wgEnableEmail, $wgEnableUserEmail;
4000  if ( !$wgEnableEmail || !$wgEnableUserEmail || !$this->isAllowed( 'sendemail' ) ) {
4001  return false;
4002  }
4003  $canSend = $this->isEmailConfirmed();
4004  wfRunHooks( 'UserCanSendEmail', array( &$this, &$canSend ) );
4005  return $canSend;
4006  }
4007 
4013  public function canReceiveEmail() {
4014  return $this->isEmailConfirmed() && !$this->getOption( 'disablemail' );
4015  }
4016 
4027  public function isEmailConfirmed() {
4028  global $wgEmailAuthentication;
4029  $this->load();
4030  $confirmed = true;
4031  if ( wfRunHooks( 'EmailConfirmed', array( &$this, &$confirmed ) ) ) {
4032  if ( $this->isAnon() ) {
4033  return false;
4034  }
4035  if ( !Sanitizer::validateEmail( $this->mEmail ) ) {
4036  return false;
4037  }
4038  if ( $wgEmailAuthentication && !$this->getEmailAuthenticationTimestamp() ) {
4039  return false;
4040  }
4041  return true;
4042  } else {
4043  return $confirmed;
4044  }
4045  }
4051  public function isEmailConfirmationPending() {
4052  global $wgEmailAuthentication;
4053  return $wgEmailAuthentication &&
4054  !$this->isEmailConfirmed() &&
4055  $this->mEmailToken &&
4056  $this->mEmailTokenExpires > wfTimestamp();
4057  }
4058 
4066  public function getRegistration() {
4067  if ( $this->isAnon() ) {
4068  return false;
4069  }
4070  $this->load();
4071  return $this->mRegistration;
4072  }
4073 
4080  public function getFirstEditTimestamp() {
4081  if ( $this->getId() == 0 ) {
4082  return false; // anons
4083  }
4084  $dbr = wfGetDB( DB_SLAVE );
4085  $time = $dbr->selectField( 'revision', 'rev_timestamp',
4086  array( 'rev_user' => $this->getId() ),
4087  __METHOD__,
4088  array( 'ORDER BY' => 'rev_timestamp ASC' )
4089  );
4090  if ( !$time ) {
4091  return false; // no edits
4092  }
4093  return wfTimestamp( TS_MW, $time );
4094  }
4095 
4102  public static function getGroupPermissions( $groups ) {
4103  global $wgGroupPermissions, $wgRevokePermissions;
4104  $rights = array();
4105  // grant every granted permission first
4106  foreach ( $groups as $group ) {
4107  if ( isset( $wgGroupPermissions[$group] ) ) {
4108  $rights = array_merge( $rights,
4109  // array_filter removes empty items
4110  array_keys( array_filter( $wgGroupPermissions[$group] ) ) );
4111  }
4112  }
4113  // now revoke the revoked permissions
4114  foreach ( $groups as $group ) {
4115  if ( isset( $wgRevokePermissions[$group] ) ) {
4116  $rights = array_diff( $rights,
4117  array_keys( array_filter( $wgRevokePermissions[$group] ) ) );
4118  }
4119  }
4120  return array_unique( $rights );
4121  }
4122 
4129  public static function getGroupsWithPermission( $role ) {
4130  global $wgGroupPermissions;
4131  $allowedGroups = array();
4132  foreach ( array_keys( $wgGroupPermissions ) as $group ) {
4133  if ( self::groupHasPermission( $group, $role ) ) {
4134  $allowedGroups[] = $group;
4135  }
4136  }
4137  return $allowedGroups;
4138  }
4139 
4152  public static function groupHasPermission( $group, $role ) {
4153  global $wgGroupPermissions, $wgRevokePermissions;
4154  return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
4155  && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
4156  }
4157 
4165  public static function isEveryoneAllowed( $right ) {
4166  global $wgGroupPermissions, $wgRevokePermissions;
4167  static $cache = array();
4168 
4169  // Use the cached results, except in unit tests which rely on
4170  // being able change the permission mid-request
4171  if ( isset( $cache[$right] ) && !defined( 'MW_PHPUNIT_TEST' ) ) {
4172  return $cache[$right];
4173  }
4174 
4175  if ( !isset( $wgGroupPermissions['*'][$right] ) || !$wgGroupPermissions['*'][$right] ) {
4176  $cache[$right] = false;
4177  return false;
4178  }
4179 
4180  // If it's revoked anywhere, then everyone doesn't have it
4181  foreach ( $wgRevokePermissions as $rights ) {
4182  if ( isset( $rights[$right] ) && $rights[$right] ) {
4183  $cache[$right] = false;
4184  return false;
4185  }
4186  }
4187 
4188  // Allow extensions (e.g. OAuth) to say false
4189  if ( !wfRunHooks( 'UserIsEveryoneAllowed', array( $right ) ) ) {
4190  $cache[$right] = false;
4191  return false;
4192  }
4193 
4194  $cache[$right] = true;
4195  return true;
4196  }
4197 
4204  public static function getGroupName( $group ) {
4205  $msg = wfMessage( "group-$group" );
4206  return $msg->isBlank() ? $group : $msg->text();
4207  }
4208 
4216  public static function getGroupMember( $group, $username = '#' ) {
4217  $msg = wfMessage( "group-$group-member", $username );
4218  return $msg->isBlank() ? $group : $msg->text();
4219  }
4220 
4227  public static function getAllGroups() {
4228  global $wgGroupPermissions, $wgRevokePermissions;
4229  return array_diff(
4230  array_merge( array_keys( $wgGroupPermissions ), array_keys( $wgRevokePermissions ) ),
4231  self::getImplicitGroups()
4232  );
4233  }
4239  public static function getAllRights() {
4240  if ( self::$mAllRights === false ) {
4241  global $wgAvailableRights;
4242  if ( count( $wgAvailableRights ) ) {
4243  self::$mAllRights = array_unique( array_merge( self::$mCoreRights, $wgAvailableRights ) );
4244  } else {
4245  self::$mAllRights = self::$mCoreRights;
4246  }
4247  wfRunHooks( 'UserGetAllRights', array( &self::$mAllRights ) );
4248  }
4249  return self::$mAllRights;
4250  }
4256  public static function getImplicitGroups() {
4257  global $wgImplicitGroups;
4258  $groups = $wgImplicitGroups;
4259  wfRunHooks( 'UserGetImplicitGroups', array( &$groups ) ); #deprecated, use $wgImplictGroups instead
4260  return $groups;
4261  }
4262 
4269  public static function getGroupPage( $group ) {
4270  $msg = wfMessage( 'grouppage-' . $group )->inContentLanguage();
4271  if ( $msg->exists() ) {
4272  $title = Title::newFromText( $msg->text() );
4273  if ( is_object( $title ) ) {
4274  return $title;
4275  }
4276  }
4277  return false;
4278  }
4279 
4288  public static function makeGroupLinkHTML( $group, $text = '' ) {
4289  if ( $text == '' ) {
4290  $text = self::getGroupName( $group );
4291  }
4292  $title = self::getGroupPage( $group );
4293  if ( $title ) {
4294  return Linker::link( $title, htmlspecialchars( $text ) );
4295  } else {
4296  return $text;
4297  }
4298  }
4299 
4308  public static function makeGroupLinkWiki( $group, $text = '' ) {
4309  if ( $text == '' ) {
4310  $text = self::getGroupName( $group );
4311  }
4312  $title = self::getGroupPage( $group );
4313  if ( $title ) {
4314  $page = $title->getPrefixedText();
4315  return "[[$page|$text]]";
4316  } else {
4317  return $text;
4318  }
4319  }
4320 
4330  public static function changeableByGroup( $group ) {
4331  global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
4332 
4333  $groups = array( 'add' => array(), 'remove' => array(), 'add-self' => array(), 'remove-self' => array() );
4334  if ( empty( $wgAddGroups[$group] ) ) {
4335  // Don't add anything to $groups
4336  } elseif ( $wgAddGroups[$group] === true ) {
4337  // You get everything
4338  $groups['add'] = self::getAllGroups();
4339  } elseif ( is_array( $wgAddGroups[$group] ) ) {
4340  $groups['add'] = $wgAddGroups[$group];
4341  }
4342 
4343  // Same thing for remove
4344  if ( empty( $wgRemoveGroups[$group] ) ) {
4345  } elseif ( $wgRemoveGroups[$group] === true ) {
4346  $groups['remove'] = self::getAllGroups();
4347  } elseif ( is_array( $wgRemoveGroups[$group] ) ) {
4348  $groups['remove'] = $wgRemoveGroups[$group];
4349  }
4350 
4351  // Re-map numeric keys of AddToSelf/RemoveFromSelf to the 'user' key for backwards compatibility
4352  if ( empty( $wgGroupsAddToSelf['user'] ) || $wgGroupsAddToSelf['user'] !== true ) {
4353  foreach ( $wgGroupsAddToSelf as $key => $value ) {
4354  if ( is_int( $key ) ) {
4355  $wgGroupsAddToSelf['user'][] = $value;
4356  }
4357  }
4358  }
4359 
4360  if ( empty( $wgGroupsRemoveFromSelf['user'] ) || $wgGroupsRemoveFromSelf['user'] !== true ) {
4361  foreach ( $wgGroupsRemoveFromSelf as $key => $value ) {
4362  if ( is_int( $key ) ) {
4363  $wgGroupsRemoveFromSelf['user'][] = $value;
4364  }
4365  }
4366  }
4367 
4368  // Now figure out what groups the user can add to him/herself
4369  if ( empty( $wgGroupsAddToSelf[$group] ) ) {
4370  } elseif ( $wgGroupsAddToSelf[$group] === true ) {
4371  // No idea WHY this would be used, but it's there
4372  $groups['add-self'] = User::getAllGroups();
4373  } elseif ( is_array( $wgGroupsAddToSelf[$group] ) ) {
4374  $groups['add-self'] = $wgGroupsAddToSelf[$group];
4375  }
4376 
4377  if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
4378  } elseif ( $wgGroupsRemoveFromSelf[$group] === true ) {
4379  $groups['remove-self'] = User::getAllGroups();
4380  } elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {
4381  $groups['remove-self'] = $wgGroupsRemoveFromSelf[$group];
4382  }
4383 
4384  return $groups;
4385  }
4386 
4394  public function changeableGroups() {
4395  if ( $this->isAllowed( 'userrights' ) ) {
4396  // This group gives the right to modify everything (reverse-
4397  // compatibility with old "userrights lets you change
4398  // everything")
4399  // Using array_merge to make the groups reindexed
4400  $all = array_merge( User::getAllGroups() );
4401  return array(
4402  'add' => $all,
4403  'remove' => $all,
4404  'add-self' => array(),
4405  'remove-self' => array()
4406  );
4407  }
4408 
4409  // Okay, it's not so simple, we will have to go through the arrays
4410  $groups = array(
4411  'add' => array(),
4412  'remove' => array(),
4413  'add-self' => array(),
4414  'remove-self' => array()
4415  );
4416  $addergroups = $this->getEffectiveGroups();
4417 
4418  foreach ( $addergroups as $addergroup ) {
4419  $groups = array_merge_recursive(
4420  $groups, $this->changeableByGroup( $addergroup )
4421  );
4422  $groups['add'] = array_unique( $groups['add'] );
4423  $groups['remove'] = array_unique( $groups['remove'] );
4424  $groups['add-self'] = array_unique( $groups['add-self'] );
4425  $groups['remove-self'] = array_unique( $groups['remove-self'] );
4426  }
4427  return $groups;
4428  }
4434  public function incEditCount() {
4435  if ( !$this->isAnon() ) {
4436  $dbw = wfGetDB( DB_MASTER );
4437  $dbw->update(
4438  'user',
4439  array( 'user_editcount=user_editcount+1' ),
4440  array( 'user_id' => $this->getId() ),
4441  __METHOD__
4442  );
4443 
4444  // Lazy initialization check...
4445  if ( $dbw->affectedRows() == 0 ) {
4446  // Now here's a goddamn hack...
4447  $dbr = wfGetDB( DB_SLAVE );
4448  if ( $dbr !== $dbw ) {
4449  // If we actually have a slave server, the count is
4450  // at least one behind because the current transaction
4451  // has not been committed and replicated.
4452  $this->initEditCount( 1 );
4453  } else {
4454  // But if DB_SLAVE is selecting the master, then the
4455  // count we just read includes the revision that was
4456  // just added in the working transaction.
4457  $this->initEditCount();
4458  }
4459  }
4460  }
4461  // edit count in user cache too
4462  $this->invalidateCache();
4463  }
4464 
4471  protected function initEditCount( $add = 0 ) {
4472  // Pull from a slave to be less cruel to servers
4473  // Accuracy isn't the point anyway here
4474  $dbr = wfGetDB( DB_SLAVE );
4475  $count = (int)$dbr->selectField(
4476  'revision',
4477  'COUNT(rev_user)',
4478  array( 'rev_user' => $this->getId() ),
4479  __METHOD__
4480  );
4481  $count = $count + $add;
4482 
4483  $dbw = wfGetDB( DB_MASTER );
4484  $dbw->update(
4485  'user',
4486  array( 'user_editcount' => $count ),
4487  array( 'user_id' => $this->getId() ),
4488  __METHOD__
4489  );
4490 
4491  return $count;
4492  }
4493 
4500  public static function getRightDescription( $right ) {
4501  $key = "right-$right";
4502  $msg = wfMessage( $key );
4503  return $msg->isBlank() ? $right : $msg->text();
4504  }
4505 
4513  public static function oldCrypt( $password, $userId ) {
4514  global $wgPasswordSalt;
4515  if ( $wgPasswordSalt ) {
4516  return md5( $userId . '-' . md5( $password ) );
4517  } else {
4518  return md5( $password );
4519  }
4520  }
4521 
4530  public static function crypt( $password, $salt = false ) {
4531  global $wgPasswordSalt;
4532 
4533  $hash = '';
4534  if ( !wfRunHooks( 'UserCryptPassword', array( &$password, &$salt, &$wgPasswordSalt, &$hash ) ) ) {
4535  return $hash;
4536  }
4537 
4538  if ( $wgPasswordSalt ) {
4539  if ( $salt === false ) {
4540  $salt = MWCryptRand::generateHex( 8 );
4541  }
4542  return ':B:' . $salt . ':' . md5( $salt . '-' . md5( $password ) );
4543  } else {
4544  return ':A:' . md5( $password );
4545  }
4546  }
4547 
4558  public static function comparePasswords( $hash, $password, $userId = false ) {
4559  $type = substr( $hash, 0, 3 );
4560 
4561  $result = false;
4562  if ( !wfRunHooks( 'UserComparePasswords', array( &$hash, &$password, &$userId, &$result ) ) ) {
4563  return $result;
4564  }
4565 
4566  if ( $type == ':A:' ) {
4567  // Unsalted
4568  return md5( $password ) === substr( $hash, 3 );
4569  } elseif ( $type == ':B:' ) {
4570  // Salted
4571  list( $salt, $realHash ) = explode( ':', substr( $hash, 3 ), 2 );
4572  return md5( $salt . '-' . md5( $password ) ) === $realHash;
4573  } else {
4574  // Old-style
4575  return self::oldCrypt( $password, $userId ) === $hash;
4576  }
4577  }
4578 
4600  public function addNewUserLogEntry( $action = false, $reason = '' ) {
4601  global $wgUser, $wgNewUserLog;
4602  if ( empty( $wgNewUserLog ) ) {
4603  return true; // disabled
4604  }
4605 
4606  if ( $action === true ) {
4607  $action = 'byemail';
4608  } elseif ( $action === false ) {
4609  if ( $this->getName() == $wgUser->getName() ) {
4610  $action = 'create';
4611  } else {
4612  $action = 'create2';
4613  }
4614  }
4615 
4616  if ( $action === 'create' || $action === 'autocreate' ) {
4617  $performer = $this;
4618  } else {
4619  $performer = $wgUser;
4620  }
4621 
4622  $logEntry = new ManualLogEntry( 'newusers', $action );
4623  $logEntry->setPerformer( $performer );
4624  $logEntry->setTarget( $this->getUserPage() );
4625  $logEntry->setComment( $reason );
4626  $logEntry->setParameters( array(
4627  '4::userid' => $this->getId(),
4628  ) );
4629  $logid = $logEntry->insert();
4630 
4631  if ( $action !== 'autocreate' ) {
4632  $logEntry->publish( $logid );
4633  }
4634 
4635  return (int)$logid;
4636  }
4637 
4645  public function addNewUserLogEntryAutoCreate() {
4646  $this->addNewUserLogEntry( 'autocreate' );
4647 
4648  return true;
4649  }
4650 
4656  protected function loadOptions( $data = null ) {
4658 
4659  $this->load();
4660 
4661  if ( $this->mOptionsLoaded ) {
4662  return;
4663  }
4664 
4665  $this->mOptions = self::getDefaultOptions();
4666 
4667  if ( !$this->getId() ) {
4668  // For unlogged-in users, load language/variant options from request.
4669  // There's no need to do it for logged-in users: they can set preferences,
4670  // and handling of page content is done by $pageLang->getPreferredVariant() and such,
4671  // so don't override user's choice (especially when the user chooses site default).
4672  $variant = $wgContLang->getDefaultVariant();
4673  $this->mOptions['variant'] = $variant;
4674  $this->mOptions['language'] = $variant;
4675  $this->mOptionsLoaded = true;
4676  return;
4677  }
4678 
4679  // Maybe load from the object
4680  if ( !is_null( $this->mOptionOverrides ) ) {
4681  wfDebug( "User: loading options for user " . $this->getId() . " from override cache.\n" );
4682  foreach ( $this->mOptionOverrides as $key => $value ) {
4683  $this->mOptions[$key] = $value;
4684  }
4685  } else {
4686  if ( !is_array( $data ) ) {
4687  wfDebug( "User: loading options for user " . $this->getId() . " from database.\n" );
4688  // Load from database
4689  $dbr = wfGetDB( DB_SLAVE );
4690 
4691  $res = $dbr->select(
4692  'user_properties',
4693  array( 'up_property', 'up_value' ),
4694  array( 'up_user' => $this->getId() ),
4695  __METHOD__
4696  );
4697 
4698  $this->mOptionOverrides = array();
4699  $data = array();
4700  foreach ( $res as $row ) {
4701  $data[$row->up_property] = $row->up_value;
4702  }
4703  }
4704  foreach ( $data as $property => $value ) {
4705  $this->mOptionOverrides[$property] = $value;
4706  $this->mOptions[$property] = $value;
4707  }
4708  }
4709 
4710  $this->mOptionsLoaded = true;
4711 
4712  wfRunHooks( 'UserLoadOptions', array( $this, &$this->mOptions ) );
4713  }
4714 
4718  protected function saveOptions() {
4719  $this->loadOptions();
4720 
4721  // Not using getOptions(), to keep hidden preferences in database
4722  $saveOptions = $this->mOptions;
4723 
4724  // Allow hooks to abort, for instance to save to a global profile.
4725  // Reset options to default state before saving.
4726  if ( !wfRunHooks( 'UserSaveOptions', array( $this, &$saveOptions ) ) ) {
4727  return;
4728  }
4729 
4730  $userId = $this->getId();
4731  $insert_rows = array();
4732  foreach ( $saveOptions as $key => $value ) {
4733  // Don't bother storing default values
4734  $defaultOption = self::getDefaultOption( $key );
4735  if ( ( is_null( $defaultOption ) &&
4736  !( $value === false || is_null( $value ) ) ) ||
4737  $value != $defaultOption
4738  ) {
4739  $insert_rows[] = array(
4740  'up_user' => $userId,
4741  'up_property' => $key,
4742  'up_value' => $value,
4743  );
4744  }
4745  }
4746 
4747  $dbw = wfGetDB( DB_MASTER );
4748  // Find and delete any prior preference rows...
4749  $res = $dbw->select( 'user_properties',
4750  array( 'up_property' ), array( 'up_user' => $userId ), __METHOD__ );
4751  $priorKeys = array();
4752  foreach ( $res as $row ) {
4753  $priorKeys[] = $row->up_property;
4754  }
4755  if ( count( $priorKeys ) ) {
4756  // Do the DELETE by PRIMARY KEY for prior rows.
4757  // In the past a very large portion of calls to this function are for setting
4758  // 'rememberpassword' for new accounts (a preference that has since been removed).
4759  // Doing a blanket per-user DELETE for new accounts with no rows in the table
4760  // caused gap locks on [max user ID,+infinity) which caused high contention since
4761  // updates would pile up on each other as they are for higher (newer) user IDs.
4762  // It might not be necessary these days, but it shouldn't hurt either.
4763  $dbw->delete( 'user_properties',
4764  array( 'up_user' => $userId, 'up_property' => $priorKeys ), __METHOD__ );
4765  }
4766  // Insert the new preference rows
4767  $dbw->insert( 'user_properties', $insert_rows, __METHOD__, array( 'IGNORE' ) );
4768  }
4769 
4793  public static function passwordChangeInputAttribs() {
4794  global $wgMinimalPasswordLength;
4795 
4796  if ( $wgMinimalPasswordLength == 0 ) {
4797  return array();
4798  }
4799 
4800  # Note that the pattern requirement will always be satisfied if the
4801  # input is empty, so we need required in all cases.
4802  #
4803  # @todo FIXME: Bug 23769: This needs to not claim the password is required
4804  # if e-mail confirmation is being used. Since HTML5 input validation
4805  # is b0rked anyway in some browsers, just return nothing. When it's
4806  # re-enabled, fix this code to not output required for e-mail
4807  # registration.
4808  #$ret = array( 'required' );
4809  $ret = array();
4810 
4811  # We can't actually do this right now, because Opera 9.6 will print out
4812  # the entered password visibly in its error message! When other
4813  # browsers add support for this attribute, or Opera fixes its support,
4814  # we can add support with a version check to avoid doing this on Opera
4815  # versions where it will be a problem. Reported to Opera as
4816  # DSK-262266, but they don't have a public bug tracker for us to follow.
4817  /*
4818  if ( $wgMinimalPasswordLength > 1 ) {
4819  $ret['pattern'] = '.{' . intval( $wgMinimalPasswordLength ) . ',}';
4820  $ret['title'] = wfMessage( 'passwordtooshort' )
4821  ->numParams( $wgMinimalPasswordLength )->text();
4822  }
4823  */
4824 
4825  return $ret;
4826  }
4827 
4833  public static function selectFields() {
4834  return array(
4835  'user_id',
4836  'user_name',
4837  'user_real_name',
4838  'user_password',
4839  'user_newpassword',
4840  'user_newpass_time',
4841  'user_email',
4842  'user_touched',
4843  'user_token',
4844  'user_email_authenticated',
4845  'user_email_token',
4846  'user_email_token_expires',
4847  'user_password_expires',
4848  'user_registration',
4849  'user_editcount',
4850  );
4851  }
4852 
4860  static function newFatalPermissionDeniedStatus( $permission ) {
4861  global $wgLang;
4862 
4863  $groups = array_map(
4864  array( 'User', 'makeGroupLinkWiki' ),
4865  User::getGroupsWithPermission( $permission )
4866  );
4867 
4868  if ( $groups ) {
4869  return Status::newFatal( 'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
4870  } else {
4871  return Status::newFatal( 'badaccess-group0' );
4872  }
4873  }
4874 }
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:3135
User\$mHash
$mHash
Bool Whether the cache variables have been loaded.
Definition: User.php:220
User\saveOptions
saveOptions()
Definition: User.php:4713
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:886
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:4788
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:2915
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:3912
DB_MASTER
const DB_MASTER
Definition: Defines.php:56
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:4186
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:4303
User\isAnon
isAnon()
Get whether the user is anonymous.
Definition: User.php:2988
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:3939
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:4855
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:2884
User\spreadBlock
spreadBlock()
If this (non-anonymous) user is blocked, block the IP address they've successfully logged in from.
Definition: User.php:3596
User\incEditCount
incEditCount()
Increment the user's edit-count field.
Definition: User.php:4429
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:1089
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:3706
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:4046
$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:3745
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:3584
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:2702
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:4651
User\makeGroupLinkHTML
static makeGroupLinkHTML( $group, $text='')
Create a link to the group in HTML, if available; else return the group name.
Definition: User.php:4283
$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:2803
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:1847
User\comparePasswords
static comparePasswords( $hash, $password, $userId=false)
Compare a password hash with a plain-text password.
Definition: User.php:4553
$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:970
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:3982
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:3276
User\getUserPage
getUserPage()
Get this user's personal page title.
Definition: User.php:3654
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:2798
$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:3059
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:3833
User\groupHasPermission
static groupHasPermission( $group, $role)
Check, if the given group has the given permission.
Definition: User.php:4147
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:4466
User\useRCPatrol
useRCPatrol()
Check whether to enable recent changes patrol features for this user.
Definition: User.php:3050
User\invalidateEmail
invalidateEmail()
Invalidate the user's e-mail confirmation, and unauthenticate the e-mail address if it was already co...
Definition: User.php:3969
$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:3072
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:2834
User\generateToken
static generateToken()
Generate a looking random token for various uses.
Definition: User.php:3788
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:3663
$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:3803
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:3521
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:3101
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:3921
wfMemcKey
wfMemcKey()
Get a cache key.
Definition: GlobalFunctions.php:3627
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:3952
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:3124
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:3645
User\logout
logout()
Log this user out.
Definition: User.php:3354
User\confirmationToken
confirmationToken(&$expiration)
Generate, store, and return a new e-mail confirmation code.
Definition: User.php:3894
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:4251
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:3636
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4058
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:2811
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:2947
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:4008
User\isNewbie
isNewbie()
Determine whether the user is a newbie.
Definition: User.php:3673
User\isAllowedAll
isAllowedAll()
Is the input a valid password for this user?
Definition: User.php:3015
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:2843
$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:3262
User\createNew
static createNew( $name, $params=array())
Add a user to the database, return the user object.
Definition: User.php:3458
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:2702
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:3160
User\saveSettings
saveSettings()
Save this user's settings into the database.
Definition: User.php:3381
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:4595
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:1010
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:4075
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:3660
User\idForName
idForName()
If only this user's username is known, and it exists, return the user ID.
Definition: User.php:3428
$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:2865
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:1306
User\setCookies
setCookies( $request=null, $secure=null, $rememberMe=false)
Set the default cookies for this session on the user's client.
Definition: User.php:3288
User\getGroupPermissions
static getGroupPermissions( $groups)
Get the permissions associated with a given list of groups.
Definition: User.php:4097
User\getGroupPage
static getGroupPage( $group)
Get the title of a page describing a particular group.
Definition: User.php:4264
User\matchEditTokenNoSuffix
matchEditTokenNoSuffix( $val, $salt='', $request=null)
Check given value against the token value stored in the session, ignoring the suffix.
Definition: User.php:3821
User\changeableGroups
changeableGroups()
Returns an array of groups that this user can add and remove.
Definition: User.php:4389
User\clearAllNotifications
clearAllNotifications()
Resets all of the given user's page-change notification timestamps.
Definition: User.php:3221
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:4525
User\checkPassword
checkPassword( $password)
Check to see if the given clear-text password is one of the accepted passwords.
Definition: User.php:3682
User\getAllGroups
static getAllGroups()
Return the set of defined explicit groups.
Definition: User.php:4222
User\getAllRights
static getAllRights()
Get a list of all available permissions.
Definition: User.php:4234
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:4211
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:2702
$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:2702
$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:4325
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:4199
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:4061
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:4160
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:3000
User\getRightDescription
static getRightDescription( $right)
Get the description of a given right.
Definition: User.php:4495
$cache
$cache
Definition: mcc.php:32
User\isLoggedIn
isLoggedIn()
Get whether the user is logged in.
Definition: User.php:2980
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:3722
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:3424
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:4022
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:3871
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:3087
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:4828
$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:4640
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:3147
$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:2578
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:3615
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:3762
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
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:3364
User\canSendEmail
canSendEmail()
Is this user allowed to send e-mails within limits of current site configuration?
Definition: User.php:3993
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:4508
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:4124
User\isAllowed
isAllowed( $action='')
Internal mechanics of testing a permission.
Definition: User.php:3030
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