MediaWiki  1.23.8
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  $length = $length * 1.25;
962  // Generate random hex chars
963  $hex = MWCryptRand::generateHex( $length );
964  // Convert from base 16 to base 32 to get a proper password like string
965  return wfBaseConvert( $hex, 16, 32 );
966  }
967 
976  public function loadDefaults( $name = false ) {
977  wfProfileIn( __METHOD__ );
978 
979  $this->mId = 0;
980  $this->mName = $name;
981  $this->mRealName = '';
982  $this->mPassword = $this->mNewpassword = '';
983  $this->mNewpassTime = null;
984  $this->mEmail = '';
985  $this->mOptionOverrides = null;
986  $this->mOptionsLoaded = false;
987 
988  $loggedOut = $this->getRequest()->getCookie( 'LoggedOut' );
989  if ( $loggedOut !== null ) {
990  $this->mTouched = wfTimestamp( TS_MW, $loggedOut );
991  } else {
992  $this->mTouched = '1'; # Allow any pages to be cached
993  }
994 
995  $this->mToken = null; // Don't run cryptographic functions till we need a token
996  $this->mEmailAuthenticated = null;
997  $this->mEmailToken = '';
998  $this->mEmailTokenExpires = null;
999  $this->mPasswordExpires = null;
1000  $this->resetPasswordExpiration( false );
1001  $this->mRegistration = wfTimestamp( TS_MW );
1002  $this->mGroups = array();
1003 
1004  wfRunHooks( 'UserLoadDefaults', array( $this, $name ) );
1005 
1006  wfProfileOut( __METHOD__ );
1007  }
1008 
1021  public function isItemLoaded( $item, $all = 'all' ) {
1022  return ( $this->mLoadedItems === true && $all === 'all' ) ||
1023  ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] === true );
1024  }
1025 
1031  protected function setItemLoaded( $item ) {
1032  if ( is_array( $this->mLoadedItems ) ) {
1033  $this->mLoadedItems[$item] = true;
1034  }
1035  }
1041  private function loadFromSession() {
1042  $result = null;
1043  wfRunHooks( 'UserLoadFromSession', array( $this, &$result ) );
1044  if ( $result !== null ) {
1045  return $result;
1046  }
1047 
1048  $request = $this->getRequest();
1049 
1050  $cookieId = $request->getCookie( 'UserID' );
1051  $sessId = $request->getSessionData( 'wsUserID' );
1052 
1053  if ( $cookieId !== null ) {
1054  $sId = intval( $cookieId );
1055  if ( $sessId !== null && $cookieId != $sessId ) {
1056  wfDebugLog( 'loginSessions', "Session user ID ($sessId) and
1057  cookie user ID ($sId) don't match!" );
1058  return false;
1059  }
1060  $request->setSessionData( 'wsUserID', $sId );
1061  } elseif ( $sessId !== null && $sessId != 0 ) {
1062  $sId = $sessId;
1063  } else {
1064  return false;
1065  }
1066 
1067  if ( $request->getSessionData( 'wsUserName' ) !== null ) {
1068  $sName = $request->getSessionData( 'wsUserName' );
1069  } elseif ( $request->getCookie( 'UserName' ) !== null ) {
1070  $sName = $request->getCookie( 'UserName' );
1071  $request->setSessionData( 'wsUserName', $sName );
1072  } else {
1073  return false;
1074  }
1075 
1076  $proposedUser = User::newFromId( $sId );
1077  if ( !$proposedUser->isLoggedIn() ) {
1078  // Not a valid ID
1079  return false;
1080  }
1081 
1082  global $wgBlockDisablesLogin;
1083  if ( $wgBlockDisablesLogin && $proposedUser->isBlocked() ) {
1084  // User blocked and we've disabled blocked user logins
1085  return false;
1086  }
1087 
1088  if ( $request->getSessionData( 'wsToken' ) ) {
1089  $passwordCorrect = ( $proposedUser->getToken( false ) === $request->getSessionData( 'wsToken' ) );
1090  $from = 'session';
1091  } elseif ( $request->getCookie( 'Token' ) ) {
1092  # Get the token from DB/cache and clean it up to remove garbage padding.
1093  # This deals with historical problems with bugs and the default column value.
1094  $token = rtrim( $proposedUser->getToken( false ) ); // correct token
1095  // Make comparison in constant time (bug 61346)
1096  $passwordCorrect = strlen( $token ) && $this->compareSecrets( $token, $request->getCookie( 'Token' ) );
1097  $from = 'cookie';
1098  } else {
1099  // No session or persistent login cookie
1100  return false;
1101  }
1102 
1103  if ( ( $sName === $proposedUser->getName() ) && $passwordCorrect ) {
1104  $this->loadFromUserObject( $proposedUser );
1105  $request->setSessionData( 'wsToken', $this->mToken );
1106  wfDebug( "User: logged in from $from\n" );
1107  return true;
1108  } else {
1109  // Invalid credentials
1110  wfDebug( "User: can't log in from $from, invalid credentials\n" );
1111  return false;
1112  }
1113  }
1114 
1121  protected function compareSecrets( $answer, $test ) {
1122  if ( strlen( $answer ) !== strlen( $test ) ) {
1123  $passwordCorrect = false;
1124  } else {
1125  $result = 0;
1126  for ( $i = 0; $i < strlen( $answer ); $i++ ) {
1127  $result |= ord( $answer[$i] ) ^ ord( $test[$i] );
1128  }
1129  $passwordCorrect = ( $result == 0 );
1130  }
1131  return $passwordCorrect;
1132  }
1133 
1140  public function loadFromDatabase() {
1141  // Paranoia
1142  $this->mId = intval( $this->mId );
1143 
1144  // Anonymous user
1145  if ( !$this->mId ) {
1146  $this->loadDefaults();
1147  return false;
1148  }
1149 
1150  $dbr = wfGetDB( DB_MASTER );
1151  $s = $dbr->selectRow( 'user', self::selectFields(), array( 'user_id' => $this->mId ), __METHOD__ );
1152 
1153  wfRunHooks( 'UserLoadFromDatabase', array( $this, &$s ) );
1154 
1155  if ( $s !== false ) {
1156  // Initialise user table data
1157  $this->loadFromRow( $s );
1158  $this->mGroups = null; // deferred
1159  $this->getEditCount(); // revalidation for nulls
1160  return true;
1161  } else {
1162  // Invalid user_id
1163  $this->mId = 0;
1164  $this->loadDefaults();
1165  return false;
1166  }
1167  }
1168 
1178  public function loadFromRow( $row, $data = null ) {
1179  $all = true;
1180 
1181  $this->mGroups = null; // deferred
1182 
1183  if ( isset( $row->user_name ) ) {
1184  $this->mName = $row->user_name;
1185  $this->mFrom = 'name';
1186  $this->setItemLoaded( 'name' );
1187  } else {
1188  $all = false;
1189  }
1190 
1191  if ( isset( $row->user_real_name ) ) {
1192  $this->mRealName = $row->user_real_name;
1193  $this->setItemLoaded( 'realname' );
1194  } else {
1195  $all = false;
1196  }
1197 
1198  if ( isset( $row->user_id ) ) {
1199  $this->mId = intval( $row->user_id );
1200  $this->mFrom = 'id';
1201  $this->setItemLoaded( 'id' );
1202  } else {
1203  $all = false;
1204  }
1205 
1206  if ( isset( $row->user_editcount ) ) {
1207  $this->mEditCount = $row->user_editcount;
1208  } else {
1209  $all = false;
1210  }
1211 
1212  if ( isset( $row->user_password ) ) {
1213  $this->mPassword = $row->user_password;
1214  $this->mNewpassword = $row->user_newpassword;
1215  $this->mNewpassTime = wfTimestampOrNull( TS_MW, $row->user_newpass_time );
1216  $this->mEmail = $row->user_email;
1217  $this->mTouched = wfTimestamp( TS_MW, $row->user_touched );
1218  $this->mToken = $row->user_token;
1219  if ( $this->mToken == '' ) {
1220  $this->mToken = null;
1221  }
1222  $this->mEmailAuthenticated = wfTimestampOrNull( TS_MW, $row->user_email_authenticated );
1223  $this->mEmailToken = $row->user_email_token;
1224  $this->mEmailTokenExpires = wfTimestampOrNull( TS_MW, $row->user_email_token_expires );
1225  $this->mPasswordExpires = wfTimestampOrNull( TS_MW, $row->user_password_expires );
1226  $this->mRegistration = wfTimestampOrNull( TS_MW, $row->user_registration );
1227  } else {
1228  $all = false;
1229  }
1230 
1231  if ( $all ) {
1232  $this->mLoadedItems = true;
1233  }
1234 
1235  if ( is_array( $data ) ) {
1236  if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) {
1237  $this->mGroups = $data['user_groups'];
1238  }
1239  if ( isset( $data['user_properties'] ) && is_array( $data['user_properties'] ) ) {
1240  $this->loadOptions( $data['user_properties'] );
1241  }
1242  }
1243  }
1244 
1250  protected function loadFromUserObject( $user ) {
1251  $user->load();
1252  $user->loadGroups();
1253  $user->loadOptions();
1254  foreach ( self::$mCacheVars as $var ) {
1255  $this->$var = $user->$var;
1256  }
1257  }
1258 
1262  private function loadGroups() {
1263  if ( is_null( $this->mGroups ) ) {
1264  $dbr = wfGetDB( DB_MASTER );
1265  $res = $dbr->select( 'user_groups',
1266  array( 'ug_group' ),
1267  array( 'ug_user' => $this->mId ),
1268  __METHOD__ );
1269  $this->mGroups = array();
1270  foreach ( $res as $row ) {
1271  $this->mGroups[] = $row->ug_group;
1272  }
1273  }
1274  }
1275 
1290  public function addAutopromoteOnceGroups( $event ) {
1291  global $wgAutopromoteOnceLogInRC, $wgAuth;
1292 
1293  $toPromote = array();
1294  if ( $this->getId() ) {
1295  $toPromote = Autopromote::getAutopromoteOnceGroups( $this, $event );
1296  if ( count( $toPromote ) ) {
1297  $oldGroups = $this->getGroups(); // previous groups
1298 
1299  foreach ( $toPromote as $group ) {
1300  $this->addGroup( $group );
1301  }
1302  // update groups in external authentication database
1303  $wgAuth->updateExternalDBGroups( $this, $toPromote );
1304 
1305  $newGroups = array_merge( $oldGroups, $toPromote ); // all groups
1306 
1307  $logEntry = new ManualLogEntry( 'rights', 'autopromote' );
1308  $logEntry->setPerformer( $this );
1309  $logEntry->setTarget( $this->getUserPage() );
1310  $logEntry->setParameters( array(
1311  '4::oldgroups' => $oldGroups,
1312  '5::newgroups' => $newGroups,
1313  ) );
1314  $logid = $logEntry->insert();
1315  if ( $wgAutopromoteOnceLogInRC ) {
1316  $logEntry->publish( $logid );
1317  }
1318  }
1319  }
1320  return $toPromote;
1321  }
1322 
1331  public function clearInstanceCache( $reloadFrom = false ) {
1332  $this->mNewtalk = -1;
1333  $this->mDatePreference = null;
1334  $this->mBlockedby = -1; # Unset
1335  $this->mHash = false;
1336  $this->mRights = null;
1337  $this->mEffectiveGroups = null;
1338  $this->mImplicitGroups = null;
1339  $this->mGroups = null;
1340  $this->mOptions = null;
1341  $this->mOptionsLoaded = false;
1342  $this->mEditCount = null;
1343 
1344  if ( $reloadFrom ) {
1345  $this->mLoadedItems = array();
1346  $this->mFrom = $reloadFrom;
1347  }
1348  }
1349 
1356  public static function getDefaultOptions() {
1357  global $wgNamespacesToBeSearchedDefault, $wgDefaultUserOptions, $wgContLang, $wgDefaultSkin;
1358 
1359  static $defOpt = null;
1360  if ( !defined( 'MW_PHPUNIT_TEST' ) && $defOpt !== null ) {
1361  // Disabling this for the unit tests, as they rely on being able to change $wgContLang
1362  // mid-request and see that change reflected in the return value of this function.
1363  // Which is insane and would never happen during normal MW operation
1364  return $defOpt;
1365  }
1366 
1367  $defOpt = $wgDefaultUserOptions;
1368  // Default language setting
1369  $defOpt['language'] = $wgContLang->getCode();
1370  foreach ( LanguageConverter::$languagesWithVariants as $langCode ) {
1371  $defOpt[$langCode == $wgContLang->getCode() ? 'variant' : "variant-$langCode"] = $langCode;
1372  }
1373  foreach ( SearchEngine::searchableNamespaces() as $nsnum => $nsname ) {
1374  $defOpt['searchNs' . $nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
1375  }
1376  $defOpt['skin'] = $wgDefaultSkin;
1377 
1378  wfRunHooks( 'UserGetDefaultOptions', array( &$defOpt ) );
1379 
1380  return $defOpt;
1381  }
1382 
1389  public static function getDefaultOption( $opt ) {
1390  $defOpts = self::getDefaultOptions();
1391  if ( isset( $defOpts[$opt] ) ) {
1392  return $defOpts[$opt];
1393  } else {
1394  return null;
1395  }
1396  }
1397 
1405  private function getBlockedStatus( $bFromSlave = true ) {
1406  global $wgProxyWhitelist, $wgUser, $wgApplyIpBlocksToXff;
1407 
1408  if ( -1 != $this->mBlockedby ) {
1409  return;
1410  }
1411 
1412  wfProfileIn( __METHOD__ );
1413  wfDebug( __METHOD__ . ": checking...\n" );
1414 
1415  // Initialize data...
1416  // Otherwise something ends up stomping on $this->mBlockedby when
1417  // things get lazy-loaded later, causing false positive block hits
1418  // due to -1 !== 0. Probably session-related... Nothing should be
1419  // overwriting mBlockedby, surely?
1420  $this->load();
1421 
1422  # We only need to worry about passing the IP address to the Block generator if the
1423  # user is not immune to autoblocks/hardblocks, and they are the current user so we
1424  # know which IP address they're actually coming from
1425  if ( !$this->isAllowed( 'ipblock-exempt' ) && $this->getID() == $wgUser->getID() ) {
1426  $ip = $this->getRequest()->getIP();
1427  } else {
1428  $ip = null;
1429  }
1430 
1431  // User/IP blocking
1432  $block = Block::newFromTarget( $this, $ip, !$bFromSlave );
1433 
1434  // Proxy blocking
1435  if ( !$block instanceof Block && $ip !== null && !$this->isAllowed( 'proxyunbannable' )
1436  && !in_array( $ip, $wgProxyWhitelist )
1437  ) {
1438  // Local list
1439  if ( self::isLocallyBlockedProxy( $ip ) ) {
1440  $block = new Block;
1441  $block->setBlocker( wfMessage( 'proxyblocker' )->text() );
1442  $block->mReason = wfMessage( 'proxyblockreason' )->text();
1443  $block->setTarget( $ip );
1444  } elseif ( $this->isAnon() && $this->isDnsBlacklisted( $ip ) ) {
1445  $block = new Block;
1446  $block->setBlocker( wfMessage( 'sorbs' )->text() );
1447  $block->mReason = wfMessage( 'sorbsreason' )->text();
1448  $block->setTarget( $ip );
1449  }
1450  }
1451 
1452  // (bug 23343) Apply IP blocks to the contents of XFF headers, if enabled
1453  if ( !$block instanceof Block
1454  && $wgApplyIpBlocksToXff
1455  && $ip !== null
1456  && !$this->isAllowed( 'proxyunbannable' )
1457  && !in_array( $ip, $wgProxyWhitelist )
1458  ) {
1459  $xff = $this->getRequest()->getHeader( 'X-Forwarded-For' );
1460  $xff = array_map( 'trim', explode( ',', $xff ) );
1461  $xff = array_diff( $xff, array( $ip ) );
1462  $xffblocks = Block::getBlocksForIPList( $xff, $this->isAnon(), !$bFromSlave );
1463  $block = Block::chooseBlock( $xffblocks, $xff );
1464  if ( $block instanceof Block ) {
1465  # Mangle the reason to alert the user that the block
1466  # originated from matching the X-Forwarded-For header.
1467  $block->mReason = wfMessage( 'xffblockreason', $block->mReason )->text();
1468  }
1469  }
1470 
1471  if ( $block instanceof Block ) {
1472  wfDebug( __METHOD__ . ": Found block.\n" );
1473  $this->mBlock = $block;
1474  $this->mBlockedby = $block->getByName();
1475  $this->mBlockreason = $block->mReason;
1476  $this->mHideName = $block->mHideName;
1477  $this->mAllowUsertalk = !$block->prevents( 'editownusertalk' );
1478  } else {
1479  $this->mBlockedby = '';
1480  $this->mHideName = 0;
1481  $this->mAllowUsertalk = false;
1482  }
1483 
1484  // Extensions
1485  wfRunHooks( 'GetBlockedStatus', array( &$this ) );
1486 
1487  wfProfileOut( __METHOD__ );
1488  }
1489 
1497  public function isDnsBlacklisted( $ip, $checkWhitelist = false ) {
1498  global $wgEnableSorbs, $wgEnableDnsBlacklist,
1499  $wgSorbsUrl, $wgDnsBlacklistUrls, $wgProxyWhitelist;
1500 
1501  if ( !$wgEnableDnsBlacklist && !$wgEnableSorbs ) {
1502  return false;
1503  }
1504 
1505  if ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) ) {
1506  return false;
1507  }
1508 
1509  $urls = array_merge( $wgDnsBlacklistUrls, (array)$wgSorbsUrl );
1510  return $this->inDnsBlacklist( $ip, $urls );
1511  }
1512 
1520  public function inDnsBlacklist( $ip, $bases ) {
1521  wfProfileIn( __METHOD__ );
1522 
1523  $found = false;
1524  // @todo FIXME: IPv6 ??? (http://bugs.php.net/bug.php?id=33170)
1525  if ( IP::isIPv4( $ip ) ) {
1526  // Reverse IP, bug 21255
1527  $ipReversed = implode( '.', array_reverse( explode( '.', $ip ) ) );
1528 
1529  foreach ( (array)$bases as $base ) {
1530  // Make hostname
1531  // If we have an access key, use that too (ProjectHoneypot, etc.)
1532  if ( is_array( $base ) ) {
1533  if ( count( $base ) >= 2 ) {
1534  // Access key is 1, base URL is 0
1535  $host = "{$base[1]}.$ipReversed.{$base[0]}";
1536  } else {
1537  $host = "$ipReversed.{$base[0]}";
1538  }
1539  } else {
1540  $host = "$ipReversed.$base";
1541  }
1542 
1543  // Send query
1544  $ipList = gethostbynamel( $host );
1545 
1546  if ( $ipList ) {
1547  wfDebugLog( 'dnsblacklist', "Hostname $host is {$ipList[0]}, it's a proxy says $base!" );
1548  $found = true;
1549  break;
1550  } else {
1551  wfDebugLog( 'dnsblacklist', "Requested $host, not found in $base." );
1552  }
1553  }
1554  }
1555 
1556  wfProfileOut( __METHOD__ );
1557  return $found;
1558  }
1559 
1567  public static function isLocallyBlockedProxy( $ip ) {
1568  global $wgProxyList;
1569 
1570  if ( !$wgProxyList ) {
1571  return false;
1572  }
1573  wfProfileIn( __METHOD__ );
1574 
1575  if ( !is_array( $wgProxyList ) ) {
1576  // Load from the specified file
1577  $wgProxyList = array_map( 'trim', file( $wgProxyList ) );
1578  }
1579 
1580  if ( !is_array( $wgProxyList ) ) {
1581  $ret = false;
1582  } elseif ( array_search( $ip, $wgProxyList ) !== false ) {
1583  $ret = true;
1584  } elseif ( array_key_exists( $ip, $wgProxyList ) ) {
1585  // Old-style flipped proxy list
1586  $ret = true;
1587  } else {
1588  $ret = false;
1589  }
1590  wfProfileOut( __METHOD__ );
1591  return $ret;
1592  }
1593 
1599  public function isPingLimitable() {
1600  global $wgRateLimitsExcludedIPs;
1601  if ( in_array( $this->getRequest()->getIP(), $wgRateLimitsExcludedIPs ) ) {
1602  // No other good way currently to disable rate limits
1603  // for specific IPs. :P
1604  // But this is a crappy hack and should die.
1605  return false;
1606  }
1607  return !$this->isAllowed( 'noratelimit' );
1608  }
1609 
1621  public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
1622  // Call the 'PingLimiter' hook
1623  $result = false;
1624  if ( !wfRunHooks( 'PingLimiter', array( &$this, $action, &$result, $incrBy ) ) ) {
1625  return $result;
1626  }
1627 
1628  global $wgRateLimits;
1629  if ( !isset( $wgRateLimits[$action] ) ) {
1630  return false;
1631  }
1632 
1633  // Some groups shouldn't trigger the ping limiter, ever
1634  if ( !$this->isPingLimitable() ) {
1635  return false;
1636  }
1637 
1638  global $wgMemc;
1639  wfProfileIn( __METHOD__ );
1640 
1641  $limits = $wgRateLimits[$action];
1642  $keys = array();
1643  $id = $this->getId();
1644  $userLimit = false;
1645 
1646  if ( isset( $limits['anon'] ) && $id == 0 ) {
1647  $keys[wfMemcKey( 'limiter', $action, 'anon' )] = $limits['anon'];
1648  }
1649 
1650  if ( isset( $limits['user'] ) && $id != 0 ) {
1651  $userLimit = $limits['user'];
1652  }
1653  if ( $this->isNewbie() ) {
1654  if ( isset( $limits['newbie'] ) && $id != 0 ) {
1655  $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $limits['newbie'];
1656  }
1657  if ( isset( $limits['ip'] ) ) {
1658  $ip = $this->getRequest()->getIP();
1659  $keys["mediawiki:limiter:$action:ip:$ip"] = $limits['ip'];
1660  }
1661  if ( isset( $limits['subnet'] ) ) {
1662  $ip = $this->getRequest()->getIP();
1663  $matches = array();
1664  $subnet = false;
1665  if ( IP::isIPv6( $ip ) ) {
1666  $parts = IP::parseRange( "$ip/64" );
1667  $subnet = $parts[0];
1668  } elseif ( preg_match( '/^(\d+\.\d+\.\d+)\.\d+$/', $ip, $matches ) ) {
1669  // IPv4
1670  $subnet = $matches[1];
1671  }
1672  if ( $subnet !== false ) {
1673  $keys["mediawiki:limiter:$action:subnet:$subnet"] = $limits['subnet'];
1674  }
1675  }
1676  }
1677  // Check for group-specific permissions
1678  // If more than one group applies, use the group with the highest limit
1679  foreach ( $this->getGroups() as $group ) {
1680  if ( isset( $limits[$group] ) ) {
1681  if ( $userLimit === false || $limits[$group] > $userLimit ) {
1682  $userLimit = $limits[$group];
1683  }
1684  }
1685  }
1686  // Set the user limit key
1687  if ( $userLimit !== false ) {
1688  list( $max, $period ) = $userLimit;
1689  wfDebug( __METHOD__ . ": effective user limit: $max in {$period}s\n" );
1690  $keys[wfMemcKey( 'limiter', $action, 'user', $id )] = $userLimit;
1691  }
1692 
1693  $triggered = false;
1694  foreach ( $keys as $key => $limit ) {
1695  list( $max, $period ) = $limit;
1696  $summary = "(limit $max in {$period}s)";
1697  $count = $wgMemc->get( $key );
1698  // Already pinged?
1699  if ( $count ) {
1700  if ( $count >= $max ) {
1701  wfDebugLog( 'ratelimit', $this->getName() . " tripped! $key at $count $summary" );
1702  $triggered = true;
1703  } else {
1704  wfDebug( __METHOD__ . ": ok. $key at $count $summary\n" );
1705  }
1706  } else {
1707  wfDebug( __METHOD__ . ": adding record for $key $summary\n" );
1708  if ( $incrBy > 0 ) {
1709  $wgMemc->add( $key, 0, intval( $period ) ); // first ping
1710  }
1711  }
1712  if ( $incrBy > 0 ) {
1713  $wgMemc->incr( $key, $incrBy );
1714  }
1715  }
1716 
1717  wfProfileOut( __METHOD__ );
1718  return $triggered;
1719  }
1720 
1727  public function isBlocked( $bFromSlave = true ) { // hacked from false due to horrible probs on site
1728  return $this->getBlock( $bFromSlave ) instanceof Block && $this->getBlock()->prevents( 'edit' );
1729  }
1730 
1737  public function getBlock( $bFromSlave = true ) {
1738  $this->getBlockedStatus( $bFromSlave );
1739  return $this->mBlock instanceof Block ? $this->mBlock : null;
1740  }
1741 
1749  public function isBlockedFrom( $title, $bFromSlave = false ) {
1750  global $wgBlockAllowsUTEdit;
1751  wfProfileIn( __METHOD__ );
1752 
1753  $blocked = $this->isBlocked( $bFromSlave );
1754  $allowUsertalk = ( $wgBlockAllowsUTEdit ? $this->mAllowUsertalk : false );
1755  // If a user's name is suppressed, they cannot make edits anywhere
1756  if ( !$this->mHideName && $allowUsertalk && $title->getText() === $this->getName()
1757  && $title->getNamespace() == NS_USER_TALK ) {
1758  $blocked = false;
1759  wfDebug( __METHOD__ . ": self-talk page, ignoring any blocks\n" );
1760  }
1761 
1762  wfRunHooks( 'UserIsBlockedFrom', array( $this, $title, &$blocked, &$allowUsertalk ) );
1763 
1764  wfProfileOut( __METHOD__ );
1765  return $blocked;
1766  }
1772  public function blockedBy() {
1773  $this->getBlockedStatus();
1774  return $this->mBlockedby;
1775  }
1781  public function blockedFor() {
1782  $this->getBlockedStatus();
1783  return $this->mBlockreason;
1784  }
1790  public function getBlockId() {
1791  $this->getBlockedStatus();
1792  return ( $this->mBlock ? $this->mBlock->getId() : false );
1793  }
1794 
1803  public function isBlockedGlobally( $ip = '' ) {
1804  if ( $this->mBlockedGlobally !== null ) {
1805  return $this->mBlockedGlobally;
1806  }
1807  // User is already an IP?
1808  if ( IP::isIPAddress( $this->getName() ) ) {
1809  $ip = $this->getName();
1810  } elseif ( !$ip ) {
1811  $ip = $this->getRequest()->getIP();
1812  }
1813  $blocked = false;
1814  wfRunHooks( 'UserIsBlockedGlobally', array( &$this, $ip, &$blocked ) );
1815  $this->mBlockedGlobally = (bool)$blocked;
1816  return $this->mBlockedGlobally;
1817  }
1818 
1824  public function isLocked() {
1825  if ( $this->mLocked !== null ) {
1826  return $this->mLocked;
1827  }
1828  global $wgAuth;
1829  StubObject::unstub( $wgAuth );
1830  $authUser = $wgAuth->getUserInstance( $this );
1831  $this->mLocked = (bool)$authUser->isLocked();
1832  return $this->mLocked;
1833  }
1834 
1840  public function isHidden() {
1841  if ( $this->mHideName !== null ) {
1842  return $this->mHideName;
1843  }
1844  $this->getBlockedStatus();
1845  if ( !$this->mHideName ) {
1846  global $wgAuth;
1847  StubObject::unstub( $wgAuth );
1848  $authUser = $wgAuth->getUserInstance( $this );
1849  $this->mHideName = (bool)$authUser->isHidden();
1850  }
1851  return $this->mHideName;
1852  }
1858  public function getId() {
1859  if ( $this->mId === null && $this->mName !== null && User::isIP( $this->mName ) ) {
1860  // Special case, we know the user is anonymous
1861  return 0;
1862  } elseif ( !$this->isItemLoaded( 'id' ) ) {
1863  // Don't load if this was initialized from an ID
1864  $this->load();
1865  }
1866  return $this->mId;
1867  }
1873  public function setId( $v ) {
1874  $this->mId = $v;
1875  $this->clearInstanceCache( 'id' );
1876  }
1882  public function getName() {
1883  if ( $this->isItemLoaded( 'name', 'only' ) ) {
1884  // Special case optimisation
1885  return $this->mName;
1886  } else {
1887  $this->load();
1888  if ( $this->mName === false ) {
1889  // Clean up IPs
1890  $this->mName = IP::sanitizeIP( $this->getRequest()->getIP() );
1891  }
1892  return $this->mName;
1893  }
1894  }
1895 
1909  public function setName( $str ) {
1910  $this->load();
1911  $this->mName = $str;
1912  }
1918  public function getTitleKey() {
1919  return str_replace( ' ', '_', $this->getName() );
1920  }
1926  public function getNewtalk() {
1927  $this->load();
1928 
1929  // Load the newtalk status if it is unloaded (mNewtalk=-1)
1930  if ( $this->mNewtalk === -1 ) {
1931  $this->mNewtalk = false; # reset talk page status
1932 
1933  // Check memcached separately for anons, who have no
1934  // entire User object stored in there.
1935  if ( !$this->mId ) {
1936  global $wgDisableAnonTalk;
1937  if ( $wgDisableAnonTalk ) {
1938  // Anon newtalk disabled by configuration.
1939  $this->mNewtalk = false;
1940  } else {
1941  global $wgMemc;
1942  $key = wfMemcKey( 'newtalk', 'ip', $this->getName() );
1943  $newtalk = $wgMemc->get( $key );
1944  if ( strval( $newtalk ) !== '' ) {
1945  $this->mNewtalk = (bool)$newtalk;
1946  } else {
1947  // Since we are caching this, make sure it is up to date by getting it
1948  // from the master
1949  $this->mNewtalk = $this->checkNewtalk( 'user_ip', $this->getName(), true );
1950  $wgMemc->set( $key, (int)$this->mNewtalk, 1800 );
1951  }
1952  }
1953  } else {
1954  $this->mNewtalk = $this->checkNewtalk( 'user_id', $this->mId );
1955  }
1956  }
1957 
1958  return (bool)$this->mNewtalk;
1959  }
1960 
1974  public function getNewMessageLinks() {
1975  $talks = array();
1976  if ( !wfRunHooks( 'UserRetrieveNewTalks', array( &$this, &$talks ) ) ) {
1977  return $talks;
1978  } elseif ( !$this->getNewtalk() ) {
1979  return array();
1980  }
1981  $utp = $this->getTalkPage();
1982  $dbr = wfGetDB( DB_SLAVE );
1983  // Get the "last viewed rev" timestamp from the oldest message notification
1984  $timestamp = $dbr->selectField( 'user_newtalk',
1985  'MIN(user_last_timestamp)',
1986  $this->isAnon() ? array( 'user_ip' => $this->getName() ) : array( 'user_id' => $this->getID() ),
1987  __METHOD__ );
1989  return array( array( 'wiki' => wfWikiID(), 'link' => $utp->getLocalURL(), 'rev' => $rev ) );
1990  }
1991 
1997  public function getNewMessageRevisionId() {
1998  $newMessageRevisionId = null;
1999  $newMessageLinks = $this->getNewMessageLinks();
2000  if ( $newMessageLinks ) {
2001  // Note: getNewMessageLinks() never returns more than a single link
2002  // and it is always for the same wiki, but we double-check here in
2003  // case that changes some time in the future.
2004  if ( count( $newMessageLinks ) === 1
2005  && $newMessageLinks[0]['wiki'] === wfWikiID()
2006  && $newMessageLinks[0]['rev']
2007  ) {
2008  $newMessageRevision = $newMessageLinks[0]['rev'];
2009  $newMessageRevisionId = $newMessageRevision->getId();
2010  }
2011  }
2012  return $newMessageRevisionId;
2013  }
2014 
2024  protected function checkNewtalk( $field, $id, $fromMaster = false ) {
2025  if ( $fromMaster ) {
2026  $db = wfGetDB( DB_MASTER );
2027  } else {
2028  $db = wfGetDB( DB_SLAVE );
2029  }
2030  $ok = $db->selectField( 'user_newtalk', $field,
2031  array( $field => $id ), __METHOD__ );
2032  return $ok !== false;
2033  }
2034 
2042  protected function updateNewtalk( $field, $id, $curRev = null ) {
2043  // Get timestamp of the talk page revision prior to the current one
2044  $prevRev = $curRev ? $curRev->getPrevious() : false;
2045  $ts = $prevRev ? $prevRev->getTimestamp() : null;
2046  // Mark the user as having new messages since this revision
2047  $dbw = wfGetDB( DB_MASTER );
2048  $dbw->insert( 'user_newtalk',
2049  array( $field => $id, 'user_last_timestamp' => $dbw->timestampOrNull( $ts ) ),
2050  __METHOD__,
2051  'IGNORE' );
2052  if ( $dbw->affectedRows() ) {
2053  wfDebug( __METHOD__ . ": set on ($field, $id)\n" );
2054  return true;
2055  } else {
2056  wfDebug( __METHOD__ . " already set ($field, $id)\n" );
2057  return false;
2058  }
2059  }
2060 
2067  protected function deleteNewtalk( $field, $id ) {
2068  $dbw = wfGetDB( DB_MASTER );
2069  $dbw->delete( 'user_newtalk',
2070  array( $field => $id ),
2071  __METHOD__ );
2072  if ( $dbw->affectedRows() ) {
2073  wfDebug( __METHOD__ . ": killed on ($field, $id)\n" );
2074  return true;
2075  } else {
2076  wfDebug( __METHOD__ . ": already gone ($field, $id)\n" );
2077  return false;
2078  }
2079  }
2080 
2086  public function setNewtalk( $val, $curRev = null ) {
2087  if ( wfReadOnly() ) {
2088  return;
2089  }
2090 
2091  $this->load();
2092  $this->mNewtalk = $val;
2093 
2094  if ( $this->isAnon() ) {
2095  $field = 'user_ip';
2096  $id = $this->getName();
2097  } else {
2098  $field = 'user_id';
2099  $id = $this->getId();
2100  }
2101  global $wgMemc;
2102 
2103  if ( $val ) {
2104  $changed = $this->updateNewtalk( $field, $id, $curRev );
2105  } else {
2106  $changed = $this->deleteNewtalk( $field, $id );
2107  }
2108 
2109  if ( $this->isAnon() ) {
2110  // Anons have a separate memcached space, since
2111  // user records aren't kept for them.
2112  $key = wfMemcKey( 'newtalk', 'ip', $id );
2113  $wgMemc->set( $key, $val ? 1 : 0, 1800 );
2114  }
2115  if ( $changed ) {
2116  $this->invalidateCache();
2117  }
2118  }
2119 
2125  private static function newTouchedTimestamp() {
2126  global $wgClockSkewFudge;
2127  return wfTimestamp( TS_MW, time() + $wgClockSkewFudge );
2128  }
2129 
2137  private function clearSharedCache() {
2138  $this->load();
2139  if ( $this->mId ) {
2140  global $wgMemc;
2141  $wgMemc->delete( wfMemcKey( 'user', 'id', $this->mId ) );
2142  }
2143  }
2144 
2150  public function invalidateCache() {
2151  if ( wfReadOnly() ) {
2152  return;
2153  }
2154  $this->load();
2155  if ( $this->mId ) {
2156  $this->mTouched = self::newTouchedTimestamp();
2157 
2158  $dbw = wfGetDB( DB_MASTER );
2159  $userid = $this->mId;
2160  $touched = $this->mTouched;
2161  $method = __METHOD__;
2162  $dbw->onTransactionIdle( function() use ( $dbw, $userid, $touched, $method ) {
2163  // Prevent contention slams by checking user_touched first
2164  $encTouched = $dbw->addQuotes( $dbw->timestamp( $touched ) );
2165  $needsPurge = $dbw->selectField( 'user', '1',
2166  array( 'user_id' => $userid, 'user_touched < ' . $encTouched ) );
2167  if ( $needsPurge ) {
2168  $dbw->update( 'user',
2169  array( 'user_touched' => $dbw->timestamp( $touched ) ),
2170  array( 'user_id' => $userid, 'user_touched < ' . $encTouched ),
2171  $method
2172  );
2173  }
2174  } );
2175  $this->clearSharedCache();
2176  }
2177  }
2178 
2184  public function validateCache( $timestamp ) {
2185  $this->load();
2186  return ( $timestamp >= $this->mTouched );
2187  }
2193  public function getTouched() {
2194  $this->load();
2195  return $this->mTouched;
2196  }
2197 
2214  public function setPassword( $str ) {
2215  global $wgAuth;
2216 
2217  if ( $str !== null ) {
2218  if ( !$wgAuth->allowPasswordChange() ) {
2219  throw new PasswordError( wfMessage( 'password-change-forbidden' )->text() );
2220  }
2221 
2222  if ( !$this->isValidPassword( $str ) ) {
2223  global $wgMinimalPasswordLength;
2224  $valid = $this->getPasswordValidity( $str );
2225  if ( is_array( $valid ) ) {
2226  $message = array_shift( $valid );
2227  $params = $valid;
2228  } else {
2229  $message = $valid;
2230  $params = array( $wgMinimalPasswordLength );
2231  }
2232  throw new PasswordError( wfMessage( $message, $params )->text() );
2233  }
2234  }
2235 
2236  if ( !$wgAuth->setPassword( $this, $str ) ) {
2237  throw new PasswordError( wfMessage( 'externaldberror' )->text() );
2238  }
2239 
2240  $this->setInternalPassword( $str );
2241 
2242  return true;
2243  }
2244 
2252  public function setInternalPassword( $str ) {
2253  $this->load();
2254  $this->setToken();
2255 
2256  if ( $str === null ) {
2257  // Save an invalid hash...
2258  $this->mPassword = '';
2259  } else {
2260  $this->mPassword = self::crypt( $str );
2261  }
2262  $this->mNewpassword = '';
2263  $this->mNewpassTime = null;
2264  }
2265 
2271  public function getToken( $forceCreation = true ) {
2272  $this->load();
2273  if ( !$this->mToken && $forceCreation ) {
2274  $this->setToken();
2275  }
2276  return $this->mToken;
2277  }
2278 
2285  public function setToken( $token = false ) {
2286  $this->load();
2287  if ( !$token ) {
2288  $this->mToken = MWCryptRand::generateHex( USER_TOKEN_LENGTH );
2289  } else {
2290  $this->mToken = $token;
2291  }
2292  }
2293 
2301  public function setNewpassword( $str, $throttle = true ) {
2302  $this->load();
2303 
2304  if ( $str === null ) {
2305  $this->mNewpassword = '';
2306  $this->mNewpassTime = null;
2307  } else {
2308  $this->mNewpassword = self::crypt( $str );
2309  if ( $throttle ) {
2310  $this->mNewpassTime = wfTimestampNow();
2311  }
2312  }
2313  }
2314 
2320  public function isPasswordReminderThrottled() {
2321  global $wgPasswordReminderResendTime;
2322  $this->load();
2323  if ( !$this->mNewpassTime || !$wgPasswordReminderResendTime ) {
2324  return false;
2325  }
2326  $expiry = wfTimestamp( TS_UNIX, $this->mNewpassTime ) + $wgPasswordReminderResendTime * 3600;
2327  return time() < $expiry;
2328  }
2334  public function getEmail() {
2335  $this->load();
2336  wfRunHooks( 'UserGetEmail', array( $this, &$this->mEmail ) );
2337  return $this->mEmail;
2338  }
2344  public function getEmailAuthenticationTimestamp() {
2345  $this->load();
2346  wfRunHooks( 'UserGetEmailAuthenticationTimestamp', array( $this, &$this->mEmailAuthenticated ) );
2348  }
2354  public function setEmail( $str ) {
2355  $this->load();
2356  if ( $str == $this->mEmail ) {
2357  return;
2358  }
2359  $this->mEmail = $str;
2360  $this->invalidateEmail();
2361  wfRunHooks( 'UserSetEmail', array( $this, &$this->mEmail ) );
2362  }
2363 
2371  public function setEmailWithConfirmation( $str ) {
2372  global $wgEnableEmail, $wgEmailAuthentication;
2373 
2374  if ( !$wgEnableEmail ) {
2375  return Status::newFatal( 'emaildisabled' );
2376  }
2377 
2378  $oldaddr = $this->getEmail();
2379  if ( $str === $oldaddr ) {
2380  return Status::newGood( true );
2381  }
2382 
2383  $this->setEmail( $str );
2384 
2385  if ( $str !== '' && $wgEmailAuthentication ) {
2386  // Send a confirmation request to the new address if needed
2387  $type = $oldaddr != '' ? 'changed' : 'set';
2388  $result = $this->sendConfirmationMail( $type );
2389  if ( $result->isGood() ) {
2390  // Say the the caller that a confirmation mail has been sent
2391  $result->value = 'eauth';
2392  }
2393  } else {
2394  $result = Status::newGood( true );
2395  }
2396 
2397  return $result;
2398  }
2404  public function getRealName() {
2405  if ( !$this->isItemLoaded( 'realname' ) ) {
2406  $this->load();
2407  }
2408 
2409  return $this->mRealName;
2410  }
2416  public function setRealName( $str ) {
2417  $this->load();
2418  $this->mRealName = $str;
2419  }
2420 
2431  public function getOption( $oname, $defaultOverride = null, $ignoreHidden = false ) {
2432  global $wgHiddenPrefs;
2433  $this->loadOptions();
2434 
2435  # We want 'disabled' preferences to always behave as the default value for
2436  # users, even if they have set the option explicitly in their settings (ie they
2437  # set it, and then it was disabled removing their ability to change it). But
2438  # we don't want to erase the preferences in the database in case the preference
2439  # is re-enabled again. So don't touch $mOptions, just override the returned value
2440  if ( !$ignoreHidden && in_array( $oname, $wgHiddenPrefs ) ) {
2441  return self::getDefaultOption( $oname );
2442  }
2443 
2444  if ( array_key_exists( $oname, $this->mOptions ) ) {
2445  return $this->mOptions[$oname];
2446  } else {
2447  return $defaultOverride;
2448  }
2449  }
2450 
2456  public function getOptions() {
2457  global $wgHiddenPrefs;
2458  $this->loadOptions();
2460 
2461  # We want 'disabled' preferences to always behave as the default value for
2462  # users, even if they have set the option explicitly in their settings (ie they
2463  # set it, and then it was disabled removing their ability to change it). But
2464  # we don't want to erase the preferences in the database in case the preference
2465  # is re-enabled again. So don't touch $mOptions, just override the returned value
2466  foreach ( $wgHiddenPrefs as $pref ) {
2467  $default = self::getDefaultOption( $pref );
2468  if ( $default !== null ) {
2469  $options[$pref] = $default;
2470  }
2471  }
2472 
2473  return $options;
2474  }
2475 
2483  public function getBoolOption( $oname ) {
2484  return (bool)$this->getOption( $oname );
2485  }
2486 
2495  public function getIntOption( $oname, $defaultOverride = 0 ) {
2496  $val = $this->getOption( $oname );
2497  if ( $val == '' ) {
2498  $val = $defaultOverride;
2499  }
2500  return intval( $val );
2501  }
2502 
2509  public function setOption( $oname, $val ) {
2510  $this->loadOptions();
2511 
2512  // Explicitly NULL values should refer to defaults
2513  if ( is_null( $val ) ) {
2514  $val = self::getDefaultOption( $oname );
2515  }
2516 
2517  $this->mOptions[$oname] = $val;
2518  }
2519 
2529  public function getTokenFromOption( $oname ) {
2530  global $wgHiddenPrefs;
2531  if ( in_array( $oname, $wgHiddenPrefs ) ) {
2532  return false;
2533  }
2534 
2535  $token = $this->getOption( $oname );
2536  if ( !$token ) {
2537  $token = $this->resetTokenFromOption( $oname );
2538  $this->saveSettings();
2539  }
2540  return $token;
2541  }
2542 
2552  public function resetTokenFromOption( $oname ) {
2553  global $wgHiddenPrefs;
2554  if ( in_array( $oname, $wgHiddenPrefs ) ) {
2555  return false;
2556  }
2557 
2558  $token = MWCryptRand::generateHex( 40 );
2559  $this->setOption( $oname, $token );
2560  return $token;
2561  }
2562 
2586  public static function listOptionKinds() {
2587  return array(
2588  'registered',
2589  'registered-multiselect',
2590  'registered-checkmatrix',
2591  'userjs',
2592  'special',
2593  'unused'
2594  );
2595  }
2596 
2608  public function getOptionKinds( IContextSource $context, $options = null ) {
2609  $this->loadOptions();
2610  if ( $options === null ) {
2612  }
2613 
2614  $prefs = Preferences::getPreferences( $this, $context );
2615  $mapping = array();
2616 
2617  // Pull out the "special" options, so they don't get converted as
2618  // multiselect or checkmatrix.
2619  $specialOptions = array_fill_keys( Preferences::getSaveBlacklist(), true );
2620  foreach ( $specialOptions as $name => $value ) {
2621  unset( $prefs[$name] );
2622  }
2623 
2624  // Multiselect and checkmatrix options are stored in the database with
2625  // one key per option, each having a boolean value. Extract those keys.
2626  $multiselectOptions = array();
2627  foreach ( $prefs as $name => $info ) {
2628  if ( ( isset( $info['type'] ) && $info['type'] == 'multiselect' ) ||
2629  ( isset( $info['class'] ) && $info['class'] == 'HTMLMultiSelectField' ) ) {
2630  $opts = HTMLFormField::flattenOptions( $info['options'] );
2631  $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
2632 
2633  foreach ( $opts as $value ) {
2634  $multiselectOptions["$prefix$value"] = true;
2635  }
2636 
2637  unset( $prefs[$name] );
2638  }
2639  }
2640  $checkmatrixOptions = array();
2641  foreach ( $prefs as $name => $info ) {
2642  if ( ( isset( $info['type'] ) && $info['type'] == 'checkmatrix' ) ||
2643  ( isset( $info['class'] ) && $info['class'] == 'HTMLCheckMatrix' ) ) {
2644  $columns = HTMLFormField::flattenOptions( $info['columns'] );
2645  $rows = HTMLFormField::flattenOptions( $info['rows'] );
2646  $prefix = isset( $info['prefix'] ) ? $info['prefix'] : $name;
2647 
2648  foreach ( $columns as $column ) {
2649  foreach ( $rows as $row ) {
2650  $checkmatrixOptions["$prefix-$column-$row"] = true;
2651  }
2652  }
2653 
2654  unset( $prefs[$name] );
2655  }
2656  }
2657 
2658  // $value is ignored
2659  foreach ( $options as $key => $value ) {
2660  if ( isset( $prefs[$key] ) ) {
2661  $mapping[$key] = 'registered';
2662  } elseif ( isset( $multiselectOptions[$key] ) ) {
2663  $mapping[$key] = 'registered-multiselect';
2664  } elseif ( isset( $checkmatrixOptions[$key] ) ) {
2665  $mapping[$key] = 'registered-checkmatrix';
2666  } elseif ( isset( $specialOptions[$key] ) ) {
2667  $mapping[$key] = 'special';
2668  } elseif ( substr( $key, 0, 7 ) === 'userjs-' ) {
2669  $mapping[$key] = 'userjs';
2670  } else {
2671  $mapping[$key] = 'unused';
2672  }
2673  }
2674 
2675  return $mapping;
2676  }
2677 
2692  public function resetOptions(
2693  $resetKinds = array( 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused' ),
2694  IContextSource $context = null
2695  ) {
2696  $this->load();
2698 
2699  if ( !is_array( $resetKinds ) ) {
2700  $resetKinds = array( $resetKinds );
2701  }
2702 
2703  if ( in_array( 'all', $resetKinds ) ) {
2704  $newOptions = $defaultOptions;
2705  } else {
2706  if ( $context === null ) {
2707  $context = RequestContext::getMain();
2708  }
2709 
2710  $optionKinds = $this->getOptionKinds( $context );
2711  $resetKinds = array_intersect( $resetKinds, self::listOptionKinds() );
2712  $newOptions = array();
2713 
2714  // Use default values for the options that should be deleted, and
2715  // copy old values for the ones that shouldn't.
2716  foreach ( $this->mOptions as $key => $value ) {
2717  if ( in_array( $optionKinds[$key], $resetKinds ) ) {
2718  if ( array_key_exists( $key, $defaultOptions ) ) {
2719  $newOptions[$key] = $defaultOptions[$key];
2720  }
2721  } else {
2722  $newOptions[$key] = $value;
2723  }
2724  }
2725  }
2726 
2727  $this->mOptions = $newOptions;
2728  $this->mOptionsLoaded = true;
2729  }
2735  public function getDatePreference() {
2736  // Important migration for old data rows
2737  if ( is_null( $this->mDatePreference ) ) {
2738  global $wgLang;
2739  $value = $this->getOption( 'date' );
2740  $map = $wgLang->getDatePreferenceMigrationMap();
2741  if ( isset( $map[$value] ) ) {
2742  $value = $map[$value];
2743  }
2744  $this->mDatePreference = $value;
2745  }
2746  return $this->mDatePreference;
2747  }
2748 
2755  public function requiresHTTPS() {
2756  global $wgSecureLogin;
2757  if ( !$wgSecureLogin ) {
2758  return false;
2759  } else {
2760  $https = $this->getBoolOption( 'prefershttps' );
2761  wfRunHooks( 'UserRequiresHTTPS', array( $this, &$https ) );
2762  if ( $https ) {
2763  $https = wfCanIPUseHTTPS( $this->getRequest()->getIP() );
2764  }
2765  return $https;
2766  }
2767  }
2768 
2774  public function getStubThreshold() {
2775  global $wgMaxArticleSize; # Maximum article size, in Kb
2776  $threshold = $this->getIntOption( 'stubthreshold' );
2777  if ( $threshold > $wgMaxArticleSize * 1024 ) {
2778  // If they have set an impossible value, disable the preference
2779  // so we can use the parser cache again.
2780  $threshold = 0;
2781  }
2782  return $threshold;
2783  }
2789  public function getRights() {
2790  if ( is_null( $this->mRights ) ) {
2791  $this->mRights = self::getGroupPermissions( $this->getEffectiveGroups() );
2792  wfRunHooks( 'UserGetRights', array( $this, &$this->mRights ) );
2793  // Force reindexation of rights when a hook has unset one of them
2794  $this->mRights = array_values( array_unique( $this->mRights ) );
2795  }
2796  return $this->mRights;
2797  }
2798 
2804  public function getGroups() {
2805  $this->load();
2806  $this->loadGroups();
2807  return $this->mGroups;
2808  }
2809 
2817  public function getEffectiveGroups( $recache = false ) {
2818  if ( $recache || is_null( $this->mEffectiveGroups ) ) {
2819  wfProfileIn( __METHOD__ );
2820  $this->mEffectiveGroups = array_unique( array_merge(
2821  $this->getGroups(), // explicit groups
2822  $this->getAutomaticGroups( $recache ) // implicit groups
2823  ) );
2824  // Hook for additional groups
2825  wfRunHooks( 'UserEffectiveGroups', array( &$this, &$this->mEffectiveGroups ) );
2826  // Force reindexation of groups when a hook has unset one of them
2827  $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
2828  wfProfileOut( __METHOD__ );
2829  }
2830  return $this->mEffectiveGroups;
2831  }
2832 
2840  public function getAutomaticGroups( $recache = false ) {
2841  if ( $recache || is_null( $this->mImplicitGroups ) ) {
2842  wfProfileIn( __METHOD__ );
2843  $this->mImplicitGroups = array( '*' );
2844  if ( $this->getId() ) {
2845  $this->mImplicitGroups[] = 'user';
2846 
2847  $this->mImplicitGroups = array_unique( array_merge(
2848  $this->mImplicitGroups,
2850  ) );
2851  }
2852  if ( $recache ) {
2853  // Assure data consistency with rights/groups,
2854  // as getEffectiveGroups() depends on this function
2855  $this->mEffectiveGroups = null;
2856  }
2857  wfProfileOut( __METHOD__ );
2858  }
2859  return $this->mImplicitGroups;
2860  }
2861 
2871  public function getFormerGroups() {
2872  if ( is_null( $this->mFormerGroups ) ) {
2873  $dbr = wfGetDB( DB_MASTER );
2874  $res = $dbr->select( 'user_former_groups',
2875  array( 'ufg_group' ),
2876  array( 'ufg_user' => $this->mId ),
2877  __METHOD__ );
2878  $this->mFormerGroups = array();
2879  foreach ( $res as $row ) {
2880  $this->mFormerGroups[] = $row->ufg_group;
2881  }
2882  }
2883  return $this->mFormerGroups;
2884  }
2890  public function getEditCount() {
2891  if ( !$this->getId() ) {
2892  return null;
2893  }
2894 
2895  if ( !isset( $this->mEditCount ) ) {
2896  /* Populate the count, if it has not been populated yet */
2897  wfProfileIn( __METHOD__ );
2898  $dbr = wfGetDB( DB_SLAVE );
2899  // check if the user_editcount field has been initialized
2900  $count = $dbr->selectField(
2901  'user', 'user_editcount',
2902  array( 'user_id' => $this->mId ),
2903  __METHOD__
2904  );
2905 
2906  if ( $count === null ) {
2907  // it has not been initialized. do so.
2908  $count = $this->initEditCount();
2909  }
2910  $this->mEditCount = $count;
2911  wfProfileOut( __METHOD__ );
2912  }
2913  return (int)$this->mEditCount;
2914  }
2915 
2921  public function addGroup( $group ) {
2922  if ( wfRunHooks( 'UserAddGroup', array( $this, &$group ) ) ) {
2923  $dbw = wfGetDB( DB_MASTER );
2924  if ( $this->getId() ) {
2925  $dbw->insert( 'user_groups',
2926  array(
2927  'ug_user' => $this->getID(),
2928  'ug_group' => $group,
2929  ),
2930  __METHOD__,
2931  array( 'IGNORE' ) );
2932  }
2933  }
2934  $this->loadGroups();
2935  $this->mGroups[] = $group;
2936  // In case loadGroups was not called before, we now have the right twice.
2937  // Get rid of the duplicate.
2938  $this->mGroups = array_unique( $this->mGroups );
2939 
2940  // Refresh the groups caches, and clear the rights cache so it will be
2941  // refreshed on the next call to $this->getRights().
2942  $this->getEffectiveGroups( true );
2943  $this->mRights = null;
2944 
2945  $this->invalidateCache();
2946  }
2947 
2953  public function removeGroup( $group ) {
2954  $this->load();
2955  if ( wfRunHooks( 'UserRemoveGroup', array( $this, &$group ) ) ) {
2956  $dbw = wfGetDB( DB_MASTER );
2957  $dbw->delete( 'user_groups',
2958  array(
2959  'ug_user' => $this->getID(),
2960  'ug_group' => $group,
2961  ), __METHOD__ );
2962  // Remember that the user was in this group
2963  $dbw->insert( 'user_former_groups',
2964  array(
2965  'ufg_user' => $this->getID(),
2966  'ufg_group' => $group,
2967  ),
2968  __METHOD__,
2969  array( 'IGNORE' ) );
2970  }
2971  $this->loadGroups();
2972  $this->mGroups = array_diff( $this->mGroups, array( $group ) );
2973 
2974  // Refresh the groups caches, and clear the rights cache so it will be
2975  // refreshed on the next call to $this->getRights().
2976  $this->getEffectiveGroups( true );
2977  $this->mRights = null;
2978 
2979  $this->invalidateCache();
2980  }
2986  public function isLoggedIn() {
2987  return $this->getID() != 0;
2988  }
2994  public function isAnon() {
2995  return !$this->isLoggedIn();
2996  }
2997 
3006  public function isAllowedAny( /*...*/ ) {
3007  $permissions = func_get_args();
3008  foreach ( $permissions as $permission ) {
3009  if ( $this->isAllowed( $permission ) ) {
3010  return true;
3011  }
3012  }
3013  return false;
3014  }
3015 
3021  public function isAllowedAll( /*...*/ ) {
3022  $permissions = func_get_args();
3023  foreach ( $permissions as $permission ) {
3024  if ( !$this->isAllowed( $permission ) ) {
3025  return false;
3026  }
3027  }
3028  return true;
3029  }
3030 
3036  public function isAllowed( $action = '' ) {
3037  if ( $action === '' ) {
3038  return true; // In the spirit of DWIM
3039  }
3040  // Patrolling may not be enabled
3041  if ( $action === 'patrol' || $action === 'autopatrol' ) {
3042  global $wgUseRCPatrol, $wgUseNPPatrol;
3043  if ( !$wgUseRCPatrol && !$wgUseNPPatrol ) {
3044  return false;
3045  }
3046  }
3047  // Use strict parameter to avoid matching numeric 0 accidentally inserted
3048  // by misconfiguration: 0 == 'foo'
3049  return in_array( $action, $this->getRights(), true );
3050  }
3056  public function useRCPatrol() {
3057  global $wgUseRCPatrol;
3058  return $wgUseRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
3059  }
3065  public function useNPPatrol() {
3066  global $wgUseRCPatrol, $wgUseNPPatrol;
3067  return (
3068  ( $wgUseRCPatrol || $wgUseNPPatrol )
3069  && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
3070  );
3071  }
3072 
3078  public function getRequest() {
3079  if ( $this->mRequest ) {
3080  return $this->mRequest;
3081  } else {
3082  global $wgRequest;
3083  return $wgRequest;
3084  }
3085  }
3086 
3093  public function getSkin() {
3094  wfDeprecated( __METHOD__, '1.18' );
3095  return RequestContext::getMain()->getSkin();
3096  }
3097 
3107  public function getWatchedItem( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3108  $key = $checkRights . ':' . $title->getNamespace() . ':' . $title->getDBkey();
3109 
3110  if ( isset( $this->mWatchedItems[$key] ) ) {
3111  return $this->mWatchedItems[$key];
3112  }
3113 
3114  if ( count( $this->mWatchedItems ) >= self::MAX_WATCHED_ITEMS_CACHE ) {
3115  $this->mWatchedItems = array();
3116  }
3117 
3118  $this->mWatchedItems[$key] = WatchedItem::fromUserTitle( $this, $title, $checkRights );
3119  return $this->mWatchedItems[$key];
3120  }
3121 
3130  public function isWatched( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3131  return $this->getWatchedItem( $title, $checkRights )->isWatched();
3132  }
3133 
3141  public function addWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3142  $this->getWatchedItem( $title, $checkRights )->addWatch();
3143  $this->invalidateCache();
3144  }
3145 
3153  public function removeWatch( $title, $checkRights = WatchedItem::CHECK_USER_RIGHTS ) {
3154  $this->getWatchedItem( $title, $checkRights )->removeWatch();
3155  $this->invalidateCache();
3156  }
3157 
3166  public function clearNotification( &$title, $oldid = 0 ) {
3167  global $wgUseEnotif, $wgShowUpdatedMarker;
3168 
3169  // Do nothing if the database is locked to writes
3170  if ( wfReadOnly() ) {
3171  return;
3172  }
3173 
3174  // Do nothing if not allowed to edit the watchlist
3175  if ( !$this->isAllowed( 'editmywatchlist' ) ) {
3176  return;
3177  }
3178 
3179  // If we're working on user's talk page, we should update the talk page message indicator
3180  if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
3181  if ( !wfRunHooks( 'UserClearNewTalkNotification', array( &$this, $oldid ) ) ) {
3182  return;
3183  }
3184 
3185  $nextid = $oldid ? $title->getNextRevisionID( $oldid ) : null;
3186 
3187  if ( !$oldid || !$nextid ) {
3188  // If we're looking at the latest revision, we should definitely clear it
3189  $this->setNewtalk( false );
3190  } else {
3191  // Otherwise we should update its revision, if it's present
3192  if ( $this->getNewtalk() ) {
3193  // Naturally the other one won't clear by itself
3194  $this->setNewtalk( false );
3195  $this->setNewtalk( true, Revision::newFromId( $nextid ) );
3196  }
3197  }
3198  }
3199 
3200  if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3201  return;
3202  }
3203 
3204  if ( $this->isAnon() ) {
3205  // Nothing else to do...
3206  return;
3207  }
3208 
3209  // Only update the timestamp if the page is being watched.
3210  // The query to find out if it is watched is cached both in memcached and per-invocation,
3211  // and when it does have to be executed, it can be on a slave
3212  // If this is the user's newtalk page, we always update the timestamp
3213  $force = '';
3214  if ( $title->getNamespace() == NS_USER_TALK && $title->getText() == $this->getName() ) {
3215  $force = 'force';
3216  }
3217 
3218  $this->getWatchedItem( $title )->resetNotificationTimestamp( $force, $oldid );
3219  }
3220 
3227  public function clearAllNotifications() {
3228  if ( wfReadOnly() ) {
3229  return;
3230  }
3231 
3232  // Do nothing if not allowed to edit the watchlist
3233  if ( !$this->isAllowed( 'editmywatchlist' ) ) {
3234  return;
3235  }
3236 
3237  global $wgUseEnotif, $wgShowUpdatedMarker;
3238  if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3239  $this->setNewtalk( false );
3240  return;
3241  }
3242  $id = $this->getId();
3243  if ( $id != 0 ) {
3244  $dbw = wfGetDB( DB_MASTER );
3245  $dbw->update( 'watchlist',
3246  array( /* SET */ 'wl_notificationtimestamp' => null ),
3247  array( /* WHERE */ 'wl_user' => $id ),
3248  __METHOD__
3249  );
3250  // We also need to clear here the "you have new message" notification for the own user_talk page;
3251  // it's cleared one page view later in WikiPage::doViewUpdates().
3252  }
3253  }
3254 
3268  protected function setCookie( $name, $value, $exp = 0, $secure = null, $params = array() ) {
3269  $params['secure'] = $secure;
3270  $this->getRequest()->response()->setcookie( $name, $value, $exp, $params );
3271  }
3272 
3282  protected function clearCookie( $name, $secure = null, $params = array() ) {
3283  $this->setCookie( $name, '', time() - 86400, $secure, $params );
3284  }
3285 
3294  public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
3295  if ( $request === null ) {
3296  $request = $this->getRequest();
3297  }
3298 
3299  $this->load();
3300  if ( 0 == $this->mId ) {
3301  return;
3302  }
3303  if ( !$this->mToken ) {
3304  // When token is empty or NULL generate a new one and then save it to the database
3305  // This allows a wiki to re-secure itself after a leak of it's user table or $wgSecretKey
3306  // Simply by setting every cell in the user_token column to NULL and letting them be
3307  // regenerated as users log back into the wiki.
3308  $this->setToken();
3309  $this->saveSettings();
3310  }
3311  $session = array(
3312  'wsUserID' => $this->mId,
3313  'wsToken' => $this->mToken,
3314  'wsUserName' => $this->getName()
3315  );
3316  $cookies = array(
3317  'UserID' => $this->mId,
3318  'UserName' => $this->getName(),
3319  );
3320  if ( $rememberMe ) {
3321  $cookies['Token'] = $this->mToken;
3322  } else {
3323  $cookies['Token'] = false;
3324  }
3325 
3326  wfRunHooks( 'UserSetCookies', array( $this, &$session, &$cookies ) );
3327 
3328  foreach ( $session as $name => $value ) {
3329  $request->setSessionData( $name, $value );
3330  }
3331  foreach ( $cookies as $name => $value ) {
3332  if ( $value === false ) {
3333  $this->clearCookie( $name );
3334  } else {
3335  $this->setCookie( $name, $value, 0, $secure );
3336  }
3337  }
3338 
3346  if ( $request->getCheck( 'wpStickHTTPS' ) || $this->requiresHTTPS() ) {
3347  $this->setCookie(
3348  'forceHTTPS',
3349  'true',
3350  $rememberMe ? 0 : null,
3351  false,
3352  array( 'prefix' => '' ) // no prefix
3353  );
3354  }
3355  }
3356 
3360  public function logout() {
3361  if ( wfRunHooks( 'UserLogout', array( &$this ) ) ) {
3362  $this->doLogout();
3363  }
3364  }
3370  public function doLogout() {
3371  $this->clearInstanceCache( 'defaults' );
3372 
3373  $this->getRequest()->setSessionData( 'wsUserID', 0 );
3374 
3375  $this->clearCookie( 'UserID' );
3376  $this->clearCookie( 'Token' );
3377  $this->clearCookie( 'forceHTTPS', false, array( 'prefix' => '' ) );
3378 
3379  // Remember when user logged out, to prevent seeing cached pages
3380  $this->setCookie( 'LoggedOut', time(), time() + 86400 );
3381  }
3387  public function saveSettings() {
3388  global $wgAuth;
3389 
3390  $this->load();
3391  if ( wfReadOnly() ) {
3392  return;
3393  }
3394  if ( 0 == $this->mId ) {
3395  return;
3396  }
3397 
3398  $this->mTouched = self::newTouchedTimestamp();
3399  if ( !$wgAuth->allowSetLocalPassword() ) {
3400  $this->mPassword = '';
3401  }
3402 
3403  $dbw = wfGetDB( DB_MASTER );
3404  $dbw->update( 'user',
3405  array( /* SET */
3406  'user_name' => $this->mName,
3407  'user_password' => $this->mPassword,
3408  'user_newpassword' => $this->mNewpassword,
3409  'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
3410  'user_real_name' => $this->mRealName,
3411  'user_email' => $this->mEmail,
3412  'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3413  'user_touched' => $dbw->timestamp( $this->mTouched ),
3414  'user_token' => strval( $this->mToken ),
3415  'user_email_token' => $this->mEmailToken,
3416  'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
3417  'user_password_expires' => $dbw->timestampOrNull( $this->mPasswordExpires ),
3418  ), array( /* WHERE */
3419  'user_id' => $this->mId
3420  ), __METHOD__
3421  );
3422 
3423  $this->saveOptions();
3424 
3425  wfRunHooks( 'UserSaveSettings', array( $this ) );
3426  $this->clearSharedCache();
3427  $this->getUserPage()->invalidateCache();
3428  }
3434  public function idForName() {
3435  $s = trim( $this->getName() );
3436  if ( $s === '' ) {
3437  return 0;
3438  }
3439 
3440  $dbr = wfGetDB( DB_SLAVE );
3441  $id = $dbr->selectField( 'user', 'user_id', array( 'user_name' => $s ), __METHOD__ );
3442  if ( $id === false ) {
3443  $id = 0;
3444  }
3445  return $id;
3446  }
3447 
3464  public static function createNew( $name, $params = array() ) {
3465  $user = new User;
3466  $user->load();
3467  $user->setToken(); // init token
3468  if ( isset( $params['options'] ) ) {
3469  $user->mOptions = $params['options'] + (array)$user->mOptions;
3470  unset( $params['options'] );
3471  }
3472  $dbw = wfGetDB( DB_MASTER );
3473  $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
3474 
3475  $fields = array(
3476  'user_id' => $seqVal,
3477  'user_name' => $name,
3478  'user_password' => $user->mPassword,
3479  'user_newpassword' => $user->mNewpassword,
3480  'user_newpass_time' => $dbw->timestampOrNull( $user->mNewpassTime ),
3481  'user_email' => $user->mEmail,
3482  'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
3483  'user_real_name' => $user->mRealName,
3484  'user_token' => strval( $user->mToken ),
3485  'user_registration' => $dbw->timestamp( $user->mRegistration ),
3486  'user_editcount' => 0,
3487  'user_touched' => $dbw->timestamp( self::newTouchedTimestamp() ),
3488  );
3489  foreach ( $params as $name => $value ) {
3490  $fields["user_$name"] = $value;
3491  }
3492  $dbw->insert( 'user', $fields, __METHOD__, array( 'IGNORE' ) );
3493  if ( $dbw->affectedRows() ) {
3494  $newUser = User::newFromId( $dbw->insertId() );
3495  } else {
3496  $newUser = null;
3497  }
3498  return $newUser;
3499  }
3500 
3527  public function addToDatabase() {
3528  $this->load();
3529  if ( !$this->mToken ) {
3530  $this->setToken(); // init token
3531  }
3532 
3533  $this->mTouched = self::newTouchedTimestamp();
3534 
3535  $dbw = wfGetDB( DB_MASTER );
3536  $inWrite = $dbw->writesOrCallbacksPending();
3537  $seqVal = $dbw->nextSequenceValue( 'user_user_id_seq' );
3538  $dbw->insert( 'user',
3539  array(
3540  'user_id' => $seqVal,
3541  'user_name' => $this->mName,
3542  'user_password' => $this->mPassword,
3543  'user_newpassword' => $this->mNewpassword,
3544  'user_newpass_time' => $dbw->timestampOrNull( $this->mNewpassTime ),
3545  'user_email' => $this->mEmail,
3546  'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3547  'user_real_name' => $this->mRealName,
3548  'user_token' => strval( $this->mToken ),
3549  'user_registration' => $dbw->timestamp( $this->mRegistration ),
3550  'user_editcount' => 0,
3551  'user_touched' => $dbw->timestamp( $this->mTouched ),
3552  ), __METHOD__,
3553  array( 'IGNORE' )
3554  );
3555  if ( !$dbw->affectedRows() ) {
3556  if ( !$inWrite ) {
3557  // XXX: Get out of REPEATABLE-READ so the SELECT below works.
3558  // Often this case happens early in views before any writes.
3559  // This shows up at least with CentralAuth.
3560  $dbw->commit( __METHOD__, 'flush' );
3561  }
3562  $this->mId = $dbw->selectField( 'user', 'user_id',
3563  array( 'user_name' => $this->mName ), __METHOD__ );
3564  $loaded = false;
3565  if ( $this->mId ) {
3566  if ( $this->loadFromDatabase() ) {
3567  $loaded = true;
3568  }
3569  }
3570  if ( !$loaded ) {
3571  throw new MWException( __METHOD__ . ": hit a key conflict attempting " .
3572  "to insert user '{$this->mName}' row, but it was not present in select!" );
3573  }
3574  return Status::newFatal( 'userexists' );
3575  }
3576  $this->mId = $dbw->insertId();
3577 
3578  // Clear instance cache other than user table data, which is already accurate
3579  $this->clearInstanceCache();
3580 
3581  $this->saveOptions();
3582  return Status::newGood();
3583  }
3584 
3590  public function spreadAnyEditBlock() {
3591  if ( $this->isLoggedIn() && $this->isBlocked() ) {
3592  return $this->spreadBlock();
3593  }
3594  return false;
3595  }
3596 
3602  protected function spreadBlock() {
3603  wfDebug( __METHOD__ . "()\n" );
3604  $this->load();
3605  if ( $this->mId == 0 ) {
3606  return false;
3607  }
3608 
3609  $userblock = Block::newFromTarget( $this->getName() );
3610  if ( !$userblock ) {
3611  return false;
3612  }
3613 
3614  return (bool)$userblock->doAutoblock( $this->getRequest()->getIP() );
3615  }
3621  public function isBlockedFromCreateAccount() {
3622  $this->getBlockedStatus();
3623  if ( $this->mBlock && $this->mBlock->prevents( 'createaccount' ) ) {
3624  return $this->mBlock;
3625  }
3626 
3627  # bug 13611: if the IP address the user is trying to create an account from is
3628  # blocked with createaccount disabled, prevent new account creation there even
3629  # when the user is logged in
3630  if ( $this->mBlockedFromCreateAccount === false && !$this->isAllowed( 'ipblock-exempt' ) ) {
3631  $this->mBlockedFromCreateAccount = Block::newFromTarget( null, $this->getRequest()->getIP() );
3632  }
3633  return $this->mBlockedFromCreateAccount instanceof Block && $this->mBlockedFromCreateAccount->prevents( 'createaccount' )
3634  ? $this->mBlockedFromCreateAccount
3635  : false;
3636  }
3642  public function isBlockedFromEmailuser() {
3643  $this->getBlockedStatus();
3644  return $this->mBlock && $this->mBlock->prevents( 'sendemail' );
3645  }
3651  public function isAllowedToCreateAccount() {
3652  return $this->isAllowed( 'createaccount' ) && !$this->isBlockedFromCreateAccount();
3653  }
3654 
3660  public function getUserPage() {
3661  return Title::makeTitle( NS_USER, $this->getName() );
3662  }
3663 
3669  public function getTalkPage() {
3670  $title = $this->getUserPage();
3671  return $title->getTalkPage();
3672  }
3673 
3679  public function isNewbie() {
3680  return !$this->isAllowed( 'autoconfirmed' );
3681  }
3682 
3688  public function checkPassword( $password ) {
3689  global $wgAuth, $wgLegacyEncoding;
3690  $this->load();
3691 
3692  // Certain authentication plugins do NOT want to save
3693  // domain passwords in a mysql database, so we should
3694  // check this (in case $wgAuth->strict() is false).
3695 
3696  if ( $wgAuth->authenticate( $this->getName(), $password ) ) {
3697  return true;
3698  } elseif ( $wgAuth->strict() ) {
3699  // Auth plugin doesn't allow local authentication
3700  return false;
3701  } elseif ( $wgAuth->strictUserAuth( $this->getName() ) ) {
3702  // Auth plugin doesn't allow local authentication for this user name
3703  return false;
3704  }
3705  if ( self::comparePasswords( $this->mPassword, $password, $this->mId ) ) {
3706  return true;
3707  } elseif ( $wgLegacyEncoding ) {
3708  // Some wikis were converted from ISO 8859-1 to UTF-8, the passwords can't be converted
3709  // Check for this with iconv
3710  $cp1252Password = iconv( 'UTF-8', 'WINDOWS-1252//TRANSLIT', $password );
3711  if ( $cp1252Password != $password
3712  && self::comparePasswords( $this->mPassword, $cp1252Password, $this->mId )
3713  ) {
3714  return true;
3715  }
3716  }
3717  return false;
3718  }
3719 
3728  public function checkTemporaryPassword( $plaintext ) {
3729  global $wgNewPasswordExpiry;
3730 
3731  $this->load();
3732  if ( self::comparePasswords( $this->mNewpassword, $plaintext, $this->getId() ) ) {
3733  if ( is_null( $this->mNewpassTime ) ) {
3734  return true;
3735  }
3736  $expiry = wfTimestamp( TS_UNIX, $this->mNewpassTime ) + $wgNewPasswordExpiry;
3737  return ( time() < $expiry );
3738  } else {
3739  return false;
3740  }
3741  }
3742 
3751  public function editToken( $salt = '', $request = null ) {
3752  wfDeprecated( __METHOD__, '1.19' );
3753  return $this->getEditToken( $salt, $request );
3754  }
3755 
3768  public function getEditToken( $salt = '', $request = null ) {
3769  if ( $request == null ) {
3770  $request = $this->getRequest();
3771  }
3772 
3773  if ( $this->isAnon() ) {
3774  return EDIT_TOKEN_SUFFIX;
3775  } else {
3776  $token = $request->getSessionData( 'wsEditToken' );
3777  if ( $token === null ) {
3778  $token = MWCryptRand::generateHex( 32 );
3779  $request->setSessionData( 'wsEditToken', $token );
3780  }
3781  if ( is_array( $salt ) ) {
3782  $salt = implode( '|', $salt );
3783  }
3784  return md5( $token . $salt ) . EDIT_TOKEN_SUFFIX;
3785  }
3786  }
3787 
3794  public static function generateToken() {
3795  return MWCryptRand::generateHex( 32 );
3796  }
3797 
3809  public function matchEditToken( $val, $salt = '', $request = null ) {
3810  $sessionToken = $this->getEditToken( $salt, $request );
3811  if ( $val != $sessionToken ) {
3812  wfDebug( "User::matchEditToken: broken session data\n" );
3813  }
3814  return $val == $sessionToken;
3815  }
3816 
3826  public function matchEditTokenNoSuffix( $val, $salt = '', $request = null ) {
3827  $sessionToken = $this->getEditToken( $salt, $request );
3828  return 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:1384
User\addWatch
addWatch( $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Watch an article.
Definition: User.php:3136
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:2037
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:1921
User\addGroup
addGroup( $group)
Add the user to the given group.
Definition: User.php:2916
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:552
User\inDnsBlacklist
inDnsBlacklist( $ip, $bases)
Whether the given IP is in a given DNS blacklist.
Definition: User.php:1515
$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
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1358
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:4138
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:1853
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:2989
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:1562
User\resetTokenFromOption
resetTokenFromOption( $oname)
Reset a token stored in the preferences (like the watchlist one).
Definition: User.php:2547
User\loadFromUserObject
loadFromUserObject( $user)
Load the data for this user object from another user object.
Definition: User.php:1245
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:2885
User\spreadBlock
spreadBlock()
If this (non-anonymous) user is blocked, block the IP address they've successfully logged in from.
Definition: User.php:3597
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:2603
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:1732
wfGetDB
& wfGetDB( $db, $groups=array(), $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:3659
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:1785
User\getIntOption
getIntOption( $oname, $defaultOverride=0)
Get the user's current setting for a given option, as an integer value.
Definition: User.php:2490
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:3746
wfTimestamp
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
Definition: GlobalFunctions.php:2483
User\getToken
getToken( $forceCreation=true)
Get the user's current token.
Definition: User.php:2266
User\spreadAnyEditBlock
spreadAnyEditBlock()
If this user is logged-in and blocked, block any IP address they've successfully logged in from.
Definition: User.php:3585
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:1040
User\getNewMessageRevisionId
getNewMessageRevisionId()
Get the revision ID for the last talk page revision viewed by the talk page owner.
Definition: User.php:1992
User\loadDefaults
loadDefaults( $name=false)
Set cached properties to default.
Definition: User.php:971
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:2697
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:2296
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:2798
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:2366
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:2769
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:1313
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:1173
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:3277
User\getUserPage
getUserPage()
Get this user's personal page title.
Definition: User.php:3655
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:2799
$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:3060
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:2730
User\setEmail
setEmail( $str)
Set the user's e-mail address.
Definition: User.php:2349
$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:2339
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:1616
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:3051
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:1257
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:1116
User\deleteNewtalk
deleteNewtalk( $field, $id)
Clear the new messages flag for the given user.
Definition: User.php:2062
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:2784
User\getRequest
getRequest()
Get the WebRequest object to use with this object.
Definition: User.php:3073
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:2835
User\generateToken
static generateToken()
Generate a looking random token for various uses.
Definition: User.php:3789
User\setPassword
setPassword( $str)
Set the password and reset the random token.
Definition: User.php:2209
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:1351
$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:1744
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:2687
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:2329
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:3664
$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:3804
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:3522
User\clearSharedCache
clearSharedCache()
Clear user data from memcached.
Definition: User.php:2132
User\invalidateCache
invalidateCache()
Immediately touch the user data cache for this account.
Definition: User.php:2145
User\setInternalPassword
setInternalPassword( $str)
Set the password and reset the random token unconditionally.
Definition: User.php:2247
User\getWatchedItem
getWatchedItem( $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Get a WatchedItem for this user and $title.
Definition: User.php:3102
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:3580
User\isLocked
isLocked()
Check if user account is locked.
Definition: User.php:1819
wfDeprecated
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
Definition: GlobalFunctions.php:1127
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:1026
User\blockedFor
blockedFor()
If user is blocked, return the specified reason for the block.
Definition: User.php:1776
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:2451
User\setNewtalk
setNewtalk( $val, $curRev=null)
Update the 'You have new messages!' status.
Definition: User.php:2081
User\isWatched
isWatched( $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Check the watched status of an article.
Definition: User.php:3125
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:3646
User\logout
logout()
Log this user out.
Definition: User.php:3355
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:2501
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:1835
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:3637
wfRunHooks
wfRunHooks( $event, array $args=array(), $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
Definition: GlobalFunctions.php:4010
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:2179
User\getEffectiveGroups
getEffectiveGroups( $recache=false)
Get the list of implicit group memberships this user has.
Definition: User.php:2812
User\isPingLimitable
isPingLimitable()
Is this user subject to rate limiting?
Definition: User.php:1594
User\removeGroup
removeGroup( $group)
Remove the user from the given group.
Definition: User.php:2948
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:3674
User\isAllowedAll
isAllowedAll()
Is the input a valid password for this user?
Definition: User.php:3016
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:2019
User\clearInstanceCache
clearInstanceCache( $reloadFrom=false)
Clear various cached data stored in this object.
Definition: User.php:1326
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:2514
$cookies
return false to override stock group removal can be modified modifiable will be added to $_SESSION & $cookies
Definition: hooks.txt:2838
$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:1904
User\setCookie
setCookie( $name, $value, $exp=0, $secure=null, $params=array())
Set a cookie on the user's client.
Definition: User.php:3263
User\createNew
static createNew( $name, $params=array())
Add a user to the database, return the user object.
Definition: User.php:3459
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:2697
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:3161
User\saveSettings
saveSettings()
Save this user's settings into the database.
Definition: User.php:3382
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:2411
$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:1969
TS_MW
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
Definition: GlobalFunctions.php:2431
wfDebug
wfDebug( $text, $dest='all')
Sends a line to the debug log if enabled or, optionally, to a comment in output.
Definition: GlobalFunctions.php:933
User\getBlockedStatus
getBlockedStatus( $bFromSlave=true)
Get blocking information.
Definition: User.php:1400
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:3613
User\idForName
idForName()
If only this user's username is known, and it exists, return the user ID.
Definition: User.php:3429
$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:2866
User\loadFromDatabase
loadFromDatabase()
Load user and user_group data from the database.
Definition: User.php:1135
$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:2120
$value
$value
Definition: styleTest.css.php:45
User\loadFromSession
loadFromSession()
Load user data from the session or login cookie.
Definition: User.php:1036
User\isBlockedGlobally
isBlockedGlobally( $ip='')
Check if user is blocked on all wikis.
Definition: User.php:1798
User\getOption
getOption( $oname, $defaultOverride=null, $ignoreHidden=false)
Get the user's current setting for a given option.
Definition: User.php:2426
User\isDnsBlacklisted
isDnsBlacklisted( $ip, $checkWhitelist=false)
Whether the given IP is in a DNS blacklist.
Definition: User.php:1492
User\getTouched
getTouched()
Get the user touched timestamp.
Definition: User.php:2188
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:564
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:2399
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:3289
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:3222
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:2315
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:3683
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:1767
$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:2697
$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:2697
$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:288
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:1868
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:134
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:3001
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:2981
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:3723
User\getTitleKey
getTitleKey()
Get the user's name escaped by underscores.
Definition: User.php:1913
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:2280
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:3377
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:2426
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:1956
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:1285
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:2524
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:3088
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:2478
User\removeWatch
removeWatch( $title, $checkRights=WatchedItem::CHECK_USER_RIGHTS)
Stop watching an article.
Definition: User.php:3148
$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:2573
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:1722
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:3616
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:3763
User\requiresHTTPS
requiresHTTPS()
Determine based on the wiki configuration and the user's options, whether this user must be over HTTP...
Definition: User.php:2750
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:1016
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:2504
$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:1877
User\doLogout
doLogout()
Clear the user's cookies and session, and reset the instance cache.
Definition: User.php:3365
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:3031
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:2581
$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:1956
$type
$type
Definition: testCompression.php:46