35 define(
'EDIT_TOKEN_SUFFIX', Token::SUFFIX );
100 'mEmailAuthenticated',
102 'mEmailTokenExpires',
147 'editusercssjs', # deprecated
160 'move-categorypages',
161 'move-rootuserpages',
165 'override-export-depth',
188 'userrights-interwiki',
353 return ( !defined(
'MW_NO_SESSION' ) && $wgFullyInitialised ) ||
354 $this->mLoadedItems ===
true || $this->mFrom !==
'session';
365 if ( $this->mLoadedItems ===
true ) {
371 $this->mLoadedItems =
true;
372 $this->queryFlagsUsed =
$flags;
375 if ( !$wgFullyInitialised && $this->mFrom ===
'session' ) {
377 ->warning(
'User::loadFromSession called before the end of Setup.php', [
378 'exception' =>
new Exception(
'User::loadFromSession called before the end of Setup.php' ),
381 $this->mLoadedItems = $oldLoadedItems;
385 switch ( $this->mFrom ) {
391 if (
wfGetLB()->hasOrMadeRecentMasterChanges() ) {
392 $flags |= self::READ_LATEST;
393 $this->queryFlagsUsed =
$flags;
396 $this->mId = self::idFromName( $this->mName,
$flags );
412 Hooks::run(
'UserLoadAfterLoadFromSession', [ $this ] );
416 "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
426 if ( $this->mId == 0 ) {
435 wfDebug(
"User: cache miss for user {$this->mId}\n" );
437 if (
wfGetLB()->hasOrMadeRecentMasterChanges() ) {
438 $flags |= self::READ_LATEST;
447 $this->mLoadedItems =
true;
448 $this->queryFlagsUsed =
$flags;
458 public static function purge( $wikiId, $userId ) {
460 $processCache = self::getInProcessCache();
461 $key =
$cache->makeGlobalKey(
'user',
'id', $wikiId, $userId );
463 $processCache->delete(
$key );
480 if ( !self::$inProcessCache ) {
481 self::$inProcessCache =
new HashBagOStuff( [
'maxKeys' => 10 ] );
483 return self::$inProcessCache;
493 if ( $this->mId == 0 ) {
499 $processCache = self::getInProcessCache();
501 $data = $processCache->get(
$key );
502 if ( !is_array( $data ) ) {
504 if ( !is_array( $data ) || $data[
'mVersion'] < self::VERSION ) {
508 $processCache->set(
$key, $data );
510 wfDebug(
"User: got user {$this->mId} from cache\n" );
513 foreach ( self::$mCacheVars
as $name ) {
514 $this->$name = $data[
$name];
536 foreach ( self::$mCacheVars
as $name ) {
537 $data[
$name] = $this->$name;
539 $data[
'mVersion'] = self::VERSION;
543 $processCache = self::getInProcessCache();
545 $cache->set(
$key, $data, $cache::TTL_HOUR, $opts );
546 $processCache->set(
$key, $data );
569 if ( $validate ===
true ) {
572 $name = self::getCanonicalName(
$name, $validate );
573 if (
$name ===
false ) {
580 $u->setItemLoaded(
'name' );
595 $u->setItemLoaded(
'id' );
611 $db = (
$flags & self::READ_LATEST ) == self::READ_LATEST
615 $id = $db->selectField(
619 'user_email_token' => md5(
$code ),
620 'user_email_token_expires > ' . $db->addQuotes( $db->timestamp() ),
636 $user->mFrom =
'session';
657 $user->loadFromRow( $row, $data );
697 'validate' =>
'valid',
703 if (
$name ===
false ) {
707 $fields = self::selectFields();
710 $row = $dbw->selectRow(
713 [
'user_name' =>
$name ],
720 $user = self::newFromRow( $row );
724 if (
$user->mEmail ||
$user->mToken !== self::INVALID_TOKEN ||
725 AuthManager::singleton()->userCanAuthenticate(
$name )
732 AuthManager::singleton()->revokeAccessForUser(
$name );
734 $user->invalidateEmail();
735 $user->mToken = self::INVALID_TOKEN;
736 $user->saveSettings();
737 SessionManager::singleton()->preventSessionsForUser(
$user->getName() );
750 public static function whoIs( $id ) {
772 if ( is_null( $nt ) ) {
777 if ( !(
$flags & self::READ_LATEST ) && isset( self::$idCacheByName[
$name] ) ) {
778 return self::$idCacheByName[
$name];
781 $db = (
$flags & self::READ_LATEST )
788 [
'user_name' => $nt->getText() ],
792 if (
$s ===
false ) {
800 if ( count( self::$idCacheByName ) > 1000 ) {
801 self::$idCacheByName = [];
811 self::$idCacheByName = [];
831 return preg_match(
'/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/',
$name )
851 || strpos(
$name,
'/' ) !==
false
852 || strlen(
$name ) > $wgMaxNameChars
861 if ( is_null( $parsed )
862 || $parsed->getNamespace()
863 || strcmp(
$name, $parsed->getPrefixedText() ) ) {
869 $unicodeBlacklist =
'/[' .
870 '\x{0080}-\x{009f}' . # iso-8859-1 control chars
871 '\x{00a0}' . # non-breaking space
872 '\x{2000}-\x{200f}' . # various whitespace
873 '\x{2028}-\x{202f}' . # breaks
and control chars
874 '\x{3000}' . # ideographic space
875 '\x{e000}-\x{f8ff}' . #
private use
877 if ( preg_match( $unicodeBlacklist,
$name ) ) {
896 global $wgReservedUsernames;
898 if ( !self::isValidUserName(
$name ) ) {
902 static $reservedUsernames =
false;
903 if ( !$reservedUsernames ) {
904 $reservedUsernames = $wgReservedUsernames;
905 Hooks::run(
'UserGetReservedNames', [ &$reservedUsernames ] );
909 foreach ( $reservedUsernames
as $reserved ) {
910 if ( substr( $reserved, 0, 4 ) ==
'msg:' ) {
911 $reserved =
wfMessage( substr( $reserved, 4 ) )->inContentLanguage()->text();
913 if ( $reserved ==
$name ) {
933 global $wgInvalidUsernameCharacters;
938 if ( strlen(
$name ) > 235 ) {
940 ": '$name' invalid due to length" );
945 if ( $wgInvalidUsernameCharacters !==
'' ) {
946 if ( preg_match(
'/[' . preg_quote( $wgInvalidUsernameCharacters,
'/' ) .
']/',
$name ) ) {
948 ": '$name' invalid due to wgInvalidUsernameCharacters" );
953 return self::isUsableName(
$name );
979 foreach (
$result->getErrorsByType(
'error' )
as $error ) {
982 foreach (
$result->getErrorsByType(
'warning' )
as $warning ) {
1011 global $wgPasswordPolicy;
1014 $wgPasswordPolicy[
'policies'],
1015 $wgPasswordPolicy[
'checks']
1027 $status->merge( $upp->checkUserPassword( $this, $password, $purpose ) );
1029 } elseif (
$result ===
true ) {
1055 # Reject names containing '#'; these will be cleaned up
1056 # with title normalisation, but then it's too late to
1058 if ( strpos(
$name,
'#' ) !==
false ) {
1064 $t = ( $validate !==
false ) ?
1067 if ( is_null(
$t ) ||
$t->getNamespace() !==
NS_USER ||
$t->isExternal() ) {
1072 $name = AuthManager::callLegacyAuthPlugin(
1073 'getCanonicalName', [
$t->getText() ],
$t->getText()
1076 switch ( $validate ) {
1096 'Invalid parameter value for $validate in ' . __METHOD__ );
1111 $user = self::newFromId( $uid );
1112 return $user->getEditCount();
1122 global $wgMinimalPasswordLength;
1136 $this->mName =
$name;
1137 $this->mRealName =
'';
1139 $this->mOptionOverrides = null;
1140 $this->mOptionsLoaded =
false;
1142 $loggedOut = $this->mRequest && !defined(
'MW_NO_SESSION' )
1143 ? $this->mRequest->getSession()->getLoggedOutTimestamp() : 0;
1144 if ( $loggedOut !== 0 ) {
1147 $this->mTouched =
'1'; # Allow any
pages to be cached
1150 $this->mToken = null;
1151 $this->mEmailAuthenticated = null;
1152 $this->mEmailToken =
'';
1153 $this->mEmailTokenExpires = null;
1155 $this->mGroups = [];
1173 return ( $this->mLoadedItems ===
true && $all ===
'all' ) ||
1174 ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] ===
true );
1183 if ( is_array( $this->mLoadedItems ) ) {
1184 $this->mLoadedItems[$item] =
true;
1203 $session = $this->
getRequest()->getSession();
1204 $user = $session->getUser();
1205 if (
$user->isLoggedIn() ) {
1208 $session->set(
'wsUserID', $this->
getId() );
1209 $session->set(
'wsUserName', $this->
getName() );
1210 $session->set(
'wsToken', $this->
getToken() );
1226 $this->mId = intval( $this->mId );
1229 if ( !$this->mId ) {
1237 $s = $db->selectRow(
1239 self::selectFields(),
1240 [
'user_id' => $this->mId ],
1245 $this->queryFlagsUsed =
$flags;
1248 if (
$s !==
false ) {
1251 $this->mGroups = null;
1274 $this->mGroups = null;
1276 if ( isset( $row->user_name ) ) {
1277 $this->mName = $row->user_name;
1278 $this->mFrom =
'name';
1284 if ( isset( $row->user_real_name ) ) {
1285 $this->mRealName = $row->user_real_name;
1291 if ( isset( $row->user_id ) ) {
1292 $this->mId = intval( $row->user_id );
1293 $this->mFrom =
'id';
1299 if ( isset( $row->user_id ) && isset( $row->user_name ) ) {
1300 self::$idCacheByName[$row->user_name] = $row->user_id;
1303 if ( isset( $row->user_editcount ) ) {
1304 $this->mEditCount = $row->user_editcount;
1309 if ( isset( $row->user_touched ) ) {
1315 if ( isset( $row->user_token ) ) {
1319 $this->mToken = rtrim( $row->user_token,
" \0" );
1320 if ( $this->mToken ===
'' ) {
1321 $this->mToken = null;
1327 if ( isset( $row->user_email ) ) {
1328 $this->mEmail = $row->user_email;
1330 $this->mEmailToken = $row->user_email_token;
1338 $this->mLoadedItems =
true;
1341 if ( is_array( $data ) ) {
1342 if ( isset( $data[
'user_groups'] ) && is_array( $data[
'user_groups'] ) ) {
1343 $this->mGroups = $data[
'user_groups'];
1345 if ( isset( $data[
'user_properties'] ) && is_array( $data[
'user_properties'] ) ) {
1358 $user->loadGroups();
1359 $user->loadOptions();
1360 foreach ( self::$mCacheVars
as $var ) {
1361 $this->$var =
$user->$var;
1369 if ( is_null( $this->mGroups ) ) {
1370 $db = ( $this->queryFlagsUsed & self::READ_LATEST )
1373 $res = $db->select(
'user_groups',
1375 [
'ug_user' => $this->mId ],
1377 $this->mGroups = [];
1378 foreach (
$res as $row ) {
1379 $this->mGroups[] = $row->ug_group;
1399 global $wgAutopromoteOnceLogInRC;
1406 if ( !count( $toPromote ) ) {
1415 foreach ( $toPromote
as $group ) {
1419 Hooks::run(
'UserGroupsChanged', [ $this, $toPromote, [],
false,
false ] );
1420 AuthManager::callLegacyAuthPlugin(
'updateExternalDBGroups', [ $this, $toPromote ] );
1422 $newGroups = array_merge( $oldGroups, $toPromote );
1425 $logEntry->setPerformer( $this );
1427 $logEntry->setParameters( [
1428 '4::oldgroups' => $oldGroups,
1429 '5::newgroups' => $newGroups,
1431 $logid = $logEntry->insert();
1432 if ( $wgAutopromoteOnceLogInRC ) {
1433 $logEntry->publish( $logid );
1451 if ( !$this->mId ) {
1460 $dbw->update(
'user',
1461 [
'user_touched' => $dbw->timestamp( $newTouched ) ],
1464 'user_touched' => $dbw->timestamp( $oldTouched )
1468 $success = ( $dbw->affectedRows() > 0 );
1471 $this->mTouched = $newTouched;
1489 $this->mNewtalk = -1;
1490 $this->mDatePreference = null;
1491 $this->mBlockedby = -1; # Unset
1492 $this->mHash =
false;
1493 $this->mRights = null;
1494 $this->mEffectiveGroups = null;
1495 $this->mImplicitGroups = null;
1496 $this->mGroups = null;
1497 $this->mOptions = null;
1498 $this->mOptionsLoaded =
false;
1499 $this->mEditCount = null;
1501 if ( $reloadFrom ) {
1502 $this->mLoadedItems = [];
1503 $this->mFrom = $reloadFrom;
1516 static $defOpt = null;
1517 if ( !defined(
'MW_PHPUNIT_TEST' ) && $defOpt !== null ) {
1526 $defOpt[
'language'] = $wgContLang->getCode();
1528 $defOpt[$langCode == $wgContLang->getCode() ?
'variant' :
"variant-$langCode"] = $langCode;
1530 $namespaces = MediaWikiServices::getInstance()->getSearchEngineConfig()->searchableNamespaces();
1532 $defOpt[
'searchNs' . $nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
1536 Hooks::run(
'UserGetDefaultOptions', [ &$defOpt ] );
1548 $defOpts = self::getDefaultOptions();
1549 if ( isset( $defOpts[$opt] ) ) {
1550 return $defOpts[$opt];
1565 if ( -1 != $this->mBlockedby ) {
1569 wfDebug( __METHOD__ .
": checking...\n" );
1578 # We only need to worry about passing the IP address to the Block generator if the
1579 # user is not immune to autoblocks/hardblocks, and they are the current user so we
1580 # know which IP address they're actually coming from
1582 if ( !$this->
isAllowed(
'ipblock-exempt' ) ) {
1585 $globalUserName = $wgUser->isSafeToLoad()
1586 ? $wgUser->getName()
1588 if ( $this->
getName() === $globalUserName ) {
1597 if ( !$block instanceof
Block && $ip !== null && !in_array( $ip, $wgProxyWhitelist ) ) {
1599 if ( self::isLocallyBlockedProxy( $ip ) ) {
1602 $block->mReason =
wfMessage(
'proxyblockreason' )->text();
1603 $block->setTarget( $ip );
1607 $block->mReason =
wfMessage(
'sorbsreason' )->text();
1608 $block->setTarget( $ip );
1613 if ( !$block instanceof
Block
1614 && $wgApplyIpBlocksToXff
1616 && !in_array( $ip, $wgProxyWhitelist )
1618 $xff = $this->
getRequest()->getHeader(
'X-Forwarded-For' );
1619 $xff = array_map(
'trim', explode(
',', $xff ) );
1620 $xff = array_diff( $xff, [ $ip ] );
1623 if ( $block instanceof
Block ) {
1624 # Mangle the reason to alert the user that the block
1625 # originated from matching the X-Forwarded-For header.
1626 $block->mReason =
wfMessage(
'xffblockreason', $block->mReason )->text();
1630 if ( $block instanceof
Block ) {
1631 wfDebug( __METHOD__ .
": Found block.\n" );
1632 $this->mBlock = $block;
1633 $this->mBlockedby = $block->getByName();
1634 $this->mBlockreason = $block->mReason;
1635 $this->mHideName = $block->mHideName;
1636 $this->mAllowUsertalk = !$block->prevents(
'editownusertalk' );
1638 $this->mBlockedby =
'';
1639 $this->mHideName = 0;
1640 $this->mAllowUsertalk =
false;
1644 Hooks::run(
'GetBlockedStatus', [ &$this ] );
1656 global $wgEnableDnsBlacklist, $wgDnsBlacklistUrls, $wgProxyWhitelist;
1658 if ( !$wgEnableDnsBlacklist ) {
1662 if ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) ) {
1682 $ipReversed = implode(
'.', array_reverse( explode(
'.', $ip ) ) );
1688 if ( is_array( $base ) ) {
1689 if ( count( $base ) >= 2 ) {
1691 $host =
"{$base[1]}.$ipReversed.{$base[0]}";
1693 $host =
"$ipReversed.{$base[0]}";
1695 $basename = $base[0];
1697 $host =
"$ipReversed.$base";
1701 $ipList = gethostbynamel( $host );
1704 wfDebugLog(
'dnsblacklist',
"Hostname $host is {$ipList[0]}, it's a proxy says $basename!" );
1708 wfDebugLog(
'dnsblacklist',
"Requested $host, not found in $basename." );
1726 if ( !$wgProxyList ) {
1730 if ( !is_array( $wgProxyList ) ) {
1732 $wgProxyList = array_map(
'trim',
file( $wgProxyList ) );
1735 if ( !is_array( $wgProxyList ) ) {
1737 } elseif ( array_search( $ip, $wgProxyList ) !==
false ) {
1739 } elseif ( array_key_exists( $ip, $wgProxyList ) ) {
1754 global $wgRateLimitsExcludedIPs;
1755 if ( in_array( $this->
getRequest()->getIP(), $wgRateLimitsExcludedIPs ) ) {
1761 return !$this->
isAllowed(
'noratelimit' );
1786 if ( !isset( $wgRateLimits[$action] ) ) {
1795 $limits = $wgRateLimits[$action];
1797 $id = $this->
getId();
1803 if ( isset( $limits[
'anon'] ) ) {
1804 $keys[
wfMemcKey(
'limiter', $action,
'anon' )] = $limits[
'anon'];
1808 if ( isset( $limits[
'user'] ) ) {
1809 $userLimit = $limits[
'user'];
1812 if ( $isNewbie && isset( $limits[
'newbie'] ) ) {
1813 $keys[
wfMemcKey(
'limiter', $action,
'user', $id )] = $limits[
'newbie'];
1820 if ( isset( $limits[
'ip'] ) ) {
1822 $keys[
"mediawiki:limiter:$action:ip:$ip"] = $limits[
'ip'];
1825 if ( isset( $limits[
'subnet'] ) ) {
1828 if ( $subnet !==
false ) {
1829 $keys[
"mediawiki:limiter:$action:subnet:$subnet"] = $limits[
'subnet'];
1837 if ( isset( $limits[$group] ) ) {
1838 if ( $userLimit ===
false
1839 || $limits[$group][0] / $limits[$group][1] > $userLimit[0] / $userLimit[1]
1841 $userLimit = $limits[$group];
1847 if ( $userLimit !==
false ) {
1848 list( $max, $period ) = $userLimit;
1849 wfDebug( __METHOD__ .
": effective user limit: $max in {$period}s\n" );
1850 $keys[
wfMemcKey(
'limiter', $action,
'user', $id )] = $userLimit;
1854 if ( isset( $limits[
'ip-all'] ) ) {
1857 if ( $isNewbie || $userLimit ===
false
1858 || $limits[
'ip-all'][0] / $limits[
'ip-all'][1] > $userLimit[0] / $userLimit[1] ) {
1859 $keys[
"mediawiki:limiter:$action:ip-all:$ip"] = $limits[
'ip-all'];
1864 if ( isset( $limits[
'subnet-all'] ) ) {
1867 if ( $subnet !==
false ) {
1869 if ( $isNewbie || $userLimit ===
false
1870 || $limits[
'ip-all'][0] / $limits[
'ip-all'][1]
1871 > $userLimit[0] / $userLimit[1] ) {
1872 $keys[
"mediawiki:limiter:$action:subnet-all:$subnet"] = $limits[
'subnet-all'];
1882 $summary =
"(limit $max in {$period}s)";
1887 wfDebugLog(
'ratelimit',
"User '{$this->getName()}' " .
1888 "(IP {$this->getRequest()->getIP()}) tripped $key at $count $summary" );
1891 wfDebug( __METHOD__ .
": ok. $key at $count $summary\n" );
1894 wfDebug( __METHOD__ .
": adding record for $key $summary\n" );
1926 return $this->mBlock instanceof
Block ? $this->mBlock : null;
1937 global $wgBlockAllowsUTEdit;
1939 $blocked = $this->
isBlocked( $bFromSlave );
1940 $allowUsertalk = ( $wgBlockAllowsUTEdit ? $this->mAllowUsertalk :
false );
1942 if ( !$this->mHideName && $allowUsertalk &&
$title->getText() === $this->
getName()
1945 wfDebug( __METHOD__ .
": self-talk page, ignoring any blocks\n" );
1948 Hooks::run(
'UserIsBlockedFrom', [ $this,
$title, &$blocked, &$allowUsertalk ] );
1977 return ( $this->mBlock ? $this->mBlock->getId() :
false );
2003 if ( $this->mGlobalBlock !== null ) {
2004 return $this->mGlobalBlock ?: null;
2014 Hooks::run(
'UserIsBlockedGlobally', [ &$this, $ip, &$blocked, &$block ] );
2016 if ( $blocked && $block === null ) {
2022 $this->mGlobalBlock = $blocked ? $block :
false;
2023 return $this->mGlobalBlock ?: null;
2032 if ( $this->mLocked !== null ) {
2035 $authUser = AuthManager::callLegacyAuthPlugin(
'getUserInstance', [ &$this ], null );
2036 $this->mLocked = $authUser && $authUser->isLocked();
2037 Hooks::run(
'UserIsLocked', [ $this, &$this->mLocked ] );
2047 if ( $this->mHideName !== null ) {
2051 if ( !$this->mHideName ) {
2052 $authUser = AuthManager::callLegacyAuthPlugin(
'getUserInstance', [ &$this ], null );
2053 $this->mHideName = $authUser && $authUser->isHidden();
2054 Hooks::run(
'UserIsHidden', [ $this, &$this->mHideName ] );
2064 if ( $this->mId === null && $this->mName !== null &&
User::isIP( $this->mName ) ) {
2094 if ( $this->mName ===
false ) {
2117 $this->mName = $str;
2125 return str_replace(
' ',
'_', $this->
getName() );
2136 if ( $this->mNewtalk === -1 ) {
2137 $this->mNewtalk =
false; # reset talk
page status
2141 if ( !$this->mId ) {
2142 global $wgDisableAnonTalk;
2143 if ( $wgDisableAnonTalk ) {
2145 $this->mNewtalk =
false;
2150 $this->mNewtalk = $this->
checkNewtalk(
'user_id', $this->mId );
2172 if ( !
Hooks::run(
'UserRetrieveNewTalks', [ &$this, &$talks ] ) ) {
2181 'MIN(user_last_timestamp)',
2182 $this->
isAnon() ? [
'user_ip' => $this->
getName() ] : [
'user_id' => $this->
getId() ],
2185 return [ [
'wiki' =>
wfWikiID(),
'link' => $utp->getLocalURL(),
'rev' =>
$rev ] ];
2194 $newMessageRevisionId = null;
2196 if ( $newMessageLinks ) {
2200 if ( count( $newMessageLinks ) === 1
2201 && $newMessageLinks[0][
'wiki'] ===
wfWikiID()
2202 && $newMessageLinks[0][
'rev']
2205 $newMessageRevision = $newMessageLinks[0][
'rev'];
2206 $newMessageRevisionId = $newMessageRevision->getId();
2209 return $newMessageRevisionId;
2223 $ok =
$dbr->selectField(
'user_newtalk', $field, [ $field => $id ], __METHOD__ );
2225 return $ok !==
false;
2237 $prevRev = $curRev ? $curRev->getPrevious() :
false;
2238 $ts = $prevRev ? $prevRev->getTimestamp() : null;
2241 $dbw->insert(
'user_newtalk',
2242 [ $field => $id,
'user_last_timestamp' => $dbw->timestampOrNull( $ts ) ],
2245 if ( $dbw->affectedRows() ) {
2246 wfDebug( __METHOD__ .
": set on ($field, $id)\n" );
2249 wfDebug( __METHOD__ .
" already set ($field, $id)\n" );
2262 $dbw->delete(
'user_newtalk',
2265 if ( $dbw->affectedRows() ) {
2266 wfDebug( __METHOD__ .
": killed on ($field, $id)\n" );
2269 wfDebug( __METHOD__ .
": already gone ($field, $id)\n" );
2286 $this->mNewtalk = $val;
2293 $id = $this->
getId();
2316 if ( $this->mTouched && $time <= $this->mTouched ) {
2334 if ( !$this->
getId() ) {
2339 $processCache = self::getInProcessCache();
2341 if ( $mode ===
'refresh' ) {
2343 $processCache->delete(
$key );
2348 $processCache->delete(
$key );
2377 $id = $this->
getId();
2381 $this->mQuickTouched = null;
2406 if ( $this->mQuickTouched === null ) {
2413 return max( $this->mTouched, $this->mQuickTouched );
2436 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2445 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2489 $manager = AuthManager::singleton();
2492 if ( !$manager->userExists( $this->getName() ) ) {
2493 throw new LogicException(
'Cannot set a password for a user that is not in the database.' );
2497 'username' => $this->
getName(),
2503 ->info( __METHOD__ .
': Password change rejected: '
2504 .
$status->getWikiText( null, null,
'en' ) );
2508 $this->
setOption(
'watchlisttoken',
false );
2509 SessionManager::singleton()->invalidateSessionsForUser( $this );
2527 $manager = AuthManager::singleton();
2528 $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
2529 $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
2532 foreach ( $reqs
as $req ) {
2533 $status->merge( $manager->allowsAuthenticationDataChange( $req ),
true );
2535 if (
$status->getValue() ===
'ignored' ) {
2536 $status->warning(
'authenticationdatachange-ignored' );
2540 foreach ( $reqs
as $req ) {
2541 $manager->changeAuthenticationData( $req );
2554 global $wgAuthenticationTokenVersion;
2557 if ( !$this->mToken && $forceCreation ) {
2561 if ( !$this->mToken ) {
2564 } elseif ( $this->mToken === self::INVALID_TOKEN ) {
2568 } elseif ( $wgAuthenticationTokenVersion === null ) {
2576 $len = max( 32, self::TOKEN_LENGTH );
2577 if ( strlen(
$ret ) < $len ) {
2579 throw new \UnexpectedValueException(
'Hmac returned less than 128 bits' );
2581 return substr(
$ret, -$len );
2593 if ( $this->mToken === self::INVALID_TOKEN ) {
2595 ->debug( __METHOD__ .
": Ignoring attempt to set token for system user \"$this\"" );
2596 } elseif ( !$token ) {
2599 $this->mToken = $token;
2612 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2622 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2631 Hooks::run(
'UserGetEmail', [ $this, &$this->mEmail ] );
2641 Hooks::run(
'UserGetEmailAuthenticationTimestamp', [ $this, &$this->mEmailAuthenticated ] );
2651 if ( $str == $this->mEmail ) {
2655 $this->mEmail = $str;
2656 Hooks::run(
'UserSetEmail', [ $this, &$this->mEmail ] );
2669 if ( !$wgEnableEmail ) {
2674 if ( $str === $oldaddr ) {
2678 $type = $oldaddr !=
'' ?
'changed' :
'set';
2679 $notificationResult = null;
2681 if ( $wgEmailAuthentication ) {
2684 if (
$type ==
'changed' ) {
2685 $change = $str !=
'' ?
'changed' :
'removed';
2686 $notificationResult = $this->
sendMail(
2687 wfMessage(
'notificationemail_subject_' . $change )->
text(),
2688 wfMessage(
'notificationemail_body_' . $change,
2698 if ( $str !==
'' && $wgEmailAuthentication ) {
2702 if ( $notificationResult !== null ) {
2703 $result->merge( $notificationResult );
2735 $this->mRealName = $str;
2748 public function getOption( $oname, $defaultOverride = null, $ignoreHidden =
false ) {
2752 # We want 'disabled' preferences to always behave as the default value for
2753 # users, even if they have set the option explicitly in their settings (ie they
2754 # set it, and then it was disabled removing their ability to change it). But
2755 # we don't want to erase the preferences in the database in case the preference
2756 # is re-enabled again. So don't touch $mOptions, just override the returned value
2757 if ( !$ignoreHidden && in_array( $oname, $wgHiddenPrefs ) ) {
2758 return self::getDefaultOption( $oname );
2761 if ( array_key_exists( $oname, $this->mOptions ) ) {
2762 return $this->mOptions[$oname];
2764 return $defaultOverride;
2781 # We want 'disabled' preferences to always behave as the default value for
2782 # users, even if they have set the option explicitly in their settings (ie they
2783 # set it, and then it was disabled removing their ability to change it). But
2784 # we don't want to erase the preferences in the database in case the preference
2785 # is re-enabled again. So don't touch $mOptions, just override the returned value
2786 foreach ( $wgHiddenPrefs
as $pref ) {
2787 $default = self::getDefaultOption( $pref );
2788 if ( $default !== null ) {
2793 if (
$flags & self::GETOPTIONS_EXCLUDE_DEFAULTS ) {
2808 return (
bool)$this->
getOption( $oname );
2822 $val = $defaultOverride;
2824 return intval( $val );
2839 if ( is_null( $val ) ) {
2840 $val = self::getDefaultOption( $oname );
2843 $this->mOptions[$oname] = $val;
2859 $id = $this->
getId();
2860 if ( !$id || in_array( $oname, $wgHiddenPrefs ) ) {
2869 $token = hash_hmac(
'sha1',
"$oname:$id", $this->
getToken() );
2886 if ( in_array( $oname, $wgHiddenPrefs ) ) {
2921 'registered-multiselect',
2922 'registered-checkmatrix',
2954 unset( $prefs[
$name] );
2959 $multiselectOptions = [];
2960 foreach ( $prefs
as $name => $info ) {
2961 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'multiselect' ) ||
2962 ( isset( $info[
'class'] ) && $info[
'class'] ==
'HTMLMultiSelectField' ) ) {
2964 $prefix = isset( $info[
'prefix'] ) ? $info[
'prefix'] :
$name;
2967 $multiselectOptions[
"$prefix$value"] =
true;
2970 unset( $prefs[
$name] );
2973 $checkmatrixOptions = [];
2974 foreach ( $prefs
as $name => $info ) {
2975 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'checkmatrix' ) ||
2976 ( isset( $info[
'class'] ) && $info[
'class'] ==
'HTMLCheckMatrix' ) ) {
2979 $prefix = isset( $info[
'prefix'] ) ? $info[
'prefix'] :
$name;
2981 foreach ( $columns
as $column ) {
2982 foreach ( $rows
as $row ) {
2983 $checkmatrixOptions[
"$prefix$column-$row"] =
true;
2987 unset( $prefs[
$name] );
2993 if ( isset( $prefs[
$key] ) ) {
2994 $mapping[
$key] =
'registered';
2995 } elseif ( isset( $multiselectOptions[$key] ) ) {
2996 $mapping[
$key] =
'registered-multiselect';
2997 } elseif ( isset( $checkmatrixOptions[$key] ) ) {
2998 $mapping[
$key] =
'registered-checkmatrix';
2999 } elseif ( isset( $specialOptions[$key] ) ) {
3000 $mapping[
$key] =
'special';
3001 } elseif ( substr( $key, 0, 7 ) ===
'userjs-' ) {
3002 $mapping[
$key] =
'userjs';
3004 $mapping[
$key] =
'unused';
3026 $resetKinds = [
'registered',
'registered-multiselect',
'registered-checkmatrix',
'unused' ],
3030 $defaultOptions = self::getDefaultOptions();
3032 if ( !is_array( $resetKinds ) ) {
3033 $resetKinds = [ $resetKinds ];
3036 if ( in_array(
'all', $resetKinds ) ) {
3037 $newOptions = $defaultOptions;
3044 $resetKinds = array_intersect( $resetKinds, self::listOptionKinds() );
3050 if ( in_array( $optionKinds[
$key], $resetKinds ) ) {
3051 if ( array_key_exists( $key, $defaultOptions ) ) {
3052 $newOptions[
$key] = $defaultOptions[
$key];
3060 Hooks::run(
'UserResetAllOptions', [ $this, &$newOptions, $this->mOptions, $resetKinds ] );
3062 $this->mOptions = $newOptions;
3063 $this->mOptionsLoaded =
true;
3072 if ( is_null( $this->mDatePreference ) ) {
3075 $map = $wgLang->getDatePreferenceMigrationMap();
3076 if ( isset( $map[
$value] ) ) {
3079 $this->mDatePreference =
$value;
3092 if ( !$wgSecureLogin ) {
3096 Hooks::run(
'UserRequiresHTTPS', [ $this, &$https ] );
3112 if ( $threshold > $wgMaxArticleSize * 1024 ) {
3125 if ( is_null( $this->mRights ) ) {
3127 Hooks::run(
'UserGetRights', [ $this, &$this->mRights ] );
3131 if ( !defined(
'MW_NO_SESSION' ) ) {
3132 $allowedRights = $this->
getRequest()->getSession()->getAllowedUserRights();
3133 if ( $allowedRights !== null ) {
3134 $this->mRights = array_intersect( $this->mRights, $allowedRights );
3139 $this->mRights = array_values( array_unique( $this->mRights ) );
3150 $config->get(
'BlockDisablesLogin' ) &&
3154 $this->mRights = array_intersect( $this->mRights, $anon->getRights() );
3179 if ( $recache || is_null( $this->mEffectiveGroups ) ) {
3180 $this->mEffectiveGroups = array_unique( array_merge(
3185 Hooks::run(
'UserEffectiveGroups', [ &$this, &$this->mEffectiveGroups ] );
3187 $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
3200 if ( $recache || is_null( $this->mImplicitGroups ) ) {
3201 $this->mImplicitGroups = [
'*' ];
3202 if ( $this->
getId() ) {
3203 $this->mImplicitGroups[] =
'user';
3205 $this->mImplicitGroups = array_unique( array_merge(
3206 $this->mImplicitGroups,
3213 $this->mEffectiveGroups = null;
3231 if ( is_null( $this->mFormerGroups ) ) {
3232 $db = ( $this->queryFlagsUsed & self::READ_LATEST )
3235 $res = $db->select(
'user_former_groups',
3237 [
'ufg_user' => $this->mId ],
3239 $this->mFormerGroups = [];
3240 foreach (
$res as $row ) {
3241 $this->mFormerGroups[] = $row->ufg_group;
3253 if ( !$this->
getId() ) {
3257 if ( $this->mEditCount === null ) {
3262 'user',
'user_editcount',
3263 [
'user_id' => $this->mId ],
3271 $this->mEditCount =
$count;
3285 if ( !
Hooks::run(
'UserAddGroup', [ $this, &$group ] ) ) {
3290 if ( $this->
getId() ) {
3291 $dbw->insert(
'user_groups',
3293 'ug_user' => $this->
getId(),
3294 'ug_group' => $group,
3301 $this->mGroups[] = $group;
3304 $this->mGroups = array_unique( $this->mGroups );
3309 $this->mRights = null;
3324 if ( !
Hooks::run(
'UserRemoveGroup', [ $this, &$group ] ) ) {
3329 $dbw->delete(
'user_groups',
3331 'ug_user' => $this->
getId(),
3332 'ug_group' => $group,
3336 $dbw->insert(
'user_former_groups',
3338 'ufg_user' => $this->
getId(),
3339 'ufg_group' => $group,
3346 $this->mGroups = array_diff( $this->mGroups, [ $group ] );
3351 $this->mRights = null;
3363 return $this->
getId() != 0;
3381 $permissions = func_get_args();
3382 foreach ( $permissions
as $permission ) {
3383 if ( $this->
isAllowed( $permission ) ) {
3396 $permissions = func_get_args();
3397 foreach ( $permissions
as $permission ) {
3398 if ( !$this->
isAllowed( $permission ) ) {
3411 if ( $action ===
'' ) {
3416 return in_array( $action, $this->
getRights(),
true );
3425 return $wgUseRCPatrol && $this->
isAllowedAny(
'patrol',
'patrolmarks' );
3433 global $wgUseRCPatrol, $wgUseNPPatrol;
3435 ( $wgUseRCPatrol || $wgUseNPPatrol )
3445 global $wgUseRCPatrol, $wgUseFilePatrol;
3447 ( $wgUseRCPatrol || $wgUseFilePatrol )
3458 if ( $this->mRequest ) {
3475 if (
$title->isWatchable() && ( !$checkRights || $this->
isAllowed(
'viewmywatchlist' ) ) ) {
3489 if ( !$checkRights || $this->
isAllowed(
'editmywatchlist' ) ) {
3506 if ( !$checkRights || $this->
isAllowed(
'editmywatchlist' ) ) {
3530 if ( !$this->
isAllowed(
'editmywatchlist' ) ) {
3536 if ( !
Hooks::run(
'UserClearNewTalkNotification', [ &$this, $oldid ] ) ) {
3559 if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3578 ->resetNotificationTimestamp( $this,
$title, $force, $oldid );
3593 if ( !$this->
isAllowed(
'editmywatchlist' ) ) {
3598 if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3602 $id = $this->
getId();
3605 $dbw->update(
'watchlist',
3606 [
'wl_notificationtimestamp' => null ],
3607 [
'wl_user' => $id,
'wl_notificationtimestamp IS NOT NULL' ],
3673 global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
3678 $exp += $wgExtendedLoginCookieExpiration !== null
3679 ? $wgExtendedLoginCookieExpiration
3680 : $wgCookieExpiration;
3695 if ( 0 == $this->mId ) {
3699 $session = $this->
getRequest()->getSession();
3701 $session = $session->sessionWithRequest(
$request );
3703 $delay = $session->delaySave();
3705 if ( !$session->getUser()->equals( $this ) ) {
3706 if ( !$session->canSetUser() ) {
3708 ->warning( __METHOD__ .
3709 ": Cannot save user \"$this\" to a user \"{$session->getUser()}\"'s immutable session"
3713 $session->setUser( $this );
3716 $session->setRememberUser( $rememberMe );
3717 if ( $secure !== null ) {
3718 $session->setForceHTTPS( $secure );
3721 $session->persist();
3730 if (
Hooks::run(
'UserLogout', [ &$this ] ) ) {
3740 $session = $this->
getRequest()->getSession();
3741 if ( !$session->canSetUser() ) {
3743 ->warning( __METHOD__ .
": Cannot log out of an immutable session" );
3744 } elseif ( !$session->getUser()->equals( $this ) ) {
3746 ->warning( __METHOD__ .
3747 ": Cannot log user \"$this\" out of a user \"{$session->getUser()}\"'s session"
3753 $delay = $session->delaySave();
3754 $session->unpersist();
3755 $session->setLoggedOutTimestamp( time() );
3756 $session->setUser(
new User );
3757 $session->set(
'wsUserID', 0 );
3758 $session->resetAllTokens();
3773 "Could not update user with ID '{$this->mId}'; DB is read-only."
3779 if ( 0 == $this->mId ) {
3790 $dbw->update(
'user',
3792 'user_name' => $this->mName,
3793 'user_real_name' => $this->mRealName,
3794 'user_email' => $this->mEmail,
3795 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3796 'user_touched' => $dbw->timestamp( $newTouched ),
3797 'user_token' => strval( $this->mToken ),
3799 'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
3802 'user_touched' => $dbw->timestamp( $oldTouched )
3806 if ( !$dbw->affectedRows() ) {
3810 $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ?
'master' :
'slave';
3812 "CAS update failed on user_touched for user ID '{$this->mId}' (read from $from);" .
3813 " the version of the user to be saved is older than the current version."
3817 $this->mTouched = $newTouched;
3837 $db = ( (
$flags & self::READ_LATEST ) == self::READ_LATEST )
3841 $options = ( (
$flags & self::READ_LOCKING ) == self::READ_LOCKING )
3842 ? [
'LOCK IN SHARE MODE' ]
3845 $id = $db->selectField(
'user',
3846 'user_id', [
'user_name' =>
$s ], __METHOD__,
$options );
3867 foreach ( [
'password',
'newpassword',
'newpass_time',
'password_expires' ]
as $field ) {
3868 if ( isset(
$params[$field] ) ) {
3869 wfDeprecated( __METHOD__ .
" with param '$field'",
'1.27' );
3877 if ( isset(
$params[
'options'] ) ) {
3882 $seqVal = $dbw->nextSequenceValue(
'user_user_id_seq' );
3887 'user_id' => $seqVal,
3888 'user_name' =>
$name,
3889 'user_password' => $noPass,
3890 'user_newpassword' => $noPass,
3891 'user_email' =>
$user->mEmail,
3892 'user_email_authenticated' => $dbw->timestampOrNull(
$user->mEmailAuthenticated ),
3893 'user_real_name' =>
$user->mRealName,
3894 'user_token' => strval(
$user->mToken ),
3895 'user_registration' => $dbw->timestamp(
$user->mRegistration ),
3896 'user_editcount' => 0,
3897 'user_touched' => $dbw->timestamp(
$user->newTouchedTimestamp() ),
3900 $fields[
"user_$name"] =
$value;
3902 $dbw->insert(
'user', $fields, __METHOD__, [
'IGNORE' ] );
3903 if ( $dbw->affectedRows() ) {
3939 if ( !$this->mToken ) {
3948 $inWrite = $dbw->writesOrCallbacksPending();
3949 $seqVal = $dbw->nextSequenceValue(
'user_user_id_seq' );
3950 $dbw->insert(
'user',
3952 'user_id' => $seqVal,
3953 'user_name' => $this->mName,
3954 'user_password' => $noPass,
3955 'user_newpassword' => $noPass,
3956 'user_email' => $this->mEmail,
3957 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3959 'user_token' => strval( $this->mToken ),
3960 'user_registration' => $dbw->timestamp( $this->mRegistration ),
3961 'user_editcount' => 0,
3962 'user_touched' => $dbw->timestamp( $this->mTouched ),
3966 if ( !$dbw->affectedRows() ) {
3972 $options = [
'LOCK IN SHARE MODE' ];
3973 $flags = self::READ_LOCKING;
3977 $dbw->commit( __METHOD__,
'flush' );
3979 $flags = self::READ_LATEST;
3981 $this->mId = $dbw->selectField(
'user',
'user_id',
3982 [
'user_name' => $this->mName ], __METHOD__,
$options );
3990 throw new MWException( __METHOD__ .
": hit a key conflict attempting " .
3991 "to insert user '{$this->mName}' row, but it was not present in select!" );
3995 $this->mId = $dbw->insertId();
4024 wfDebug( __METHOD__ .
"()\n" );
4026 if ( $this->mId == 0 ) {
4031 if ( !$userblock ) {
4035 return (
bool)$userblock->doAutoblock( $this->
getRequest()->getIP() );
4044 if ( $this->mBlock && $this->mBlock->prevents(
'createaccount' ) ) {
4048 # bug 13611: if the IP address the user is trying to create an account from is
4049 # blocked with createaccount disabled, prevent new account creation there even
4050 # when the user is logged in
4051 if ( $this->mBlockedFromCreateAccount ===
false && !$this->
isAllowed(
'ipblock-exempt' ) ) {
4054 return $this->mBlockedFromCreateAccount instanceof
Block
4055 && $this->mBlockedFromCreateAccount->
prevents(
'createaccount' )
4056 ? $this->mBlockedFromCreateAccount
4066 return $this->mBlock && $this->mBlock->prevents(
'sendemail' );
4093 return $title->getTalkPage();
4102 return !$this->
isAllowed(
'autoconfirmed' );
4112 $manager = AuthManager::singleton();
4113 $reqs = AuthenticationRequest::loadRequestsFromSubmission(
4114 $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
4116 'username' => $this->
getName(),
4117 'password' => $password,
4120 $res = AuthManager::singleton()->beginAuthentication( $reqs,
'null:' );
4121 switch ( $res->status ) {
4122 case AuthenticationResponse::PASS:
4124 case AuthenticationResponse::FAIL:
4127 ->info( __METHOD__ .
': Authentication failed: ' . $res->message->plain() );
4130 throw new BadMethodCallException(
4131 'AuthManager returned a response unsupported by ' . __METHOD__
4168 return $request->getSession()->getToken( $salt );
4224 $val = substr( $val, 0, strspn( $val,
'0123456789abcdef' ) ) . Token::SUFFIX;
4243 if (
$type ==
'created' ||
$type ===
false ) {
4244 $message =
'confirmemail_body';
4245 } elseif (
$type ===
true ) {
4246 $message =
'confirmemail_body_changed';
4249 $message =
'confirmemail_body_' .
$type;
4257 $wgLang->userTimeAndDate( $expiration, $this ),
4259 $wgLang->userDate( $expiration, $this ),
4260 $wgLang->userTime( $expiration, $this ) )->
text() );
4286 'replyTo' => $replyto,
4307 $hash = md5( $token );
4308 $this->mEmailToken = $hash;
4309 $this->mEmailTokenExpires = $expiration;
4319 return $this->
getTokenUrl(
'ConfirmEmail', $token );
4328 return $this->
getTokenUrl(
'InvalidateEmail', $token );
4348 return $title->getCanonicalURL();
4363 Hooks::run(
'ConfirmEmailComplete', [ $this ] );
4377 $this->mEmailToken = null;
4378 $this->mEmailTokenExpires = null;
4381 Hooks::run(
'InvalidateEmailComplete', [ $this ] );
4392 Hooks::run(
'UserSetEmailAuthenticationTimestamp', [ $this, &$this->mEmailAuthenticated ] );
4402 if ( !$wgEnableEmail || !$wgEnableUserEmail || !$this->
isAllowed(
'sendemail' ) ) {
4406 Hooks::run(
'UserCanSendEmail', [ &$this, &$canSend ] );
4433 if (
Hooks::run(
'EmailConfirmed', [ &$this, &$confirmed ] ) ) {
4455 return $wgEmailAuthentication &&
4457 $this->mEmailToken &&
4483 if ( $this->
getId() == 0 ) {
4487 $time =
$dbr->selectField(
'revision',
'rev_timestamp',
4488 [
'rev_user' => $this->
getId() ],
4490 [
'ORDER BY' =>
'rev_timestamp ASC' ]
4505 global $wgGroupPermissions, $wgRevokePermissions;
4508 foreach ( $groups
as $group ) {
4509 if ( isset( $wgGroupPermissions[$group] ) ) {
4510 $rights = array_merge( $rights,
4512 array_keys( array_filter( $wgGroupPermissions[$group] ) ) );
4516 foreach ( $groups
as $group ) {
4517 if ( isset( $wgRevokePermissions[$group] ) ) {
4518 $rights = array_diff( $rights,
4519 array_keys( array_filter( $wgRevokePermissions[$group] ) ) );
4522 return array_unique( $rights );
4532 global $wgGroupPermissions;
4533 $allowedGroups = [];
4534 foreach ( array_keys( $wgGroupPermissions )
as $group ) {
4535 if ( self::groupHasPermission( $group, $role ) ) {
4536 $allowedGroups[] = $group;
4539 return $allowedGroups;
4555 global $wgGroupPermissions, $wgRevokePermissions;
4556 return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
4557 && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
4575 global $wgGroupPermissions, $wgRevokePermissions;
4580 if ( isset(
$cache[$right] ) && !defined(
'MW_PHPUNIT_TEST' ) ) {
4584 if ( !isset( $wgGroupPermissions[
'*'][$right] ) || !$wgGroupPermissions[
'*'][$right] ) {
4590 foreach ( $wgRevokePermissions
as $rights ) {
4591 if ( isset( $rights[$right] ) && $rights[$right] ) {
4599 if ( !defined(
'MW_NO_SESSION' ) ) {
4600 $allowedRights = SessionManager::getGlobalSession()->getAllowedUserRights();
4601 if ( $allowedRights !== null && !in_array( $right, $allowedRights,
true ) ) {
4608 if ( !
Hooks::run(
'UserIsEveryoneAllowed', [ $right ] ) ) {
4625 return $msg->isBlank() ? $group : $msg->text();
4637 return $msg->isBlank() ? $group : $msg->text();
4647 global $wgGroupPermissions, $wgRevokePermissions;
4649 array_merge( array_keys( $wgGroupPermissions ), array_keys( $wgRevokePermissions ) ),
4650 self::getImplicitGroups()
4659 if ( self::$mAllRights ===
false ) {
4660 global $wgAvailableRights;
4661 if ( count( $wgAvailableRights ) ) {
4662 self::$mAllRights = array_unique( array_merge( self::$mCoreRights, $wgAvailableRights ) );
4664 self::$mAllRights = self::$mCoreRights;
4666 Hooks::run(
'UserGetAllRights', [ &self::$mAllRights ] );
4668 return self::$mAllRights;
4676 global $wgImplicitGroups;
4678 $groups = $wgImplicitGroups;
4679 # Deprecated, use $wgImplicitGroups instead
4680 Hooks::run(
'UserGetImplicitGroups', [ &$groups ],
'1.25' );
4692 $msg =
wfMessage(
'grouppage-' . $group )->inContentLanguage();
4693 if ( $msg->exists() ) {
4695 if ( is_object(
$title ) ) {
4711 if ( $text ==
'' ) {
4712 $text = self::getGroupName( $group );
4714 $title = self::getGroupPage( $group );
4718 return htmlspecialchars( $text );
4731 if ( $text ==
'' ) {
4732 $text = self::getGroupName( $group );
4734 $title = self::getGroupPage( $group );
4737 return "[[$page|$text]]";
4753 global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
4762 if ( empty( $wgAddGroups[$group] ) ) {
4764 } elseif ( $wgAddGroups[$group] ===
true ) {
4766 $groups[
'add'] = self::getAllGroups();
4767 } elseif ( is_array( $wgAddGroups[$group] ) ) {
4768 $groups[
'add'] = $wgAddGroups[$group];
4772 if ( empty( $wgRemoveGroups[$group] ) ) {
4774 } elseif ( $wgRemoveGroups[$group] ===
true ) {
4775 $groups[
'remove'] = self::getAllGroups();
4776 } elseif ( is_array( $wgRemoveGroups[$group] ) ) {
4777 $groups[
'remove'] = $wgRemoveGroups[$group];
4781 if ( empty( $wgGroupsAddToSelf[
'user'] ) || $wgGroupsAddToSelf[
'user'] !==
true ) {
4783 if ( is_int(
$key ) ) {
4784 $wgGroupsAddToSelf[
'user'][] =
$value;
4789 if ( empty( $wgGroupsRemoveFromSelf[
'user'] ) || $wgGroupsRemoveFromSelf[
'user'] !==
true ) {
4790 foreach ( $wgGroupsRemoveFromSelf
as $key =>
$value ) {
4791 if ( is_int(
$key ) ) {
4792 $wgGroupsRemoveFromSelf[
'user'][] =
$value;
4798 if ( empty( $wgGroupsAddToSelf[$group] ) ) {
4800 } elseif ( $wgGroupsAddToSelf[$group] ===
true ) {
4803 } elseif ( is_array( $wgGroupsAddToSelf[$group] ) ) {
4804 $groups[
'add-self'] = $wgGroupsAddToSelf[$group];
4807 if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
4809 } elseif ( $wgGroupsRemoveFromSelf[$group] ===
true ) {
4811 } elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {
4812 $groups[
'remove-self'] = $wgGroupsRemoveFromSelf[$group];
4826 if ( $this->
isAllowed(
'userrights' ) ) {
4849 foreach ( $addergroups
as $addergroup ) {
4850 $groups = array_merge_recursive(
4853 $groups[
'add'] = array_unique( $groups[
'add'] );
4854 $groups[
'remove'] = array_unique( $groups[
'remove'] );
4855 $groups[
'add-self'] = array_unique( $groups[
'add-self'] );
4856 $groups[
'remove-self'] = array_unique( $groups[
'remove-self'] );
4884 [
'user_editcount=user_editcount+1' ],
4885 [
'user_id' => $this->
getId(),
'user_editcount IS NOT NULL' ],
4889 if ( $dbw->affectedRows() == 0 ) {
4892 if (
$dbr !== $dbw ) {
4921 [
'rev_user' => $this->getId() ],
4929 [
'user_editcount' =>
$count ],
4930 [
'user_id' => $this->
getId() ],
4944 $key =
"right-$right";
4946 return $msg->isBlank() ? $right : $msg->text();
4958 public static function crypt( $password, $salt =
false ) {
4962 $hash = $passwordFactory->newFromPlaintext( $password );
4963 return $hash->toString();
4982 if ( preg_match(
'/^[0-9a-f]{32}$/', $hash ) ) {
4984 if ( $wgPasswordSalt ) {
4985 $password =
":B:{$userId}:{$hash}";
4987 $password =
":A:{$hash}";
4993 $hash = $passwordFactory->newFromCiphertext( $hash );
4994 return $hash->equals( $password );
5045 if ( $this->mOptionsLoaded ) {
5049 $this->mOptions = self::getDefaultOptions();
5051 if ( !$this->
getId() ) {
5056 $variant = $wgContLang->getDefaultVariant();
5057 $this->mOptions[
'variant'] = $variant;
5058 $this->mOptions[
'language'] = $variant;
5059 $this->mOptionsLoaded =
true;
5064 if ( !is_null( $this->mOptionOverrides ) ) {
5065 wfDebug(
"User: loading options for user " . $this->
getId() .
" from override cache.\n" );
5066 foreach ( $this->mOptionOverrides
as $key =>
$value ) {
5070 if ( !is_array( $data ) ) {
5071 wfDebug(
"User: loading options for user " . $this->
getId() .
" from database.\n" );
5073 $dbr = ( $this->queryFlagsUsed & self::READ_LATEST )
5079 [
'up_property',
'up_value' ],
5080 [
'up_user' => $this->
getId() ],
5084 $this->mOptionOverrides = [];
5086 foreach (
$res as $row ) {
5087 $data[$row->up_property] = $row->up_value;
5096 $this->mOptionsLoaded =
true;
5098 Hooks::run(
'UserLoadOptions', [ $this, &$this->mOptions ] );
5114 if ( !
Hooks::run(
'UserSaveOptions', [ $this, &$saveOptions ] ) ) {
5118 $userId = $this->
getId();
5123 $defaultOption = self::getDefaultOption(
$key );
5124 if ( ( $defaultOption === null &&
$value !==
false &&
$value !== null )
5125 ||
$value != $defaultOption
5128 'up_user' => $userId,
5129 'up_property' =>
$key,
5137 $res = $dbw->select(
'user_properties',
5138 [
'up_property',
'up_value' ], [
'up_user' => $userId ], __METHOD__ );
5143 foreach (
$res as $row ) {
5144 if ( !isset( $saveOptions[$row->up_property] )
5145 || strcmp( $saveOptions[$row->up_property], $row->up_value ) != 0
5147 $keysDelete[] = $row->up_property;
5151 if ( count( $keysDelete ) ) {
5159 $dbw->delete(
'user_properties',
5160 [
'up_user' => $userId,
'up_property' => $keysDelete ], __METHOD__ );
5163 $dbw->insert(
'user_properties', $insert_rows, __METHOD__, [
'IGNORE' ] );
5204 global $wgMinimalPasswordLength;
5206 if ( $wgMinimalPasswordLength == 0 ) {
5210 # Note that the pattern requirement will always be satisfied if the
5211 # input is empty, so we need required in all cases.
5213 # @todo FIXME: Bug 23769: This needs to not claim the password is required
5214 # if e-mail confirmation is being used. Since HTML5 input validation
5215 # is b0rked anyway in some browsers, just return nothing. When it's
5216 # re-enabled, fix this code to not output required for e-mail
5218 # $ret = array( 'required' );
5221 # We can't actually do this right now, because Opera 9.6 will print out
5222 # the entered password visibly in its error message! When other
5223 # browsers add support for this attribute, or Opera fixes its support,
5224 # we can add support with a version check to avoid doing this on Opera
5225 # versions where it will be a problem. Reported to Opera as
5226 # DSK-262266, but they don't have a public bug tracker for us to follow.
5251 'user_email_authenticated',
5253 'user_email_token_expires',
5254 'user_registration',
5269 $groups = array_map(
5270 [
'User',
'makeGroupLinkWiki' ],
5275 return Status::newFatal(
'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
5291 if ( !$this->
getId() ) {
5296 if ( !
$user->loadFromId( self::READ_EXCLUSIVE ) ) {
static newFromName($name, $validate= 'valid')
Static factory method for creation from username.
addAutopromoteOnceGroups($event)
Add the user to the group if he/she meets given criteria.
getEmail()
Get the user's e-mail address.
static randomPassword()
Return a random password.
$wgUserEmailConfirmationTokenExpiry
The time, in seconds, when an email confirmation email expires.
isHidden()
Check if user account is hidden.
static whoIs($id)
Get the username corresponding to a given user ID.
const VERSION
int Serialized record version.
static getMainWANInstance()
Get the main WAN cache object.
setBlocker($user)
Set the user who implemented (or will implement) this block.
Interface for objects which can provide a MediaWiki context on request.
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
isPasswordReminderThrottled()
Has password reminder email been sent within the last $wgPasswordReminderResendTime hours...
static newFromRow($row, $data=null)
Create a new user object from a user row.
wfGetDB($db, $groups=[], $wiki=false)
Get a Database object.
$wgMaxArticleSize
Maximum article size in kilobytes.
getBoolOption($oname)
Get the user's current setting for a given option, as a boolean value.
getNewMessageLinks()
Return the data needed to construct links for new talk page message alerts.
the array() calling protocol came about after MediaWiki 1.4rc1.
isNewbie()
Determine whether the user is a newbie.
static whoIsReal($id)
Get the real name of a user given their user ID.
wfCanIPUseHTTPS($ip)
Determine whether the client at a given source IP is likely to be able to access the wiki via HTTPS...
static HashBagOStuff $inProcessCache
An in-process cache for user data lookup.
matchEditTokenNoSuffix($val, $salt= '', $request=null, $maxage=null)
Check given value against the token value stored in the session, ignoring the suffix.
magic word the default is to use $key to get the and $key value or $key value text $key value html to format the value $key
static sanitizeIP($ip)
Convert an IP into a verbose, uppercase, normalized form.
static getEditTokenTimestamp($val)
Get the embedded timestamp from a token.
isBlockedFrom($title, $bFromSlave=false)
Check if user is blocked from editing a particular article.
checkPassword($password)
Check to see if the given clear-text password is one of the accepted passwords.
static chooseBlock(array $blocks, array $ipChain)
From a list of multiple blocks, find the most exact and strongest Block.
clearInstanceCache($reloadFrom=false)
Clear various cached data stored in this object.
loadFromSession()
Load user data from the session.
isAllowedToCreateAccount()
Get whether the user is allowed to create an account.
Block $mBlockedFromCreateAccount
isValidPassword($password)
Is the input a valid password for this user?
logout()
Log this user out.
clearNotification(&$title, $oldid=0)
Clear the user's notification timestamp for the given title.
isDnsBlacklisted($ip, $checkWhitelist=false)
Whether the given IP is in a DNS blacklist.
static getImplicitGroups()
Get a list of implicit groups.
saveSettings()
Save this user's settings into the database.
static isLocallyBlockedProxy($ip)
Check if an IP address is in the local proxy list.
load($flags=self::READ_NORMAL)
Load the user table data for this object from the source given by mFrom.
getFirstEditTimestamp()
Get the timestamp of the first edit.
static $mCoreRights
Array of Strings Core rights.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
const GETOPTIONS_EXCLUDE_DEFAULTS
Exclude user options that are set to their default value.
isAllowedAny()
Check if user is allowed to access a feature / make an action.
isBlockedFromEmailuser()
Get whether the user is blocked from using Special:Emailuser.
static getCanonicalName($name, $validate= 'valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid...
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
setCookie($name, $value, $exp=0, $secure=null, $params=[], $request=null)
Set a cookie on the user's client.
getAutomaticGroups($recache=false)
Get the list of implicit group memberships this user has.
pingLimiter($action= 'edit', $incrBy=1)
Primitive rate limits: enforce maximum actions per time period to put a brake on flooding.
const TOKEN_LENGTH
int Number of characters in user_token field.
clearSharedCache($mode= 'changed')
Clear user data from memcached.
loadFromUserObject($user)
Load the data for this user object from another user object.
touch()
Update the "touched" timestamp for the user.
deleteNewtalk($field, $id)
Clear the new messages flag for the given user.
processing should stop and the error should be shown to the user * false
updateNewtalk($field, $id, $curRev=null)
Add or update the new messages flag.
isBlockedGlobally($ip= '')
Check if user is blocked on all wikis.
blockedBy()
If user is blocked, return the name of the user who placed the block.
string $mQuickTouched
TS_MW timestamp from cache.
static generateRandomPasswordString($minLength=10)
Generate a random string suitable for a password.
static isUsableName($name)
Usernames which fail to pass this function will be blocked from user login and new account registrati...
null for the local wiki Added in
getRealName()
Get the user's real name.
checkPasswordValidity($password, $purpose= 'login')
Check if this is a valid password for this user.
Check if a user's password complies with any password policies that apply to that user...
checkAndSetTouched()
Bump user_touched if it didn't change since this object was loaded.
static newFromId($id)
Static factory method for creation from a given user ID.
changeableGroups()
Returns an array of groups that this user can add and remove.
clearAllNotifications()
Resets all of the given user's page-change notification timestamps.
isLoggedIn()
Get whether the user is logged in.
static getLocalClusterInstance()
Get the main cluster-local cache object.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
it s the revision text itself In either if gzip is the revision text is gzipped $flags
saveToCache()
Save user data to the shared cache.
checkNewtalk($field, $id)
Internal uncached check for new messages.
setPassword($str)
Set the password and reset the random token.
static createNew($name, $params=[])
Add a user to the database, return the user object.
invalidationTokenUrl($token)
Return a URL the user can use to invalidate their email address.
addNewUserLogEntry($action=false, $reason= '')
Add a newuser log entry for this user.
static resetIdByNameCache()
Reset the cache used in idFromName().
setName($str)
Set the user name.
getDBTouched()
Get the user_touched timestamp field (time of last DB updates)
static newFromText($text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
static isIPv6($ip)
Given a string, determine if it as valid IP in IPv6 only.
when a variable name is used in a it is silently declared as a new local masking the global
static getPreferences($user, IContextSource $context)
getOptions($flags=0)
Get all user's options.
static newFatal($message)
Factory function for fatal errors.
matchEditToken($val, $salt= '', $request=null, $maxage=null)
Check given value against the token value stored in the session.
setToken($token=false)
Set the random token (used for persistent authentication) Called from loadDefaults() among other plac...
static isIPAddress($ip)
Determine if a string is as valid IP address or network (CIDR prefix).
Multi-datacenter aware caching interface.
Value object representing a logged-out user's edit token.
static makeGroupLinkHTML($group, $text= '')
Create a link to the group in HTML, if available; else return the group name.
static makeGroupLinkWiki($group, $text= '')
Create a link to the group in Wikitext, if available; else return the group name. ...
setOption($oname, $val)
Set the given option for a user.
getName()
Get the user name, or the IP of an anonymous user.
see documentation in includes Linker php for Linker::makeImageLink & $time
static selectFields()
Return the list of user fields that should be selected to create a new user object.
string $mName
Cache variables.
string $mRegistration
Cache variables.
$wgEnableEmail
Set to true to enable the e-mail basic features: Password reminders, etc.
setEmailWithConfirmation($str)
Set the user's e-mail address and a confirmation mail if needed.
int $mEditCount
Cache variables.
wfDebug($text, $dest= 'all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
changeAuthenticationData(array $data)
Changes credentials of the user.
static isEveryoneAllowed($right)
Check if all users may be assumed to have the given permission.
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
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.Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page.Return false to stop further processing of the tag $reader:XMLReader object &$pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision.Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag.Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload.Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports.&$fullInterwikiPrefix:Interwiki prefix, may contain colons.&$pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable.Can be used to lazy-load the import sources list.&$importSources:The value of $wgImportSources.Modify as necessary.See the comment in DefaultSettings.php for the detail of how to structure this array. '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 '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 '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 '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. '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 IP::isTrustedProxy() &$ip:IP being check &$result:Change this value to override the result of IP::isTrustedProxy() '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 Sanitizer::validateEmail(), 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. '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) '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 '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. 'LanguageSelector':Hook to change the language selector available on a page.$out:The output page.$cssClassName:CSS class name of the language selector. '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
getTitleKey()
Get the user's name escaped by underscores.
static getAllGroups()
Return the set of defined explicit groups.
resetTokenFromOption($oname)
Reset a token stored in the preferences (like the watchlist one).
loadOptions($data=null)
Load the user options either from cache, the database or an array.
static listOptionKinds()
Return a list of the types of user options currently returned by User::getOptionKinds().
getIntOption($oname, $defaultOverride=0)
Get the user's current setting for a given option, as an integer value.
sendMail($subject, $body, $from=null, $replyto=null)
Send an e-mail to this user's account.
static addCallableUpdate($callable, $type=self::POSTSEND)
Add a callable update.
static send($to, $from, $subject, $body, $options=[])
This function will perform a direct (authenticated) login to a SMTP Server to use for mail relaying i...
string $mEmailTokenExpires
Cache variables.
static getAllRights()
Get a list of all available permissions.
static getInProcessCache()
isEmailConfirmed()
Is this user's e-mail address valid-looking and confirmed within limits of the current site configura...
wfTimestamp($outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
getRequest()
Get the WebRequest object.
static purge($wikiId, $userId)
static isValidUserName($name)
Is the input a valid username?
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
static edits($uid)
Count the number of edits of a user.
isBlockedFromCreateAccount()
Get whether the user is explicitly blocked from account creation.
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 before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled $incrBy
static getDefaultInstance()
setNewpassword($str, $throttle=true)
Set the password for a password reminder or new account email.
static crypt($password, $salt=false)
Make a new-style password hash.
wfDebugLog($logGroup, $text, $dest= 'all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not...
loadDefaults($name=false)
Set cached properties to default.
$mOptionsLoaded
Bool Whether the cache variables have been loaded.
getBlock($bFromSlave=true)
Get the block affecting the user, or null if the user is not blocked.
sendConfirmationMail($type= 'created')
Generate a new e-mail confirmation token and send a confirmation/invalidation mail to the user's give...
string $mEmailToken
Cache variables.
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
setEmailAuthenticationTimestamp($timestamp)
Set the e-mail authentication timestamp.
static comparePasswords($hash, $password, $userId=false)
Compare a password hash with a plain-text password.
getRegistration()
Get the timestamp of account creation.
wfGetLB($wiki=false)
Get a load balancer object.
wfReadOnly()
Check whether the wiki is in read-only mode.
static getMain()
Static methods.
setNewtalk($val, $curRev=null)
Update the 'You have new messages!' status.
static groupHasPermission($group, $role)
Check, if the given group has the given permission.
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
Base class for the more common types of database errors.
addNewUserLogEntryAutoCreate()
Add an autocreate newuser log entry for this user Used by things like CentralAuth and perhaps other a...
static changeableByGroup($group)
Returns an array of the groups that a particular group can add/remove.
isAllowed($action= '')
Internal mechanics of testing a permission.
isItemLoaded($item, $all= 'all')
Return whether an item has been loaded.
isAnon()
Get whether the user is anonymous.
inDnsBlacklist($ip, $bases)
Whether the given IP is in a given DNS blacklist.
resetOptions($resetKinds=[ 'registered', 'registered-multiselect', 'registered-checkmatrix', 'unused'], IContextSource $context=null)
Reset certain (or all) options to the site defaults.
static newFromTarget($specificTarget, $vagueTarget=null, $fromMaster=false)
Given a target and the target's type, get an existing Block object if possible.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
validateCache($timestamp)
Validate the cache for this account.
Stores a single person's name and email address.
static loadFromTimestamp($db, $title, $timestamp)
Load the revision for the given title with the given timestamp.
static getSaveBlacklist()
doLogout()
Clear the user's session, and reset the instance cache.
integer $queryFlagsUsed
User::READ_* constant bitfield used to load data.
loadFromCache()
Load user data from shared cache, given mId has already been set.
isEmailConfirmationPending()
Check whether there is an outstanding request for e-mail confirmation.
const GAID_FOR_UPDATE
Used to be GAID_FOR_UPDATE define.
incEditCount()
Deferred version of incEditCountImmediate()
newTouchedTimestamp()
Generate a current or new-future timestamp to be stored in the user_touched field when we update thin...
setTarget($target)
Set the target for this block, and update $this->type accordingly.
getOptionKinds(IContextSource $context, $options=null)
Return an associative array mapping preferences keys to the kind of a preference they're used for...
static isIPv4($ip)
Given a string, determine if it as valid IP in IPv4 only.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
static newSystemUser($name, $options=[])
Static factory method for creation of a "system" user from username.
string $mTouched
TS_MW timestamp from the DB.
clearCookie($name, $secure=null, $params=[])
Clear a cookie on the user's client.
canSendEmail()
Is this user allowed to send e-mails within limits of current site configuration? ...
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 whether this was an auto creation 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 unsetoffset-wrap String Wrap the message in html(usually something like"<
string $mEmailAuthenticated
Cache variables.
and(b) You must cause any modified files to carry prominent notices stating that You changed the files
wfDeprecated($function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
static makeTitleSafe($ns, $title, $fragment= '', $interwiki= '')
Create a new Title from a namespace index and a DB key.
static isIP($name)
Does the string match an anonymous IPv4 address?
getBlockedStatus($bFromSlave=true)
Get blocking information.
static getGroupPage($group)
Get the title of a page describing a particular group.
getPasswordValidity($password)
Given unvalidated password input, return error message on failure.
namespace and then decline to actually register it file or subcat img or subcat $title
requiresHTTPS()
Determine based on the wiki configuration and the user's options, whether this user must be over HTTP...
static $mAllRights
String Cached results of getAllRights()
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
static getDBOptions($bitfield)
Get an appropriate DB index and options for a query.
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
spreadBlock()
If this (non-anonymous) user is blocked, block the IP address they've successfully logged in from...
static newFromUser(User $user)
Create a new MailAddress object for the given user.
$wgClockSkewFudge
Clock skew or the one-second resolution of time() can occasionally cause cache problems when the user...
$wgEnableUserEmail
Set to true to enable user-to-user e-mail.
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
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
getTokenUrl($page, $token)
Internal function to format the e-mail validation/invalidation URLs.
setInternalPassword($str)
Set the password and reset the random token unconditionally.
static getCacheSetOptions(IDatabase $db1)
Merge the result of getSessionLagStatus() for several DBs using the most pessimistic values to estima...
namespace and then decline to actually register it & $namespaces
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
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
loadFromDatabase($flags=self::READ_LATEST)
Load user and user_group data from the database.
string $mToken
Cache variables.
isWatched($title, $checkRights=self::CHECK_USER_RIGHTS)
Check the watched status of an article.
static newInvalidPassword()
Create an InvalidPassword.
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 local account $user
static link($target, $html=null, $customAttribs=[], $query=[], $options=[])
This function returns an HTML link to the given target.
static normalizeKey($key)
Normalize a skin preference value to a form that can be loaded.
useRCPatrol()
Check whether to enable recent changes patrol features for this user.
$wgPasswordSender
Sender email address for e-mail notifications.
isBlocked($bFromSlave=true)
Check if user is blocked.
getOption($oname, $defaultOverride=null, $ignoreHidden=false)
Get the user's current setting for a given option.
static getGroupName($group)
Get the localized descriptive name for a group, if it exists.
$wgEmailAuthentication
Require email authentication before sending mail to an email address.
$mNewtalk
Lazy-initialized variables, invalidated with clearInstanceCache.
invalidateEmail()
Invalidate the user's e-mail confirmation, and unauthenticate the e-mail address if it was already co...
loadGroups()
Load the groups from the database if they aren't already loaded.
saveOptions()
Saves the non-default options for this user, as previously set e.g.
idForName($flags=0)
If only this user's username is known, and it exists, return the user ID.
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
static passwordChangeInputAttribs()
Provide an array of HTML5 attributes to put on an input element intended for the user to enter a new ...
static newFromId($id, $flags=0)
Load a page revision from a given revision ID number.
setId($v)
Set the user and reload all fields according to a given ID.
getStubThreshold()
Get the user preferred stub threshold.
getRequest()
Get the WebRequest object to use with this object.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
string $mEmail
Cache variables.
setExtendedLoginCookie($name, $value, $secure)
Set an extended login cookie on the user's client.
static getBlocksForIPList(array $ipChain, $isAnon, $fromMaster=false)
Get all blocks that match any IP from an array of IP addresses.
this hook is for auditing only $req
getNewtalk()
Check if the user has new messages.
this hook is for auditing only or null if authentication failed before getting that far $username
static newFromConfirmationCode($code, $flags=0)
Factory method to fetch whichever user has a given email confirmation code.
loadFromRow($row, $data=null)
Initialize this object from a row from the user table.
getGroups()
Get the list of explicit group memberships this user has.
__construct()
Lightweight constructor for an anonymous user.
static getGroupMember($group, $username= '#')
Get the localized descriptive name for a member of a group, if it exists.
array $mGroups
Cache variables.
confirmationTokenUrl($token)
Return a URL the user can use to confirm their email address.
Class for creating log entries manually, to inject them into the database.
error also a ContextSource you ll probably need to make sure the header is varied on $request
removeGroup($group)
Remove the user from the given group.
prevents($action, $x=null)
Get/set whether the Block prevents a given action.
static hasFlags($bitfield, $flags)
The ContentHandler facility adds support for arbitrary content types on wiki pages
spreadAnyEditBlock()
If this user is logged-in and blocked, block any IP address they've successfully logged in from...
useFilePatrol()
Check whether to enable new files patrol features for this user.
static hmac($data, $key, $raw=true)
Generate an acceptably unstable one-way-hmac of some text making use of the best hash algorithm that ...
getEffectiveGroups($recache=false)
Get the list of implicit group memberships this user has.
getId()
Get the user's ID.
getEmailAuthenticationTimestamp()
Get the timestamp of the user's e-mail authentication.
addToDatabase()
Add this existing user object to the database.
invalidateCache()
Immediately touch the user data cache for this account.
getTokenFromOption($oname)
Get a token stored in the preferences (like the watchlist one), resetting it if it's empty (and savin...
removeWatch($title, $checkRights=self::CHECK_USER_RIGHTS)
Stop watching an article.
$wgDefaultSkin
Default skin, for new users and anonymous visitors.
confirmEmail()
Mark the e-mail address confirmed.
getGlobalBlock($ip= '')
Check if user is blocked on all wikis.
static generateHex($chars, $forceStrong=false)
Generate a run of (ideally) cryptographically random data and return it in hexadecimal string format...
setEmail($str)
Set the user's e-mail address.
initEditCount($add=0)
Initialize user_editcount from data out of the revision table.
static getPasswordFactory()
Lazily instantiate and return a factory object for making passwords.
static isCreatableName($name)
Usernames which fail to pass this function will be blocked from new account registrations, but may be used internally either by batch processes or by user accounts which have already been created.
static newFromSession(WebRequest $request=null)
Create a new user object using data from session.
getEditCount()
Get the user's edit count.
getUserPage()
Get this user's personal page title.
getInstanceForUpdate()
Get a new instance of this user that was loaded from the master via a locking read.
static idFromName($name, $flags=self::READ_NORMAL)
Get database id given a user name.
useNPPatrol()
Check whether to enable new pages patrol features for this user.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers if desired whether it is OK to use $contentModel on $title Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok inclusive $limit
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 local content language as $wgContLang
Interface for database access objects.
setCookies($request=null, $secure=null, $rememberMe=false)
Persist this user's session (e.g.
getDatePreference()
Get the user's preferred date format.
getBlockId()
If user is blocked, return the ID for the block.
getNewMessageRevisionId()
Get the revision ID for the last talk page revision viewed by the talk page owner.
$mFrom
String Initialization data source if mLoadedItems!==true.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
static consume(ScopedCallback &$sc=null)
Trigger a scoped callback and destroy it.
getEditToken($salt= '', $request=null)
Initialize (if necessary) and return a session token value which can be used in edit forms to show th...
static newFatalPermissionDeniedStatus($permission)
Factory function for fatal permission-denied errors.
getEditTokenObject($salt= '', $request=null)
Initialize (if necessary) and return a session token value which can be used in edit forms to show th...
isLocked()
Check if user account is locked.
wfMemcKey()
Make a cache key for the local wiki.
static validateEmail($addr)
Does a string look like an e-mail address?
canReceiveEmail()
Is this user allowed to receive e-mails within limits of current site configuration?
equals(User $user)
Checks if two user objects point to the same user.
loadFromId($flags=self::READ_NORMAL)
Load user table data, given mId has already been set.
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
setRealName($str)
Set the user's real name.
addWatch($title, $checkRights=self::CHECK_USER_RIGHTS)
Watch an article.
array $mOptionOverrides
Cache variables.
checkTemporaryPassword($plaintext)
Check if the given clear-text password matches the temporary password sent by e-mail for password res...
static logException($e)
Log an exception to the exception log (if enabled).
static getDefaultOptions()
Combine the language default options with any site-specific options and add the default language vari...
const INVALID_TOKEN
string An invalid value for user_token
setItemLoaded($item)
Set that an item has been loaded.
wfTimestampOrNull($outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
static getDefaultOption($opt)
Get a given default option value.
string $mRealName
Cache variables.
isSafeToLoad()
Test if it's safe to load this User object.
static getSubnet($ip)
Returns the subnet of a given IP.
getCacheKey(WANObjectCache $cache)
static getGroupPermissions($groups)
Get the permissions associated with a given list of groups.
static array $languagesWithVariants
languages supporting variants
getTalkPage()
Get this user's talk page title.
getToken($forceCreation=true)
Get the user's current token.
const EDIT_TOKEN_SUFFIX
Global constant made accessible as class constants so that autoloader magic can be used...
isPingLimitable()
Is this user subject to rate limiting?
static getRightDescription($right)
Get the description of a given right.
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 before the output is cached one of or reset my talk page
if(is_null($wgLocalTZoffset)) if(!$wgDBerrorLogTZ) $wgRequest
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 before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
if($wgRCFilterByAge) $wgDefaultUserOptions['rcdays']
static $mCacheVars
Array of Strings List of member variables which are saved to the shared cache (memcached).
static & makeTitle($ns, $title, $fragment= '', $interwiki= '')
Create a new Title from a namespace index and a DB key.
static getGroupsWithPermission($role)
Get all the groups who have a given permission.
static newGood($value=null)
Factory function for good results.
getRights()
Get the permissions this user has.
getFormerGroups()
Returns the groups the user has belonged to.
blockedFor()
If user is blocked, return the specified reason for the block.
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 before the output is cached $page
setPasswordInternal($str)
Actually set the password and such.
incEditCountImmediate()
Increment the user's edit-count field.
addGroup($group)
Add the user to the given group.
confirmationToken(&$expiration)
Generate, store, and return a new e-mail confirmation code.
getTouched()
Get the user touched timestamp.
$mLoadedItems
Array with already loaded items or true if all items have been loaded.
Allows to change the fields on the form that will be generated $name