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',
328 return (
string)$this->
getName();
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 foreach ( self::$mCacheVars
as $var ) {
1359 $this->$var =
$user->$var;
1367 if ( is_null( $this->mGroups ) ) {
1368 $db = ( $this->queryFlagsUsed & self::READ_LATEST )
1371 $res = $db->select(
'user_groups',
1373 [
'ug_user' => $this->mId ],
1375 $this->mGroups = [];
1376 foreach (
$res as $row ) {
1377 $this->mGroups[] = $row->ug_group;
1397 global $wgAutopromoteOnceLogInRC;
1404 if ( !count( $toPromote ) ) {
1413 foreach ( $toPromote
as $group ) {
1417 Hooks::run(
'UserGroupsChanged', [ $this, $toPromote, [],
false,
false ] );
1418 AuthManager::callLegacyAuthPlugin(
'updateExternalDBGroups', [ $this, $toPromote ] );
1420 $newGroups = array_merge( $oldGroups, $toPromote );
1423 $logEntry->setPerformer( $this );
1425 $logEntry->setParameters( [
1426 '4::oldgroups' => $oldGroups,
1427 '5::newgroups' => $newGroups,
1429 $logid = $logEntry->insert();
1430 if ( $wgAutopromoteOnceLogInRC ) {
1431 $logEntry->publish( $logid );
1449 if ( !$this->mId ) {
1458 $dbw->update(
'user',
1459 [
'user_touched' => $dbw->timestamp( $newTouched ) ],
1462 'user_touched' => $dbw->timestamp( $oldTouched )
1466 $success = ( $dbw->affectedRows() > 0 );
1469 $this->mTouched = $newTouched;
1487 $this->mNewtalk = -1;
1488 $this->mDatePreference = null;
1489 $this->mBlockedby = -1; # Unset
1490 $this->mHash =
false;
1491 $this->mRights = null;
1492 $this->mEffectiveGroups = null;
1493 $this->mImplicitGroups = null;
1494 $this->mGroups = null;
1495 $this->mOptions = null;
1496 $this->mOptionsLoaded =
false;
1497 $this->mEditCount = null;
1499 if ( $reloadFrom ) {
1500 $this->mLoadedItems = [];
1501 $this->mFrom = $reloadFrom;
1514 static $defOpt = null;
1515 if ( !defined(
'MW_PHPUNIT_TEST' ) && $defOpt !== null ) {
1524 $defOpt[
'language'] = $wgContLang->getCode();
1526 $defOpt[$langCode == $wgContLang->getCode() ?
'variant' :
"variant-$langCode"] = $langCode;
1528 $namespaces = MediaWikiServices::getInstance()->getSearchEngineConfig()->searchableNamespaces();
1530 $defOpt[
'searchNs' . $nsnum] = !empty( $wgNamespacesToBeSearchedDefault[$nsnum] );
1534 Hooks::run(
'UserGetDefaultOptions', [ &$defOpt ] );
1546 $defOpts = self::getDefaultOptions();
1547 if ( isset( $defOpts[$opt] ) ) {
1548 return $defOpts[$opt];
1563 if ( -1 != $this->mBlockedby ) {
1567 wfDebug( __METHOD__ .
": checking...\n" );
1576 # We only need to worry about passing the IP address to the Block generator if the
1577 # user is not immune to autoblocks/hardblocks, and they are the current user so we
1578 # know which IP address they're actually coming from
1580 if ( !$this->
isAllowed(
'ipblock-exempt' ) ) {
1583 $globalUserName = $wgUser->isSafeToLoad()
1584 ? $wgUser->getName()
1586 if ( $this->
getName() === $globalUserName ) {
1595 if ( !$block instanceof
Block && $ip !== null && !in_array( $ip, $wgProxyWhitelist ) ) {
1597 if ( self::isLocallyBlockedProxy( $ip ) ) {
1600 $block->mReason =
wfMessage(
'proxyblockreason' )->text();
1601 $block->setTarget( $ip );
1605 $block->mReason =
wfMessage(
'sorbsreason' )->text();
1606 $block->setTarget( $ip );
1611 if ( !$block instanceof
Block
1612 && $wgApplyIpBlocksToXff
1614 && !in_array( $ip, $wgProxyWhitelist )
1616 $xff = $this->
getRequest()->getHeader(
'X-Forwarded-For' );
1617 $xff = array_map(
'trim', explode(
',', $xff ) );
1618 $xff = array_diff( $xff, [ $ip ] );
1621 if ( $block instanceof
Block ) {
1622 # Mangle the reason to alert the user that the block
1623 # originated from matching the X-Forwarded-For header.
1624 $block->mReason =
wfMessage(
'xffblockreason', $block->mReason )->text();
1628 if ( $block instanceof
Block ) {
1629 wfDebug( __METHOD__ .
": Found block.\n" );
1630 $this->mBlock = $block;
1631 $this->mBlockedby = $block->getByName();
1632 $this->mBlockreason = $block->mReason;
1633 $this->mHideName = $block->mHideName;
1634 $this->mAllowUsertalk = !$block->prevents(
'editownusertalk' );
1636 $this->mBlockedby =
'';
1637 $this->mHideName = 0;
1638 $this->mAllowUsertalk =
false;
1655 global $wgEnableDnsBlacklist, $wgDnsBlacklistUrls, $wgProxyWhitelist;
1657 if ( !$wgEnableDnsBlacklist ) {
1661 if ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) ) {
1681 $ipReversed = implode(
'.', array_reverse( explode(
'.', $ip ) ) );
1687 if ( is_array( $base ) ) {
1688 if ( count( $base ) >= 2 ) {
1690 $host =
"{$base[1]}.$ipReversed.{$base[0]}";
1692 $host =
"$ipReversed.{$base[0]}";
1694 $basename = $base[0];
1696 $host =
"$ipReversed.$base";
1700 $ipList = gethostbynamel( $host );
1703 wfDebugLog(
'dnsblacklist',
"Hostname $host is {$ipList[0]}, it's a proxy says $basename!" );
1707 wfDebugLog(
'dnsblacklist',
"Requested $host, not found in $basename." );
1725 if ( !$wgProxyList ) {
1729 if ( !is_array( $wgProxyList ) ) {
1731 $wgProxyList = array_map(
'trim',
file( $wgProxyList ) );
1734 if ( !is_array( $wgProxyList ) ) {
1736 } elseif ( array_search( $ip, $wgProxyList ) !==
false ) {
1738 } elseif ( array_key_exists( $ip, $wgProxyList ) ) {
1753 global $wgRateLimitsExcludedIPs;
1754 if ( in_array( $this->
getRequest()->getIP(), $wgRateLimitsExcludedIPs ) ) {
1760 return !$this->
isAllowed(
'noratelimit' );
1787 if ( !isset( $wgRateLimits[$action] ) ) {
1796 $limits = $wgRateLimits[$action];
1798 $id = $this->
getId();
1804 if ( isset( $limits[
'anon'] ) ) {
1805 $keys[
wfMemcKey(
'limiter', $action,
'anon' )] = $limits[
'anon'];
1809 if ( isset( $limits[
'user'] ) ) {
1810 $userLimit = $limits[
'user'];
1813 if ( $isNewbie && isset( $limits[
'newbie'] ) ) {
1814 $keys[
wfMemcKey(
'limiter', $action,
'user', $id )] = $limits[
'newbie'];
1821 if ( isset( $limits[
'ip'] ) ) {
1823 $keys[
"mediawiki:limiter:$action:ip:$ip"] = $limits[
'ip'];
1826 if ( isset( $limits[
'subnet'] ) ) {
1829 if ( $subnet !==
false ) {
1830 $keys[
"mediawiki:limiter:$action:subnet:$subnet"] = $limits[
'subnet'];
1838 if ( isset( $limits[$group] ) ) {
1839 if ( $userLimit ===
false
1840 || $limits[$group][0] / $limits[$group][1] > $userLimit[0] / $userLimit[1]
1842 $userLimit = $limits[$group];
1848 if ( $userLimit !==
false ) {
1849 list( $max, $period ) = $userLimit;
1850 wfDebug( __METHOD__ .
": effective user limit: $max in {$period}s\n" );
1851 $keys[
wfMemcKey(
'limiter', $action,
'user', $id )] = $userLimit;
1855 if ( isset( $limits[
'ip-all'] ) ) {
1858 if ( $isNewbie || $userLimit ===
false
1859 || $limits[
'ip-all'][0] / $limits[
'ip-all'][1] > $userLimit[0] / $userLimit[1] ) {
1860 $keys[
"mediawiki:limiter:$action:ip-all:$ip"] = $limits[
'ip-all'];
1865 if ( isset( $limits[
'subnet-all'] ) ) {
1868 if ( $subnet !==
false ) {
1870 if ( $isNewbie || $userLimit ===
false
1871 || $limits[
'ip-all'][0] / $limits[
'ip-all'][1]
1872 > $userLimit[0] / $userLimit[1] ) {
1873 $keys[
"mediawiki:limiter:$action:subnet-all:$subnet"] = $limits[
'subnet-all'];
1883 $summary =
"(limit $max in {$period}s)";
1888 wfDebugLog(
'ratelimit',
"User '{$this->getName()}' " .
1889 "(IP {$this->getRequest()->getIP()}) tripped $key at $count $summary" );
1892 wfDebug( __METHOD__ .
": ok. $key at $count $summary\n" );
1895 wfDebug( __METHOD__ .
": adding record for $key $summary\n" );
1927 return $this->mBlock instanceof
Block ? $this->mBlock : null;
1938 global $wgBlockAllowsUTEdit;
1940 $blocked = $this->
isBlocked( $bFromSlave );
1941 $allowUsertalk = ( $wgBlockAllowsUTEdit ? $this->mAllowUsertalk :
false );
1943 if ( !$this->mHideName && $allowUsertalk &&
$title->getText() === $this->
getName()
1946 wfDebug( __METHOD__ .
": self-talk page, ignoring any blocks\n" );
1949 Hooks::run(
'UserIsBlockedFrom', [ $this,
$title, &$blocked, &$allowUsertalk ] );
1978 return ( $this->mBlock ? $this->mBlock->getId() :
false );
2004 if ( $this->mGlobalBlock !== null ) {
2005 return $this->mGlobalBlock ?: null;
2017 Hooks::run(
'UserIsBlockedGlobally', [ &
$user, $ip, &$blocked, &$block ] );
2019 if ( $blocked && $block === null ) {
2025 $this->mGlobalBlock = $blocked ? $block :
false;
2026 return $this->mGlobalBlock ?: null;
2035 if ( $this->mLocked !== null ) {
2040 $authUser = AuthManager::callLegacyAuthPlugin(
'getUserInstance', [ &
$user ], null );
2041 $this->mLocked = $authUser && $authUser->isLocked();
2042 Hooks::run(
'UserIsLocked', [ $this, &$this->mLocked ] );
2052 if ( $this->mHideName !== null ) {
2056 if ( !$this->mHideName ) {
2059 $authUser = AuthManager::callLegacyAuthPlugin(
'getUserInstance', [ &
$user ], null );
2060 $this->mHideName = $authUser && $authUser->isHidden();
2061 Hooks::run(
'UserIsHidden', [ $this, &$this->mHideName ] );
2071 if ( $this->mId === null && $this->mName !== null &&
User::isIP( $this->mName ) ) {
2101 if ( $this->mName ===
false ) {
2124 $this->mName = $str;
2132 return str_replace(
' ',
'_', $this->
getName() );
2143 if ( $this->mNewtalk === -1 ) {
2144 $this->mNewtalk =
false; # reset talk
page status
2148 if ( !$this->mId ) {
2149 global $wgDisableAnonTalk;
2150 if ( $wgDisableAnonTalk ) {
2152 $this->mNewtalk =
false;
2157 $this->mNewtalk = $this->
checkNewtalk(
'user_id', $this->mId );
2190 'MIN(user_last_timestamp)',
2191 $this->
isAnon() ? [
'user_ip' => $this->
getName() ] : [
'user_id' => $this->
getId() ],
2194 return [ [
'wiki' =>
wfWikiID(),
'link' => $utp->getLocalURL(),
'rev' =>
$rev ] ];
2203 $newMessageRevisionId = null;
2205 if ( $newMessageLinks ) {
2209 if ( count( $newMessageLinks ) === 1
2210 && $newMessageLinks[0][
'wiki'] ===
wfWikiID()
2211 && $newMessageLinks[0][
'rev']
2214 $newMessageRevision = $newMessageLinks[0][
'rev'];
2215 $newMessageRevisionId = $newMessageRevision->getId();
2218 return $newMessageRevisionId;
2232 $ok =
$dbr->selectField(
'user_newtalk', $field, [ $field => $id ], __METHOD__ );
2234 return $ok !==
false;
2246 $prevRev = $curRev ? $curRev->getPrevious() :
false;
2247 $ts = $prevRev ? $prevRev->getTimestamp() : null;
2250 $dbw->insert(
'user_newtalk',
2251 [ $field => $id,
'user_last_timestamp' => $dbw->timestampOrNull( $ts ) ],
2254 if ( $dbw->affectedRows() ) {
2255 wfDebug( __METHOD__ .
": set on ($field, $id)\n" );
2258 wfDebug( __METHOD__ .
" already set ($field, $id)\n" );
2271 $dbw->delete(
'user_newtalk',
2274 if ( $dbw->affectedRows() ) {
2275 wfDebug( __METHOD__ .
": killed on ($field, $id)\n" );
2278 wfDebug( __METHOD__ .
": already gone ($field, $id)\n" );
2295 $this->mNewtalk = $val;
2302 $id = $this->
getId();
2325 if ( $this->mTouched && $time <= $this->mTouched ) {
2343 if ( !$this->
getId() ) {
2348 $processCache = self::getInProcessCache();
2350 if ( $mode ===
'refresh' ) {
2352 $processCache->delete(
$key );
2357 $processCache->delete(
$key );
2386 $id = $this->
getId();
2390 $this->mQuickTouched = null;
2415 if ( $this->mQuickTouched === null ) {
2422 return max( $this->mTouched, $this->mQuickTouched );
2445 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2454 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2498 $manager = AuthManager::singleton();
2501 if ( !$manager->userExists( $this->getName() ) ) {
2502 throw new LogicException(
'Cannot set a password for a user that is not in the database.' );
2506 'username' => $this->
getName(),
2512 ->info( __METHOD__ .
': Password change rejected: '
2513 .
$status->getWikiText( null, null,
'en' ) );
2517 $this->
setOption(
'watchlisttoken',
false );
2518 SessionManager::singleton()->invalidateSessionsForUser( $this );
2536 $manager = AuthManager::singleton();
2537 $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
2538 $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
2541 foreach ( $reqs
as $req ) {
2542 $status->merge( $manager->allowsAuthenticationDataChange( $req ),
true );
2544 if (
$status->getValue() ===
'ignored' ) {
2545 $status->warning(
'authenticationdatachange-ignored' );
2549 foreach ( $reqs
as $req ) {
2550 $manager->changeAuthenticationData( $req );
2563 global $wgAuthenticationTokenVersion;
2566 if ( !$this->mToken && $forceCreation ) {
2570 if ( !$this->mToken ) {
2573 } elseif ( $this->mToken === self::INVALID_TOKEN ) {
2577 } elseif ( $wgAuthenticationTokenVersion === null ) {
2585 $len = max( 32, self::TOKEN_LENGTH );
2586 if ( strlen(
$ret ) < $len ) {
2588 throw new \UnexpectedValueException(
'Hmac returned less than 128 bits' );
2590 return substr(
$ret, -$len );
2602 if ( $this->mToken === self::INVALID_TOKEN ) {
2604 ->debug( __METHOD__ .
": Ignoring attempt to set token for system user \"$this\"" );
2605 } elseif ( !$token ) {
2608 $this->mToken = $token;
2621 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2631 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2640 Hooks::run(
'UserGetEmail', [ $this, &$this->mEmail ] );
2650 Hooks::run(
'UserGetEmailAuthenticationTimestamp', [ $this, &$this->mEmailAuthenticated ] );
2660 if ( $str == $this->mEmail ) {
2664 $this->mEmail = $str;
2665 Hooks::run(
'UserSetEmail', [ $this, &$this->mEmail ] );
2678 if ( !$wgEnableEmail ) {
2683 if ( $str === $oldaddr ) {
2687 $type = $oldaddr !=
'' ?
'changed' :
'set';
2688 $notificationResult = null;
2690 if ( $wgEmailAuthentication ) {
2693 if (
$type ==
'changed' ) {
2694 $change = $str !=
'' ?
'changed' :
'removed';
2695 $notificationResult = $this->
sendMail(
2696 wfMessage(
'notificationemail_subject_' . $change )->
text(),
2697 wfMessage(
'notificationemail_body_' . $change,
2707 if ( $str !==
'' && $wgEmailAuthentication ) {
2711 if ( $notificationResult !== null ) {
2712 $result->merge( $notificationResult );
2744 $this->mRealName = $str;
2757 public function getOption( $oname, $defaultOverride = null, $ignoreHidden =
false ) {
2761 # We want 'disabled' preferences to always behave as the default value for
2762 # users, even if they have set the option explicitly in their settings (ie they
2763 # set it, and then it was disabled removing their ability to change it). But
2764 # we don't want to erase the preferences in the database in case the preference
2765 # is re-enabled again. So don't touch $mOptions, just override the returned value
2766 if ( !$ignoreHidden && in_array( $oname, $wgHiddenPrefs ) ) {
2767 return self::getDefaultOption( $oname );
2770 if ( array_key_exists( $oname, $this->mOptions ) ) {
2771 return $this->mOptions[$oname];
2773 return $defaultOverride;
2790 # We want 'disabled' preferences to always behave as the default value for
2791 # users, even if they have set the option explicitly in their settings (ie they
2792 # set it, and then it was disabled removing their ability to change it). But
2793 # we don't want to erase the preferences in the database in case the preference
2794 # is re-enabled again. So don't touch $mOptions, just override the returned value
2795 foreach ( $wgHiddenPrefs
as $pref ) {
2796 $default = self::getDefaultOption( $pref );
2797 if ( $default !== null ) {
2802 if (
$flags & self::GETOPTIONS_EXCLUDE_DEFAULTS ) {
2817 return (
bool)$this->
getOption( $oname );
2831 $val = $defaultOverride;
2833 return intval( $val );
2848 if ( is_null( $val ) ) {
2849 $val = self::getDefaultOption( $oname );
2852 $this->mOptions[$oname] = $val;
2868 $id = $this->
getId();
2869 if ( !$id || in_array( $oname, $wgHiddenPrefs ) ) {
2878 $token = hash_hmac(
'sha1',
"$oname:$id", $this->
getToken() );
2895 if ( in_array( $oname, $wgHiddenPrefs ) ) {
2930 'registered-multiselect',
2931 'registered-checkmatrix',
2963 unset( $prefs[
$name] );
2968 $multiselectOptions = [];
2969 foreach ( $prefs
as $name => $info ) {
2970 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'multiselect' ) ||
2971 ( isset( $info[
'class'] ) && $info[
'class'] ==
'HTMLMultiSelectField' ) ) {
2973 $prefix = isset( $info[
'prefix'] ) ? $info[
'prefix'] :
$name;
2976 $multiselectOptions[
"$prefix$value"] =
true;
2979 unset( $prefs[
$name] );
2982 $checkmatrixOptions = [];
2983 foreach ( $prefs
as $name => $info ) {
2984 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'checkmatrix' ) ||
2985 ( isset( $info[
'class'] ) && $info[
'class'] ==
'HTMLCheckMatrix' ) ) {
2988 $prefix = isset( $info[
'prefix'] ) ? $info[
'prefix'] :
$name;
2990 foreach ( $columns
as $column ) {
2991 foreach ( $rows
as $row ) {
2992 $checkmatrixOptions[
"$prefix$column-$row"] =
true;
2996 unset( $prefs[
$name] );
3002 if ( isset( $prefs[
$key] ) ) {
3003 $mapping[
$key] =
'registered';
3004 } elseif ( isset( $multiselectOptions[$key] ) ) {
3005 $mapping[
$key] =
'registered-multiselect';
3006 } elseif ( isset( $checkmatrixOptions[$key] ) ) {
3007 $mapping[
$key] =
'registered-checkmatrix';
3008 } elseif ( isset( $specialOptions[$key] ) ) {
3009 $mapping[
$key] =
'special';
3010 } elseif ( substr( $key, 0, 7 ) ===
'userjs-' ) {
3011 $mapping[
$key] =
'userjs';
3013 $mapping[
$key] =
'unused';
3035 $resetKinds = [
'registered',
'registered-multiselect',
'registered-checkmatrix',
'unused' ],
3039 $defaultOptions = self::getDefaultOptions();
3041 if ( !is_array( $resetKinds ) ) {
3042 $resetKinds = [ $resetKinds ];
3045 if ( in_array(
'all', $resetKinds ) ) {
3046 $newOptions = $defaultOptions;
3053 $resetKinds = array_intersect( $resetKinds, self::listOptionKinds() );
3059 if ( in_array( $optionKinds[
$key], $resetKinds ) ) {
3060 if ( array_key_exists( $key, $defaultOptions ) ) {
3061 $newOptions[
$key] = $defaultOptions[
$key];
3069 Hooks::run(
'UserResetAllOptions', [ $this, &$newOptions, $this->mOptions, $resetKinds ] );
3071 $this->mOptions = $newOptions;
3072 $this->mOptionsLoaded =
true;
3081 if ( is_null( $this->mDatePreference ) ) {
3084 $map = $wgLang->getDatePreferenceMigrationMap();
3085 if ( isset( $map[
$value] ) ) {
3088 $this->mDatePreference =
$value;
3101 if ( !$wgSecureLogin ) {
3105 Hooks::run(
'UserRequiresHTTPS', [ $this, &$https ] );
3121 if ( $threshold > $wgMaxArticleSize * 1024 ) {
3134 if ( is_null( $this->mRights ) ) {
3136 Hooks::run(
'UserGetRights', [ $this, &$this->mRights ] );
3140 if ( !defined(
'MW_NO_SESSION' ) ) {
3141 $allowedRights = $this->
getRequest()->getSession()->getAllowedUserRights();
3142 if ( $allowedRights !== null ) {
3143 $this->mRights = array_intersect( $this->mRights, $allowedRights );
3148 $this->mRights = array_values( array_unique( $this->mRights ) );
3159 $config->get(
'BlockDisablesLogin' ) &&
3163 $this->mRights = array_intersect( $this->mRights, $anon->getRights() );
3188 if ( $recache || is_null( $this->mEffectiveGroups ) ) {
3189 $this->mEffectiveGroups = array_unique( array_merge(
3196 Hooks::run(
'UserEffectiveGroups', [ &
$user, &$this->mEffectiveGroups ] );
3198 $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
3211 if ( $recache || is_null( $this->mImplicitGroups ) ) {
3212 $this->mImplicitGroups = [
'*' ];
3213 if ( $this->
getId() ) {
3214 $this->mImplicitGroups[] =
'user';
3216 $this->mImplicitGroups = array_unique( array_merge(
3217 $this->mImplicitGroups,
3224 $this->mEffectiveGroups = null;
3242 if ( is_null( $this->mFormerGroups ) ) {
3243 $db = ( $this->queryFlagsUsed & self::READ_LATEST )
3246 $res = $db->select(
'user_former_groups',
3248 [
'ufg_user' => $this->mId ],
3250 $this->mFormerGroups = [];
3251 foreach (
$res as $row ) {
3252 $this->mFormerGroups[] = $row->ufg_group;
3264 if ( !$this->
getId() ) {
3268 if ( $this->mEditCount === null ) {
3273 'user',
'user_editcount',
3274 [
'user_id' => $this->mId ],
3282 $this->mEditCount =
$count;
3296 if ( !
Hooks::run(
'UserAddGroup', [ $this, &$group ] ) ) {
3301 if ( $this->
getId() ) {
3302 $dbw->insert(
'user_groups',
3304 'ug_user' => $this->
getId(),
3305 'ug_group' => $group,
3312 $this->mGroups[] = $group;
3315 $this->mGroups = array_unique( $this->mGroups );
3320 $this->mRights = null;
3335 if ( !
Hooks::run(
'UserRemoveGroup', [ $this, &$group ] ) ) {
3340 $dbw->delete(
'user_groups',
3342 'ug_user' => $this->
getId(),
3343 'ug_group' => $group,
3347 $dbw->insert(
'user_former_groups',
3349 'ufg_user' => $this->
getId(),
3350 'ufg_group' => $group,
3357 $this->mGroups = array_diff( $this->mGroups, [ $group ] );
3362 $this->mRights = null;
3374 return $this->
getId() != 0;
3392 $permissions = func_get_args();
3393 foreach ( $permissions
as $permission ) {
3394 if ( $this->
isAllowed( $permission ) ) {
3407 $permissions = func_get_args();
3408 foreach ( $permissions
as $permission ) {
3409 if ( !$this->
isAllowed( $permission ) ) {
3422 if ( $action ===
'' ) {
3427 return in_array( $action, $this->
getRights(),
true );
3436 return $wgUseRCPatrol && $this->
isAllowedAny(
'patrol',
'patrolmarks' );
3444 global $wgUseRCPatrol, $wgUseNPPatrol;
3446 ( $wgUseRCPatrol || $wgUseNPPatrol )
3456 global $wgUseRCPatrol, $wgUseFilePatrol;
3458 ( $wgUseRCPatrol || $wgUseFilePatrol )
3469 if ( $this->mRequest ) {
3486 if (
$title->isWatchable() && ( !$checkRights || $this->
isAllowed(
'viewmywatchlist' ) ) ) {
3500 if ( !$checkRights || $this->
isAllowed(
'editmywatchlist' ) ) {
3517 if ( !$checkRights || $this->
isAllowed(
'editmywatchlist' ) ) {
3541 if ( !$this->
isAllowed(
'editmywatchlist' ) ) {
3549 if ( !
Hooks::run(
'UserClearNewTalkNotification', [ &
$user, $oldid ] ) ) {
3572 if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3591 ->resetNotificationTimestamp( $this,
$title, $force, $oldid );
3606 if ( !$this->
isAllowed(
'editmywatchlist' ) ) {
3611 if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3615 $id = $this->
getId();
3618 $dbw->update(
'watchlist',
3619 [
'wl_notificationtimestamp' => null ],
3620 [
'wl_user' => $id,
'wl_notificationtimestamp IS NOT NULL' ],
3686 global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
3691 $exp += $wgExtendedLoginCookieExpiration !== null
3692 ? $wgExtendedLoginCookieExpiration
3693 : $wgCookieExpiration;
3708 if ( 0 == $this->mId ) {
3712 $session = $this->
getRequest()->getSession();
3714 $session = $session->sessionWithRequest(
$request );
3716 $delay = $session->delaySave();
3718 if ( !$session->getUser()->equals( $this ) ) {
3719 if ( !$session->canSetUser() ) {
3721 ->warning( __METHOD__ .
3722 ": Cannot save user \"$this\" to a user \"{$session->getUser()}\"'s immutable session"
3726 $session->setUser( $this );
3729 $session->setRememberUser( $rememberMe );
3730 if ( $secure !== null ) {
3731 $session->setForceHTTPS( $secure );
3734 $session->persist();
3755 $session = $this->
getRequest()->getSession();
3756 if ( !$session->canSetUser() ) {
3758 ->warning( __METHOD__ .
": Cannot log out of an immutable session" );
3759 } elseif ( !$session->getUser()->equals( $this ) ) {
3761 ->warning( __METHOD__ .
3762 ": Cannot log user \"$this\" out of a user \"{$session->getUser()}\"'s session"
3768 $delay = $session->delaySave();
3769 $session->unpersist();
3770 $session->setLoggedOutTimestamp( time() );
3771 $session->setUser(
new User );
3772 $session->set(
'wsUserID', 0 );
3773 $session->resetAllTokens();
3788 "Could not update user with ID '{$this->mId}'; DB is read-only."
3794 if ( 0 == $this->mId ) {
3805 $dbw->update(
'user',
3807 'user_name' => $this->mName,
3808 'user_real_name' => $this->mRealName,
3809 'user_email' => $this->mEmail,
3810 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3811 'user_touched' => $dbw->timestamp( $newTouched ),
3812 'user_token' => strval( $this->mToken ),
3814 'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
3817 'user_touched' => $dbw->timestamp( $oldTouched )
3821 if ( !$dbw->affectedRows() ) {
3825 $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ?
'master' :
'slave';
3827 "CAS update failed on user_touched for user ID '{$this->mId}' (read from $from);" .
3828 " the version of the user to be saved is older than the current version."
3832 $this->mTouched = $newTouched;
3852 $db = ( (
$flags & self::READ_LATEST ) == self::READ_LATEST )
3856 $options = ( (
$flags & self::READ_LOCKING ) == self::READ_LOCKING )
3857 ? [
'LOCK IN SHARE MODE' ]
3860 $id = $db->selectField(
'user',
3861 'user_id', [
'user_name' =>
$s ], __METHOD__,
$options );
3882 foreach ( [
'password',
'newpassword',
'newpass_time',
'password_expires' ]
as $field ) {
3883 if ( isset(
$params[$field] ) ) {
3884 wfDeprecated( __METHOD__ .
" with param '$field'",
'1.27' );
3892 if ( isset(
$params[
'options'] ) ) {
3897 $seqVal = $dbw->nextSequenceValue(
'user_user_id_seq' );
3902 'user_id' => $seqVal,
3903 'user_name' =>
$name,
3904 'user_password' => $noPass,
3905 'user_newpassword' => $noPass,
3906 'user_email' =>
$user->mEmail,
3907 'user_email_authenticated' => $dbw->timestampOrNull(
$user->mEmailAuthenticated ),
3908 'user_real_name' =>
$user->mRealName,
3909 'user_token' => strval(
$user->mToken ),
3910 'user_registration' => $dbw->timestamp(
$user->mRegistration ),
3911 'user_editcount' => 0,
3912 'user_touched' => $dbw->timestamp(
$user->newTouchedTimestamp() ),
3915 $fields[
"user_$name"] =
$value;
3917 $dbw->insert(
'user', $fields, __METHOD__, [
'IGNORE' ] );
3918 if ( $dbw->affectedRows() ) {
3954 if ( !$this->mToken ) {
3963 $inWrite = $dbw->writesOrCallbacksPending();
3964 $seqVal = $dbw->nextSequenceValue(
'user_user_id_seq' );
3965 $dbw->insert(
'user',
3967 'user_id' => $seqVal,
3968 'user_name' => $this->mName,
3969 'user_password' => $noPass,
3970 'user_newpassword' => $noPass,
3971 'user_email' => $this->mEmail,
3972 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3974 'user_token' => strval( $this->mToken ),
3975 'user_registration' => $dbw->timestamp( $this->mRegistration ),
3976 'user_editcount' => 0,
3977 'user_touched' => $dbw->timestamp( $this->mTouched ),
3981 if ( !$dbw->affectedRows() ) {
3987 $options = [
'LOCK IN SHARE MODE' ];
3988 $flags = self::READ_LOCKING;
3992 $dbw->commit( __METHOD__,
'flush' );
3994 $flags = self::READ_LATEST;
3996 $this->mId = $dbw->selectField(
'user',
'user_id',
3997 [
'user_name' => $this->mName ], __METHOD__,
$options );
4005 throw new MWException( __METHOD__ .
": hit a key conflict attempting " .
4006 "to insert user '{$this->mName}' row, but it was not present in select!" );
4010 $this->mId = $dbw->insertId();
4039 wfDebug( __METHOD__ .
"()\n" );
4041 if ( $this->mId == 0 ) {
4046 if ( !$userblock ) {
4050 return (
bool)$userblock->doAutoblock( $this->
getRequest()->getIP() );
4059 if ( $this->mBlock && $this->mBlock->prevents(
'createaccount' ) ) {
4063 # bug 13611: if the IP address the user is trying to create an account from is
4064 # blocked with createaccount disabled, prevent new account creation there even
4065 # when the user is logged in
4066 if ( $this->mBlockedFromCreateAccount ===
false && !$this->
isAllowed(
'ipblock-exempt' ) ) {
4069 return $this->mBlockedFromCreateAccount instanceof
Block
4070 && $this->mBlockedFromCreateAccount->
prevents(
'createaccount' )
4071 ? $this->mBlockedFromCreateAccount
4081 return $this->mBlock && $this->mBlock->prevents(
'sendemail' );
4108 return $title->getTalkPage();
4117 return !$this->
isAllowed(
'autoconfirmed' );
4127 $manager = AuthManager::singleton();
4128 $reqs = AuthenticationRequest::loadRequestsFromSubmission(
4129 $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
4131 'username' => $this->
getName(),
4132 'password' => $password,
4135 $res = AuthManager::singleton()->beginAuthentication( $reqs,
'null:' );
4136 switch ( $res->status ) {
4137 case AuthenticationResponse::PASS:
4139 case AuthenticationResponse::FAIL:
4142 ->info( __METHOD__ .
': Authentication failed: ' . $res->message->plain() );
4145 throw new BadMethodCallException(
4146 'AuthManager returned a response unsupported by ' . __METHOD__
4183 return $request->getSession()->getToken( $salt );
4239 $val = substr( $val, 0, strspn( $val,
'0123456789abcdef' ) ) . Token::SUFFIX;
4258 if (
$type ==
'created' ||
$type ===
false ) {
4259 $message =
'confirmemail_body';
4260 } elseif (
$type ===
true ) {
4261 $message =
'confirmemail_body_changed';
4264 $message =
'confirmemail_body_' .
$type;
4272 $wgLang->userTimeAndDate( $expiration, $this ),
4274 $wgLang->userDate( $expiration, $this ),
4275 $wgLang->userTime( $expiration, $this ) )->
text() );
4301 'replyTo' => $replyto,
4322 $hash = md5( $token );
4323 $this->mEmailToken = $hash;
4324 $this->mEmailTokenExpires = $expiration;
4334 return $this->
getTokenUrl(
'ConfirmEmail', $token );
4343 return $this->
getTokenUrl(
'InvalidateEmail', $token );
4363 return $title->getCanonicalURL();
4378 Hooks::run(
'ConfirmEmailComplete', [ $this ] );
4392 $this->mEmailToken = null;
4393 $this->mEmailTokenExpires = null;
4396 Hooks::run(
'InvalidateEmailComplete', [ $this ] );
4407 Hooks::run(
'UserSetEmailAuthenticationTimestamp', [ $this, &$this->mEmailAuthenticated ] );
4417 if ( !$wgEnableEmail || !$wgEnableUserEmail || !$this->
isAllowed(
'sendemail' ) ) {
4474 return $wgEmailAuthentication &&
4476 $this->mEmailToken &&
4502 if ( $this->
getId() == 0 ) {
4506 $time =
$dbr->selectField(
'revision',
'rev_timestamp',
4507 [
'rev_user' => $this->
getId() ],
4509 [
'ORDER BY' =>
'rev_timestamp ASC' ]
4524 global $wgGroupPermissions, $wgRevokePermissions;
4527 foreach ( $groups
as $group ) {
4528 if ( isset( $wgGroupPermissions[$group] ) ) {
4529 $rights = array_merge( $rights,
4531 array_keys( array_filter( $wgGroupPermissions[$group] ) ) );
4535 foreach ( $groups
as $group ) {
4536 if ( isset( $wgRevokePermissions[$group] ) ) {
4537 $rights = array_diff( $rights,
4538 array_keys( array_filter( $wgRevokePermissions[$group] ) ) );
4541 return array_unique( $rights );
4551 global $wgGroupPermissions;
4552 $allowedGroups = [];
4553 foreach ( array_keys( $wgGroupPermissions )
as $group ) {
4554 if ( self::groupHasPermission( $group, $role ) ) {
4555 $allowedGroups[] = $group;
4558 return $allowedGroups;
4574 global $wgGroupPermissions, $wgRevokePermissions;
4575 return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
4576 && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
4594 global $wgGroupPermissions, $wgRevokePermissions;
4599 if ( isset(
$cache[$right] ) && !defined(
'MW_PHPUNIT_TEST' ) ) {
4603 if ( !isset( $wgGroupPermissions[
'*'][$right] ) || !$wgGroupPermissions[
'*'][$right] ) {
4609 foreach ( $wgRevokePermissions
as $rights ) {
4610 if ( isset( $rights[$right] ) && $rights[$right] ) {
4618 if ( !defined(
'MW_NO_SESSION' ) ) {
4619 $allowedRights = SessionManager::getGlobalSession()->getAllowedUserRights();
4620 if ( $allowedRights !== null && !in_array( $right, $allowedRights,
true ) ) {
4627 if ( !
Hooks::run(
'UserIsEveryoneAllowed', [ $right ] ) ) {
4644 return $msg->isBlank() ? $group : $msg->text();
4656 return $msg->isBlank() ? $group : $msg->text();
4666 global $wgGroupPermissions, $wgRevokePermissions;
4668 array_merge( array_keys( $wgGroupPermissions ), array_keys( $wgRevokePermissions ) ),
4669 self::getImplicitGroups()
4678 if ( self::$mAllRights ===
false ) {
4679 global $wgAvailableRights;
4680 if ( count( $wgAvailableRights ) ) {
4681 self::$mAllRights = array_unique( array_merge( self::$mCoreRights, $wgAvailableRights ) );
4683 self::$mAllRights = self::$mCoreRights;
4685 Hooks::run(
'UserGetAllRights', [ &self::$mAllRights ] );
4687 return self::$mAllRights;
4695 global $wgImplicitGroups;
4697 $groups = $wgImplicitGroups;
4698 # Deprecated, use $wgImplicitGroups instead
4699 Hooks::run(
'UserGetImplicitGroups', [ &$groups ],
'1.25' );
4711 $msg =
wfMessage(
'grouppage-' . $group )->inContentLanguage();
4712 if ( $msg->exists() ) {
4714 if ( is_object(
$title ) ) {
4730 if ( $text ==
'' ) {
4731 $text = self::getGroupName( $group );
4733 $title = self::getGroupPage( $group );
4737 return htmlspecialchars( $text );
4750 if ( $text ==
'' ) {
4751 $text = self::getGroupName( $group );
4753 $title = self::getGroupPage( $group );
4756 return "[[$page|$text]]";
4772 global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
4781 if ( empty( $wgAddGroups[$group] ) ) {
4783 } elseif ( $wgAddGroups[$group] ===
true ) {
4785 $groups[
'add'] = self::getAllGroups();
4786 } elseif ( is_array( $wgAddGroups[$group] ) ) {
4787 $groups[
'add'] = $wgAddGroups[$group];
4791 if ( empty( $wgRemoveGroups[$group] ) ) {
4793 } elseif ( $wgRemoveGroups[$group] ===
true ) {
4794 $groups[
'remove'] = self::getAllGroups();
4795 } elseif ( is_array( $wgRemoveGroups[$group] ) ) {
4796 $groups[
'remove'] = $wgRemoveGroups[$group];
4800 if ( empty( $wgGroupsAddToSelf[
'user'] ) || $wgGroupsAddToSelf[
'user'] !==
true ) {
4802 if ( is_int(
$key ) ) {
4803 $wgGroupsAddToSelf[
'user'][] =
$value;
4808 if ( empty( $wgGroupsRemoveFromSelf[
'user'] ) || $wgGroupsRemoveFromSelf[
'user'] !==
true ) {
4809 foreach ( $wgGroupsRemoveFromSelf
as $key =>
$value ) {
4810 if ( is_int(
$key ) ) {
4811 $wgGroupsRemoveFromSelf[
'user'][] =
$value;
4817 if ( empty( $wgGroupsAddToSelf[$group] ) ) {
4819 } elseif ( $wgGroupsAddToSelf[$group] ===
true ) {
4822 } elseif ( is_array( $wgGroupsAddToSelf[$group] ) ) {
4823 $groups[
'add-self'] = $wgGroupsAddToSelf[$group];
4826 if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
4828 } elseif ( $wgGroupsRemoveFromSelf[$group] ===
true ) {
4830 } elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {
4831 $groups[
'remove-self'] = $wgGroupsRemoveFromSelf[$group];
4845 if ( $this->
isAllowed(
'userrights' ) ) {
4868 foreach ( $addergroups
as $addergroup ) {
4869 $groups = array_merge_recursive(
4872 $groups[
'add'] = array_unique( $groups[
'add'] );
4873 $groups[
'remove'] = array_unique( $groups[
'remove'] );
4874 $groups[
'add-self'] = array_unique( $groups[
'add-self'] );
4875 $groups[
'remove-self'] = array_unique( $groups[
'remove-self'] );
4903 [
'user_editcount=user_editcount+1' ],
4904 [
'user_id' => $this->
getId(),
'user_editcount IS NOT NULL' ],
4908 if ( $dbw->affectedRows() == 0 ) {
4911 if (
$dbr !== $dbw ) {
4940 [
'rev_user' => $this->getId() ],
4948 [
'user_editcount' =>
$count ],
4949 [
'user_id' => $this->
getId() ],
4963 $key =
"right-$right";
4965 return $msg->isBlank() ? $right : $msg->text();
4977 public static function crypt( $password, $salt =
false ) {
4981 $hash = $passwordFactory->newFromPlaintext( $password );
4982 return $hash->toString();
5001 if ( preg_match(
'/^[0-9a-f]{32}$/', $hash ) ) {
5003 if ( $wgPasswordSalt ) {
5004 $password =
":B:{$userId}:{$hash}";
5006 $password =
":A:{$hash}";
5012 $hash = $passwordFactory->newFromCiphertext( $hash );
5013 return $hash->equals( $password );
5064 if ( $this->mOptionsLoaded ) {
5068 $this->mOptions = self::getDefaultOptions();
5070 if ( !$this->
getId() ) {
5075 $variant = $wgContLang->getDefaultVariant();
5076 $this->mOptions[
'variant'] = $variant;
5077 $this->mOptions[
'language'] = $variant;
5078 $this->mOptionsLoaded =
true;
5083 if ( !is_null( $this->mOptionOverrides ) ) {
5084 wfDebug(
"User: loading options for user " . $this->
getId() .
" from override cache.\n" );
5085 foreach ( $this->mOptionOverrides
as $key =>
$value ) {
5089 if ( !is_array( $data ) ) {
5090 wfDebug(
"User: loading options for user " . $this->
getId() .
" from database.\n" );
5092 $dbr = ( $this->queryFlagsUsed & self::READ_LATEST )
5098 [
'up_property',
'up_value' ],
5099 [
'up_user' => $this->
getId() ],
5103 $this->mOptionOverrides = [];
5105 foreach (
$res as $row ) {
5106 $data[$row->up_property] = $row->up_value;
5115 $this->mOptionsLoaded =
true;
5117 Hooks::run(
'UserLoadOptions', [ $this, &$this->mOptions ] );
5133 if ( !
Hooks::run(
'UserSaveOptions', [ $this, &$saveOptions ] ) ) {
5137 $userId = $this->
getId();
5142 $defaultOption = self::getDefaultOption(
$key );
5143 if ( ( $defaultOption === null &&
$value !==
false &&
$value !== null )
5144 ||
$value != $defaultOption
5147 'up_user' => $userId,
5148 'up_property' =>
$key,
5156 $res = $dbw->select(
'user_properties',
5157 [
'up_property',
'up_value' ], [
'up_user' => $userId ], __METHOD__ );
5162 foreach (
$res as $row ) {
5163 if ( !isset( $saveOptions[$row->up_property] )
5164 || strcmp( $saveOptions[$row->up_property], $row->up_value ) != 0
5166 $keysDelete[] = $row->up_property;
5170 if ( count( $keysDelete ) ) {
5178 $dbw->delete(
'user_properties',
5179 [
'up_user' => $userId,
'up_property' => $keysDelete ], __METHOD__ );
5182 $dbw->insert(
'user_properties', $insert_rows, __METHOD__, [
'IGNORE' ] );
5223 global $wgMinimalPasswordLength;
5225 if ( $wgMinimalPasswordLength == 0 ) {
5229 # Note that the pattern requirement will always be satisfied if the
5230 # input is empty, so we need required in all cases.
5232 # @todo FIXME: Bug 23769: This needs to not claim the password is required
5233 # if e-mail confirmation is being used. Since HTML5 input validation
5234 # is b0rked anyway in some browsers, just return nothing. When it's
5235 # re-enabled, fix this code to not output required for e-mail
5237 # $ret = array( 'required' );
5240 # We can't actually do this right now, because Opera 9.6 will print out
5241 # the entered password visibly in its error message! When other
5242 # browsers add support for this attribute, or Opera fixes its support,
5243 # we can add support with a version check to avoid doing this on Opera
5244 # versions where it will be a problem. Reported to Opera as
5245 # DSK-262266, but they don't have a public bug tracker for us to follow.
5270 'user_email_authenticated',
5272 'user_email_token_expires',
5273 'user_registration',
5288 $groups = array_map(
5289 [
'User',
'makeGroupLinkWiki' ],
5294 return Status::newFatal(
'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
5310 if ( !$this->
getId() ) {
5315 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