36 define(
'EDIT_TOKEN_SUFFIX', Token::SUFFIX );
101 'mEmailAuthenticated',
103 'mEmailTokenExpires',
149 'editusercssjs', # deprecated
162 'move-categorypages',
163 'move-rootuserpages',
167 'override-export-depth',
190 'userrights-interwiki',
324 return (
string)$this->
getName();
349 return ( !defined(
'MW_NO_SESSION' ) && $wgFullyInitialised ) ||
350 $this->mLoadedItems ===
true || $this->mFrom !==
'session';
361 if ( $this->mLoadedItems ===
true ) {
367 $this->mLoadedItems =
true;
368 $this->queryFlagsUsed =
$flags;
371 if ( !$wgFullyInitialised && $this->mFrom ===
'session' ) {
373 ->warning(
'User::loadFromSession called before the end of Setup.php', [
374 'exception' =>
new Exception(
'User::loadFromSession called before the end of Setup.php' ),
377 $this->mLoadedItems = $oldLoadedItems;
381 switch ( $this->mFrom ) {
387 if (
wfGetLB()->hasOrMadeRecentMasterChanges() ) {
388 $flags |= self::READ_LATEST;
389 $this->queryFlagsUsed =
$flags;
392 $this->mId = self::idFromName( $this->mName,
$flags );
408 Hooks::run(
'UserLoadAfterLoadFromSession', [ $this ] );
412 "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
422 if ( $this->mId == 0 ) {
440 $this->mLoadedItems =
true;
441 $this->queryFlagsUsed =
$flags;
451 public static function purge( $wikiId, $userId ) {
453 $key =
$cache->makeGlobalKey(
'user',
'id', $wikiId, $userId );
474 $data =
$cache->getWithSetCallback(
479 wfDebug(
"User: cache miss for user {$this->mId}\n" );
486 foreach ( self::$mCacheVars
as $name ) {
487 $data[
$name] = $this->$name;
495 [
'pcTTL' => $cache::TTL_PROC_LONG,
'version' => self::VERSION ]
499 foreach ( self::$mCacheVars
as $name ) {
500 $this->$name = $data[
$name];
526 if ( $validate ===
true ) {
529 $name = self::getCanonicalName(
$name, $validate );
530 if (
$name ===
false ) {
537 $u->setItemLoaded(
'name' );
552 $u->setItemLoaded(
'id' );
568 $db = (
$flags & self::READ_LATEST ) == self::READ_LATEST
572 $id = $db->selectField(
576 'user_email_token' => md5(
$code ),
577 'user_email_token_expires > ' . $db->addQuotes( $db->timestamp() ),
593 $user->mFrom =
'session';
614 $user->loadFromRow( $row, $data );
655 'validate' =>
'valid',
661 if (
$name ===
false ) {
665 $fields = self::selectFields();
668 $row = $dbw->selectRow(
671 [
'user_name' =>
$name ],
678 $user = self::newFromRow( $row );
682 if (
$user->mEmail ||
$user->mToken !== self::INVALID_TOKEN ||
683 AuthManager::singleton()->userCanAuthenticate(
$name )
690 AuthManager::singleton()->revokeAccessForUser(
$name );
692 $user->invalidateEmail();
693 $user->mToken = self::INVALID_TOKEN;
694 $user->saveSettings();
695 SessionManager::singleton()->preventSessionsForUser(
$user->getName() );
708 public static function whoIs( $id ) {
730 if ( is_null( $nt ) ) {
735 if ( !(
$flags & self::READ_LATEST ) && isset( self::$idCacheByName[
$name] ) ) {
736 return self::$idCacheByName[
$name];
745 [
'user_name' => $nt->getText() ],
750 if (
$s ===
false ) {
758 if ( count( self::$idCacheByName ) > 1000 ) {
759 self::$idCacheByName = [];
769 self::$idCacheByName = [];
789 return preg_match(
'/^\d{1,3}\.\d{1,3}\.\d{1,3}\.(?:xxx|\d{1,3})$/',
$name )
809 || strpos(
$name,
'/' ) !==
false
810 || strlen(
$name ) > $wgMaxNameChars
819 if ( is_null( $parsed )
820 || $parsed->getNamespace()
821 || strcmp(
$name, $parsed->getPrefixedText() ) ) {
827 $unicodeBlacklist =
'/[' .
828 '\x{0080}-\x{009f}' . # iso-8859-1 control chars
829 '\x{00a0}' . # non-breaking space
830 '\x{2000}-\x{200f}' . # various whitespace
831 '\x{2028}-\x{202f}' . # breaks
and control chars
832 '\x{3000}' . # ideographic space
833 '\x{e000}-\x{f8ff}' . #
private use
835 if ( preg_match( $unicodeBlacklist,
$name ) ) {
854 global $wgReservedUsernames;
856 if ( !self::isValidUserName(
$name ) ) {
860 static $reservedUsernames =
false;
861 if ( !$reservedUsernames ) {
862 $reservedUsernames = $wgReservedUsernames;
863 Hooks::run(
'UserGetReservedNames', [ &$reservedUsernames ] );
867 foreach ( $reservedUsernames
as $reserved ) {
868 if ( substr( $reserved, 0, 4 ) ==
'msg:' ) {
869 $reserved =
wfMessage( substr( $reserved, 4 ) )->inContentLanguage()->text();
871 if ( $reserved ==
$name ) {
889 if ( $groups === [] ) {
893 $groups = array_unique( (
array)$groups );
896 $conds = [
'ug_group' => $groups ];
897 if ( $after !== null ) {
898 $conds[] =
'ug_user > ' . (int)$after;
902 $ids =
$dbr->selectFieldValues(
909 'ORDER BY' =>
'ug_user',
929 global $wgInvalidUsernameCharacters;
934 if ( strlen(
$name ) > 235 ) {
936 ": '$name' invalid due to length" );
941 if ( $wgInvalidUsernameCharacters !==
'' ) {
942 if ( preg_match(
'/[' . preg_quote( $wgInvalidUsernameCharacters,
'/' ) .
']/',
$name ) ) {
944 ": '$name' invalid due to wgInvalidUsernameCharacters" );
949 return self::isUsableName(
$name );
975 foreach (
$result->getErrorsByType(
'error' )
as $error ) {
978 foreach (
$result->getErrorsByType(
'warning' )
as $warning ) {
1007 global $wgPasswordPolicy;
1010 $wgPasswordPolicy[
'policies'],
1011 $wgPasswordPolicy[
'checks']
1023 $status->merge( $upp->checkUserPassword( $this, $password, $purpose ) );
1025 } elseif (
$result ===
true ) {
1051 # Reject names containing '#'; these will be cleaned up
1052 # with title normalisation, but then it's too late to
1054 if ( strpos(
$name,
'#' ) !==
false ) {
1060 $t = ( $validate !==
false ) ?
1063 if ( is_null(
$t ) ||
$t->getNamespace() !==
NS_USER ||
$t->isExternal() ) {
1068 $name = AuthManager::callLegacyAuthPlugin(
1069 'getCanonicalName', [
$t->getText() ],
$t->getText()
1072 switch ( $validate ) {
1092 'Invalid parameter value for $validate in ' . __METHOD__ );
1107 $user = self::newFromId( $uid );
1108 return $user->getEditCount();
1118 global $wgMinimalPasswordLength;
1132 $this->mName =
$name;
1133 $this->mRealName =
'';
1135 $this->mOptionOverrides = null;
1136 $this->mOptionsLoaded =
false;
1138 $loggedOut = $this->mRequest && !defined(
'MW_NO_SESSION' )
1139 ? $this->mRequest->getSession()->getLoggedOutTimestamp() : 0;
1140 if ( $loggedOut !== 0 ) {
1143 $this->mTouched =
'1'; # Allow any
pages to be cached
1146 $this->mToken = null;
1147 $this->mEmailAuthenticated = null;
1148 $this->mEmailToken =
'';
1149 $this->mEmailTokenExpires = null;
1151 $this->mGroups = [];
1169 return ( $this->mLoadedItems ===
true && $all ===
'all' ) ||
1170 ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] ===
true );
1179 if ( is_array( $this->mLoadedItems ) ) {
1180 $this->mLoadedItems[$item] =
true;
1199 $session = $this->
getRequest()->getSession();
1200 $user = $session->getUser();
1201 if (
$user->isLoggedIn() ) {
1204 $session->set(
'wsUserID', $this->
getId() );
1205 $session->set(
'wsUserName', $this->
getName() );
1206 $session->set(
'wsToken', $this->
getToken() );
1222 $this->mId = intval( $this->mId );
1224 if ( !$this->mId ) {
1233 $s = $db->selectRow(
1235 self::selectFields(),
1236 [
'user_id' => $this->mId ],
1241 $this->queryFlagsUsed =
$flags;
1244 if (
$s !==
false ) {
1247 $this->mGroups = null;
1270 $this->mGroups = null;
1272 if ( isset( $row->user_name ) ) {
1273 $this->mName = $row->user_name;
1274 $this->mFrom =
'name';
1280 if ( isset( $row->user_real_name ) ) {
1281 $this->mRealName = $row->user_real_name;
1287 if ( isset( $row->user_id ) ) {
1288 $this->mId = intval( $row->user_id );
1289 $this->mFrom =
'id';
1295 if ( isset( $row->user_id ) && isset( $row->user_name ) ) {
1296 self::$idCacheByName[$row->user_name] = $row->user_id;
1299 if ( isset( $row->user_editcount ) ) {
1300 $this->mEditCount = $row->user_editcount;
1305 if ( isset( $row->user_touched ) ) {
1311 if ( isset( $row->user_token ) ) {
1315 $this->mToken = rtrim( $row->user_token,
" \0" );
1316 if ( $this->mToken ===
'' ) {
1317 $this->mToken = null;
1323 if ( isset( $row->user_email ) ) {
1324 $this->mEmail = $row->user_email;
1326 $this->mEmailToken = $row->user_email_token;
1334 $this->mLoadedItems =
true;
1337 if ( is_array( $data ) ) {
1338 if ( isset( $data[
'user_groups'] ) && is_array( $data[
'user_groups'] ) ) {
1339 $this->mGroups = $data[
'user_groups'];
1341 if ( isset( $data[
'user_properties'] ) && is_array( $data[
'user_properties'] ) ) {
1354 foreach ( self::$mCacheVars
as $var ) {
1355 $this->$var =
$user->$var;
1363 if ( is_null( $this->mGroups ) ) {
1364 $db = ( $this->queryFlagsUsed & self::READ_LATEST )
1367 $res = $db->select(
'user_groups',
1369 [
'ug_user' => $this->mId ],
1371 $this->mGroups = [];
1372 foreach (
$res as $row ) {
1373 $this->mGroups[] = $row->ug_group;
1393 global $wgAutopromoteOnceLogInRC;
1400 if ( !count( $toPromote ) ) {
1409 foreach ( $toPromote
as $group ) {
1413 Hooks::run(
'UserGroupsChanged', [ $this, $toPromote, [],
false,
false ] );
1414 AuthManager::callLegacyAuthPlugin(
'updateExternalDBGroups', [ $this, $toPromote ] );
1416 $newGroups = array_merge( $oldGroups, $toPromote );
1419 $logEntry->setPerformer( $this );
1421 $logEntry->setParameters( [
1422 '4::oldgroups' => $oldGroups,
1423 '5::newgroups' => $newGroups,
1425 $logid = $logEntry->insert();
1426 if ( $wgAutopromoteOnceLogInRC ) {
1427 $logEntry->publish( $logid );
1443 if ( $this->mTouched ) {
1445 $conditions[
'user_touched'] = $db->
timestamp( $this->mTouched );
1463 if ( !$this->mId ) {
1471 $dbw->update(
'user',
1472 [
'user_touched' => $dbw->timestamp( $newTouched ) ],
1474 'user_id' => $this->mId,
1478 $success = ( $dbw->affectedRows() > 0 );
1481 $this->mTouched = $newTouched;
1499 $this->mNewtalk = -1;
1500 $this->mDatePreference = null;
1501 $this->mBlockedby = -1; # Unset
1502 $this->mHash =
false;
1503 $this->mRights = null;
1504 $this->mEffectiveGroups = null;
1505 $this->mImplicitGroups = null;
1506 $this->mGroups = null;
1507 $this->mOptions = null;
1508 $this->mOptionsLoaded =
false;
1509 $this->mEditCount = null;
1511 if ( $reloadFrom ) {
1512 $this->mLoadedItems = [];
1513 $this->mFrom = $reloadFrom;
1526 static $defOpt = null;
1527 static $defOptLang = null;
1529 if ( $defOpt !== null && $defOptLang === $wgContLang->getCode() ) {
1538 $defOptLang = $wgContLang->getCode();
1539 $defOpt[
'language'] = $defOptLang;
1541 $defOpt[$langCode == $wgContLang->getCode() ?
'variant' :
"variant-$langCode"] = $langCode;
1547 foreach ( $wgNamespacesToBeSearchedDefault
as $nsnum => $val ) {
1548 $defOpt[
'searchNs' . $nsnum] = (
boolean)$val;
1552 Hooks::run(
'UserGetDefaultOptions', [ &$defOpt ] );
1564 $defOpts = self::getDefaultOptions();
1565 if ( isset( $defOpts[$opt] ) ) {
1566 return $defOpts[$opt];
1581 if ( -1 != $this->mBlockedby ) {
1585 wfDebug( __METHOD__ .
": checking...\n" );
1594 # We only need to worry about passing the IP address to the Block generator if the
1595 # user is not immune to autoblocks/hardblocks, and they are the current user so we
1596 # know which IP address they're actually coming from
1598 if ( !$this->
isAllowed(
'ipblock-exempt' ) ) {
1601 $globalUserName = $wgUser->isSafeToLoad()
1602 ? $wgUser->getName()
1604 if ( $this->
getName() === $globalUserName ) {
1613 if ( !$block instanceof
Block && $ip !== null && !in_array( $ip, $wgProxyWhitelist ) ) {
1615 if ( self::isLocallyBlockedProxy( $ip ) ) {
1618 $block->mReason =
wfMessage(
'proxyblockreason' )->text();
1619 $block->setTarget( $ip );
1623 $block->mReason =
wfMessage(
'sorbsreason' )->text();
1624 $block->setTarget( $ip );
1629 if ( !$block instanceof
Block
1630 && $wgApplyIpBlocksToXff
1632 && !in_array( $ip, $wgProxyWhitelist )
1634 $xff = $this->
getRequest()->getHeader(
'X-Forwarded-For' );
1635 $xff = array_map(
'trim', explode(
',', $xff ) );
1636 $xff = array_diff( $xff, [ $ip ] );
1639 if ( $block instanceof
Block ) {
1640 # Mangle the reason to alert the user that the block
1641 # originated from matching the X-Forwarded-For header.
1642 $block->mReason =
wfMessage(
'xffblockreason', $block->mReason )->text();
1646 if ( $block instanceof
Block ) {
1647 wfDebug( __METHOD__ .
": Found block.\n" );
1648 $this->mBlock = $block;
1649 $this->mBlockedby = $block->getByName();
1650 $this->mBlockreason = $block->mReason;
1651 $this->mHideName = $block->mHideName;
1652 $this->mAllowUsertalk = !$block->prevents(
'editownusertalk' );
1654 $this->mBlockedby =
'';
1655 $this->mHideName = 0;
1656 $this->mAllowUsertalk =
false;
1660 Hooks::run(
'GetBlockedStatus', [ &$this ] );
1672 global $wgEnableDnsBlacklist, $wgDnsBlacklistUrls, $wgProxyWhitelist;
1674 if ( !$wgEnableDnsBlacklist ) {
1678 if ( $checkWhitelist && in_array( $ip, $wgProxyWhitelist ) ) {
1698 $ipReversed = implode(
'.', array_reverse( explode(
'.', $ip ) ) );
1704 if ( is_array( $base ) ) {
1705 if ( count( $base ) >= 2 ) {
1707 $host =
"{$base[1]}.$ipReversed.{$base[0]}";
1709 $host =
"$ipReversed.{$base[0]}";
1711 $basename = $base[0];
1713 $host =
"$ipReversed.$base";
1717 $ipList = gethostbynamel( $host );
1720 wfDebugLog(
'dnsblacklist',
"Hostname $host is {$ipList[0]}, it's a proxy says $basename!" );
1724 wfDebugLog(
'dnsblacklist',
"Requested $host, not found in $basename." );
1742 if ( !$wgProxyList ) {
1746 if ( !is_array( $wgProxyList ) ) {
1748 $wgProxyList = array_map(
'trim',
file( $wgProxyList ) );
1751 if ( !is_array( $wgProxyList ) ) {
1753 } elseif ( array_search( $ip, $wgProxyList ) !==
false ) {
1755 } elseif ( array_key_exists( $ip, $wgProxyList ) ) {
1770 global $wgRateLimitsExcludedIPs;
1771 if ( in_array( $this->
getRequest()->getIP(), $wgRateLimitsExcludedIPs ) ) {
1777 return !$this->
isAllowed(
'noratelimit' );
1802 if ( !isset( $wgRateLimits[$action] ) ) {
1806 $limits = array_merge(
1807 [
'&can-bypass' =>
true ],
1808 $wgRateLimits[$action]
1817 $id = $this->
getId();
1823 if ( isset( $limits[
'anon'] ) ) {
1824 $keys[
wfMemcKey(
'limiter', $action,
'anon' )] = $limits[
'anon'];
1828 if ( isset( $limits[
'user'] ) ) {
1829 $userLimit = $limits[
'user'];
1832 if ( $isNewbie && isset( $limits[
'newbie'] ) ) {
1833 $keys[
wfMemcKey(
'limiter', $action,
'user', $id )] = $limits[
'newbie'];
1840 if ( isset( $limits[
'ip'] ) ) {
1842 $keys[
"mediawiki:limiter:$action:ip:$ip"] = $limits[
'ip'];
1845 if ( isset( $limits[
'subnet'] ) ) {
1848 if ( $subnet !==
false ) {
1849 $keys[
"mediawiki:limiter:$action:subnet:$subnet"] = $limits[
'subnet'];
1857 if ( isset( $limits[$group] ) ) {
1858 if ( $userLimit ===
false
1859 || $limits[$group][0] / $limits[$group][1] > $userLimit[0] / $userLimit[1]
1861 $userLimit = $limits[$group];
1867 if ( $userLimit !==
false ) {
1868 list( $max, $period ) = $userLimit;
1869 wfDebug( __METHOD__ .
": effective user limit: $max in {$period}s\n" );
1870 $keys[
wfMemcKey(
'limiter', $action,
'user', $id )] = $userLimit;
1874 if ( isset( $limits[
'ip-all'] ) ) {
1877 if ( $isNewbie || $userLimit ===
false
1878 || $limits[
'ip-all'][0] / $limits[
'ip-all'][1] > $userLimit[0] / $userLimit[1] ) {
1879 $keys[
"mediawiki:limiter:$action:ip-all:$ip"] = $limits[
'ip-all'];
1884 if ( isset( $limits[
'subnet-all'] ) ) {
1887 if ( $subnet !==
false ) {
1889 if ( $isNewbie || $userLimit ===
false
1890 || $limits[
'ip-all'][0] / $limits[
'ip-all'][1]
1891 > $userLimit[0] / $userLimit[1] ) {
1892 $keys[
"mediawiki:limiter:$action:subnet-all:$subnet"] = $limits[
'subnet-all'];
1902 $summary =
"(limit $max in {$period}s)";
1907 wfDebugLog(
'ratelimit',
"User '{$this->getName()}' " .
1908 "(IP {$this->getRequest()->getIP()}) tripped $key at $count $summary" );
1911 wfDebug( __METHOD__ .
": ok. $key at $count $summary\n" );
1914 wfDebug( __METHOD__ .
": adding record for $key $summary\n" );
1916 $cache->add( $key, 0, intval( $period ) );
1946 return $this->mBlock instanceof
Block ? $this->mBlock : null;
1957 global $wgBlockAllowsUTEdit;
1959 $blocked = $this->
isBlocked( $bFromSlave );
1960 $allowUsertalk = ( $wgBlockAllowsUTEdit ? $this->mAllowUsertalk :
false );
1962 if ( !$this->mHideName && $allowUsertalk &&
$title->getText() === $this->
getName()
1965 wfDebug( __METHOD__ .
": self-talk page, ignoring any blocks\n" );
1968 Hooks::run(
'UserIsBlockedFrom', [ $this,
$title, &$blocked, &$allowUsertalk ] );
1997 return ( $this->mBlock ? $this->mBlock->getId() :
false );
2023 if ( $this->mGlobalBlock !== null ) {
2024 return $this->mGlobalBlock ?: null;
2034 Hooks::run(
'UserIsBlockedGlobally', [ &$this, $ip, &$blocked, &$block ] );
2036 if ( $blocked && $block === null ) {
2042 $this->mGlobalBlock = $blocked ? $block :
false;
2043 return $this->mGlobalBlock ?: null;
2052 if ( $this->mLocked !== null ) {
2055 $authUser = AuthManager::callLegacyAuthPlugin(
'getUserInstance', [ &$this ], null );
2056 $this->mLocked = $authUser && $authUser->isLocked();
2057 Hooks::run(
'UserIsLocked', [ $this, &$this->mLocked ] );
2067 if ( $this->mHideName !== null ) {
2071 if ( !$this->mHideName ) {
2072 $authUser = AuthManager::callLegacyAuthPlugin(
'getUserInstance', [ &$this ], null );
2073 $this->mHideName = $authUser && $authUser->isHidden();
2074 Hooks::run(
'UserIsHidden', [ $this, &$this->mHideName ] );
2084 if ( $this->mId === null && $this->mName !== null &&
User::isIP( $this->mName ) ) {
2114 if ( $this->mName ===
false ) {
2137 $this->mName = $str;
2145 return str_replace(
' ',
'_', $this->
getName() );
2156 if ( $this->mNewtalk === -1 ) {
2157 $this->mNewtalk =
false; # reset talk
page status
2161 if ( !$this->mId ) {
2162 global $wgDisableAnonTalk;
2163 if ( $wgDisableAnonTalk ) {
2165 $this->mNewtalk =
false;
2170 $this->mNewtalk = $this->
checkNewtalk(
'user_id', $this->mId );
2192 if ( !
Hooks::run(
'UserRetrieveNewTalks', [ &$this, &$talks ] ) ) {
2201 'MIN(user_last_timestamp)',
2202 $this->
isAnon() ? [
'user_ip' => $this->
getName() ] : [
'user_id' => $this->
getId() ],
2205 return [ [
'wiki' =>
wfWikiID(),
'link' => $utp->getLocalURL(),
'rev' =>
$rev ] ];
2214 $newMessageRevisionId = null;
2216 if ( $newMessageLinks ) {
2220 if ( count( $newMessageLinks ) === 1
2221 && $newMessageLinks[0][
'wiki'] ===
wfWikiID()
2222 && $newMessageLinks[0][
'rev']
2225 $newMessageRevision = $newMessageLinks[0][
'rev'];
2226 $newMessageRevisionId = $newMessageRevision->getId();
2229 return $newMessageRevisionId;
2243 $ok =
$dbr->selectField(
'user_newtalk', $field, [ $field => $id ], __METHOD__ );
2245 return $ok !==
false;
2257 $prevRev = $curRev ? $curRev->getPrevious() :
false;
2258 $ts = $prevRev ? $prevRev->getTimestamp() : null;
2261 $dbw->insert(
'user_newtalk',
2262 [ $field => $id,
'user_last_timestamp' => $dbw->timestampOrNull( $ts ) ],
2265 if ( $dbw->affectedRows() ) {
2266 wfDebug( __METHOD__ .
": set on ($field, $id)\n" );
2269 wfDebug( __METHOD__ .
" already set ($field, $id)\n" );
2282 $dbw->delete(
'user_newtalk',
2285 if ( $dbw->affectedRows() ) {
2286 wfDebug( __METHOD__ .
": killed on ($field, $id)\n" );
2289 wfDebug( __METHOD__ .
": already gone ($field, $id)\n" );
2306 $this->mNewtalk = $val;
2313 $id = $this->
getId();
2336 if ( $this->mTouched && $time <= $this->mTouched ) {
2354 if ( !$this->
getId() ) {
2360 if ( $mode ===
'refresh' ) {
2361 $cache->delete( $key, 1 );
2395 $id = $this->
getId();
2397 $key =
wfMemcKey(
'user-quicktouched',
'id', $id );
2399 $this->mQuickTouched = null;
2424 if ( $this->mQuickTouched === null ) {
2425 $key =
wfMemcKey(
'user-quicktouched',
'id', $this->mId );
2431 return max( $this->mTouched, $this->mQuickTouched );
2454 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2463 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2507 $manager = AuthManager::singleton();
2510 if ( !$manager->userExists( $this->getName() ) ) {
2511 throw new LogicException(
'Cannot set a password for a user that is not in the database.' );
2515 'username' => $this->
getName(),
2521 ->info( __METHOD__ .
': Password change rejected: '
2522 .
$status->getWikiText( null, null,
'en' ) );
2526 $this->
setOption(
'watchlisttoken',
false );
2527 SessionManager::singleton()->invalidateSessionsForUser( $this );
2545 $manager = AuthManager::singleton();
2546 $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
2547 $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
2550 foreach ( $reqs
as $req ) {
2551 $status->merge( $manager->allowsAuthenticationDataChange( $req ),
true );
2553 if (
$status->getValue() ===
'ignored' ) {
2554 $status->warning(
'authenticationdatachange-ignored' );
2558 foreach ( $reqs
as $req ) {
2559 $manager->changeAuthenticationData( $req );
2572 global $wgAuthenticationTokenVersion;
2575 if ( !$this->mToken && $forceCreation ) {
2579 if ( !$this->mToken ) {
2582 } elseif ( $this->mToken === self::INVALID_TOKEN ) {
2586 } elseif ( $wgAuthenticationTokenVersion === null ) {
2594 $len = max( 32, self::TOKEN_LENGTH );
2595 if ( strlen(
$ret ) < $len ) {
2597 throw new \UnexpectedValueException(
'Hmac returned less than 128 bits' );
2599 return substr(
$ret, -$len );
2611 if ( $this->mToken === self::INVALID_TOKEN ) {
2613 ->debug( __METHOD__ .
": Ignoring attempt to set token for system user \"$this\"" );
2614 } elseif ( !$token ) {
2617 $this->mToken = $token;
2630 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2640 throw new BadMethodCallException( __METHOD__ .
' has been removed in 1.27' );
2649 Hooks::run(
'UserGetEmail', [ $this, &$this->mEmail ] );
2659 Hooks::run(
'UserGetEmailAuthenticationTimestamp', [ $this, &$this->mEmailAuthenticated ] );
2669 if ( $str == $this->mEmail ) {
2673 $this->mEmail = $str;
2674 Hooks::run(
'UserSetEmail', [ $this, &$this->mEmail ] );
2687 if ( !$wgEnableEmail ) {
2692 if ( $str === $oldaddr ) {
2696 $type = $oldaddr !=
'' ?
'changed' :
'set';
2697 $notificationResult = null;
2699 if ( $wgEmailAuthentication ) {
2702 if (
$type ==
'changed' ) {
2703 $change = $str !=
'' ?
'changed' :
'removed';
2704 $notificationResult = $this->
sendMail(
2705 wfMessage(
'notificationemail_subject_' . $change )->
text(),
2706 wfMessage(
'notificationemail_body_' . $change,
2716 if ( $str !==
'' && $wgEmailAuthentication ) {
2720 if ( $notificationResult !== null ) {
2721 $result->merge( $notificationResult );
2753 $this->mRealName = $str;
2766 public function getOption( $oname, $defaultOverride = null, $ignoreHidden =
false ) {
2770 # We want 'disabled' preferences to always behave as the default value for
2771 # users, even if they have set the option explicitly in their settings (ie they
2772 # set it, and then it was disabled removing their ability to change it). But
2773 # we don't want to erase the preferences in the database in case the preference
2774 # is re-enabled again. So don't touch $mOptions, just override the returned value
2775 if ( !$ignoreHidden && in_array( $oname, $wgHiddenPrefs ) ) {
2776 return self::getDefaultOption( $oname );
2779 if ( array_key_exists( $oname, $this->mOptions ) ) {
2780 return $this->mOptions[$oname];
2782 return $defaultOverride;
2799 # We want 'disabled' preferences to always behave as the default value for
2800 # users, even if they have set the option explicitly in their settings (ie they
2801 # set it, and then it was disabled removing their ability to change it). But
2802 # we don't want to erase the preferences in the database in case the preference
2803 # is re-enabled again. So don't touch $mOptions, just override the returned value
2804 foreach ( $wgHiddenPrefs
as $pref ) {
2805 $default = self::getDefaultOption( $pref );
2806 if ( $default !== null ) {
2811 if (
$flags & self::GETOPTIONS_EXCLUDE_DEFAULTS ) {
2826 return (
bool)$this->
getOption( $oname );
2840 $val = $defaultOverride;
2842 return intval( $val );
2857 if ( is_null( $val ) ) {
2858 $val = self::getDefaultOption( $oname );
2861 $this->mOptions[$oname] = $val;
2877 $id = $this->
getId();
2878 if ( !$id || in_array( $oname, $wgHiddenPrefs ) ) {
2887 $token = hash_hmac(
'sha1',
"$oname:$id", $this->
getToken() );
2904 if ( in_array( $oname, $wgHiddenPrefs ) ) {
2939 'registered-multiselect',
2940 'registered-checkmatrix',
2972 unset( $prefs[
$name] );
2977 $multiselectOptions = [];
2978 foreach ( $prefs
as $name => $info ) {
2979 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'multiselect' ) ||
2980 ( isset( $info[
'class'] ) && $info[
'class'] ==
'HTMLMultiSelectField' ) ) {
2982 $prefix = isset( $info[
'prefix'] ) ? $info[
'prefix'] :
$name;
2985 $multiselectOptions[
"$prefix$value"] =
true;
2988 unset( $prefs[
$name] );
2991 $checkmatrixOptions = [];
2992 foreach ( $prefs
as $name => $info ) {
2993 if ( ( isset( $info[
'type'] ) && $info[
'type'] ==
'checkmatrix' ) ||
2994 ( isset( $info[
'class'] ) && $info[
'class'] ==
'HTMLCheckMatrix' ) ) {
2997 $prefix = isset( $info[
'prefix'] ) ? $info[
'prefix'] :
$name;
2999 foreach ( $columns
as $column ) {
3000 foreach ( $rows
as $row ) {
3001 $checkmatrixOptions[
"$prefix$column-$row"] =
true;
3005 unset( $prefs[
$name] );
3011 if ( isset( $prefs[$key] ) ) {
3012 $mapping[$key] =
'registered';
3013 } elseif ( isset( $multiselectOptions[$key] ) ) {
3014 $mapping[$key] =
'registered-multiselect';
3015 } elseif ( isset( $checkmatrixOptions[$key] ) ) {
3016 $mapping[$key] =
'registered-checkmatrix';
3017 } elseif ( isset( $specialOptions[$key] ) ) {
3018 $mapping[$key] =
'special';
3019 } elseif ( substr( $key, 0, 7 ) ===
'userjs-' ) {
3020 $mapping[$key] =
'userjs';
3022 $mapping[$key] =
'unused';
3044 $resetKinds = [
'registered',
'registered-multiselect',
'registered-checkmatrix',
'unused' ],
3048 $defaultOptions = self::getDefaultOptions();
3050 if ( !is_array( $resetKinds ) ) {
3051 $resetKinds = [ $resetKinds ];
3054 if ( in_array(
'all', $resetKinds ) ) {
3055 $newOptions = $defaultOptions;
3062 $resetKinds = array_intersect( $resetKinds, self::listOptionKinds() );
3067 foreach ( $this->mOptions
as $key =>
$value ) {
3068 if ( in_array( $optionKinds[$key], $resetKinds ) ) {
3069 if ( array_key_exists( $key, $defaultOptions ) ) {
3070 $newOptions[$key] = $defaultOptions[$key];
3073 $newOptions[$key] =
$value;
3078 Hooks::run(
'UserResetAllOptions', [ $this, &$newOptions, $this->mOptions, $resetKinds ] );
3080 $this->mOptions = $newOptions;
3081 $this->mOptionsLoaded =
true;
3090 if ( is_null( $this->mDatePreference ) ) {
3093 $map = $wgLang->getDatePreferenceMigrationMap();
3094 if ( isset( $map[
$value] ) ) {
3097 $this->mDatePreference =
$value;
3110 if ( !$wgSecureLogin ) {
3114 Hooks::run(
'UserRequiresHTTPS', [ $this, &$https ] );
3130 if ( $threshold > $wgMaxArticleSize * 1024 ) {
3143 if ( is_null( $this->mRights ) ) {
3145 Hooks::run(
'UserGetRights', [ $this, &$this->mRights ] );
3149 if ( !defined(
'MW_NO_SESSION' ) ) {
3150 $allowedRights = $this->
getRequest()->getSession()->getAllowedUserRights();
3151 if ( $allowedRights !== null ) {
3152 $this->mRights = array_intersect( $this->mRights, $allowedRights );
3157 $this->mRights = array_values( array_unique( $this->mRights ) );
3168 $config->get(
'BlockDisablesLogin' ) &&
3172 $this->mRights = array_intersect( $this->mRights, $anon->getRights() );
3197 if ( $recache || is_null( $this->mEffectiveGroups ) ) {
3198 $this->mEffectiveGroups = array_unique( array_merge(
3203 Hooks::run(
'UserEffectiveGroups', [ &$this, &$this->mEffectiveGroups ] );
3205 $this->mEffectiveGroups = array_values( array_unique( $this->mEffectiveGroups ) );
3218 if ( $recache || is_null( $this->mImplicitGroups ) ) {
3219 $this->mImplicitGroups = [
'*' ];
3220 if ( $this->
getId() ) {
3221 $this->mImplicitGroups[] =
'user';
3223 $this->mImplicitGroups = array_unique( array_merge(
3224 $this->mImplicitGroups,
3231 $this->mEffectiveGroups = null;
3249 if ( is_null( $this->mFormerGroups ) ) {
3250 $db = ( $this->queryFlagsUsed & self::READ_LATEST )
3253 $res = $db->select(
'user_former_groups',
3255 [
'ufg_user' => $this->mId ],
3257 $this->mFormerGroups = [];
3258 foreach (
$res as $row ) {
3259 $this->mFormerGroups[] = $row->ufg_group;
3271 if ( !$this->
getId() ) {
3275 if ( $this->mEditCount === null ) {
3280 'user',
'user_editcount',
3281 [
'user_id' => $this->mId ],
3289 $this->mEditCount =
$count;
3303 if ( !
Hooks::run(
'UserAddGroup', [ $this, &$group ] ) ) {
3308 if ( $this->
getId() ) {
3309 $dbw->insert(
'user_groups',
3311 'ug_user' => $this->
getId(),
3312 'ug_group' => $group,
3319 $this->mGroups[] = $group;
3322 $this->mGroups = array_unique( $this->mGroups );
3327 $this->mRights = null;
3342 if ( !
Hooks::run(
'UserRemoveGroup', [ $this, &$group ] ) ) {
3347 $dbw->delete(
'user_groups',
3349 'ug_user' => $this->
getId(),
3350 'ug_group' => $group,
3354 $dbw->insert(
'user_former_groups',
3356 'ufg_user' => $this->
getId(),
3357 'ufg_group' => $group,
3364 $this->mGroups = array_diff( $this->mGroups, [ $group ] );
3369 $this->mRights = null;
3381 return $this->
getId() != 0;
3402 Hooks::run(
"UserIsBot", [ $this, &$isBot ] );
3414 $permissions = func_get_args();
3415 foreach ( $permissions
as $permission ) {
3416 if ( $this->
isAllowed( $permission ) ) {
3429 $permissions = func_get_args();
3430 foreach ( $permissions
as $permission ) {
3431 if ( !$this->
isAllowed( $permission ) ) {
3444 if ( $action ===
'' ) {
3449 return in_array( $action, $this->
getRights(),
true );
3458 return $wgUseRCPatrol && $this->
isAllowedAny(
'patrol',
'patrolmarks' );
3466 global $wgUseRCPatrol, $wgUseNPPatrol;
3468 ( $wgUseRCPatrol || $wgUseNPPatrol )
3478 global $wgUseRCPatrol, $wgUseFilePatrol;
3480 ( $wgUseRCPatrol || $wgUseFilePatrol )
3491 if ( $this->mRequest ) {
3508 if (
$title->isWatchable() && ( !$checkRights || $this->
isAllowed(
'viewmywatchlist' ) ) ) {
3509 return MediaWikiServices::getInstance()->getWatchedItemStore()->isWatched( $this,
$title );
3522 if ( !$checkRights || $this->
isAllowed(
'editmywatchlist' ) ) {
3523 MediaWikiServices::getInstance()->getWatchedItemStore()->addWatchBatchForUser(
3539 if ( !$checkRights || $this->
isAllowed(
'editmywatchlist' ) ) {
3540 $store = MediaWikiServices::getInstance()->getWatchedItemStore();
3541 $store->removeWatch( $this,
$title->getSubjectPage() );
3542 $store->removeWatch( $this,
$title->getTalkPage() );
3564 if ( !$this->
isAllowed(
'editmywatchlist' ) ) {
3570 if ( !
Hooks::run(
'UserClearNewTalkNotification', [ &$this, $oldid ] ) ) {
3593 if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3611 MediaWikiServices::getInstance()->getWatchedItemStore()
3612 ->resetNotificationTimestamp( $this,
$title, $force, $oldid );
3628 if ( !$wgUseEnotif && !$wgShowUpdatedMarker ) {
3633 $id = $this->
getId();
3639 $asOfTimes = array_unique( $dbw->selectFieldValues(
3641 'wl_notificationtimestamp',
3642 [
'wl_user' => $id,
'wl_notificationtimestamp IS NOT NULL' ],
3644 [
'ORDER BY' =>
'wl_notificationtimestamp DESC',
'LIMIT' => 500 ]
3646 if ( !$asOfTimes ) {
3653 [
'wl_notificationtimestamp' => null ],
3654 [
'wl_user' => $id,
'wl_notificationtimestamp' => $asOfTimes ],
3661 function ()
use ( $dbw, $id ) {
3662 global $wgUpdateRowsPerQuery;
3664 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
3665 $ticket =
$lbFactory->getEmptyTransactionTicket( __METHOD__ );
3666 $asOfTimes = array_unique( $dbw->selectFieldValues(
3668 'wl_notificationtimestamp',
3669 [
'wl_user' => $id,
'wl_notificationtimestamp IS NOT NULL' ],
3672 foreach ( array_chunk( $asOfTimes, $wgUpdateRowsPerQuery )
as $asOfTimeBatch ) {
3675 [
'wl_notificationtimestamp' => null ],
3676 [
'wl_user' => $id,
'wl_notificationtimestamp' => $asOfTimeBatch ],
3679 $lbFactory->commitAndWaitForReplication( __METHOD__, $ticket );
3745 global $wgExtendedLoginCookieExpiration, $wgCookieExpiration;
3750 $exp += $wgExtendedLoginCookieExpiration !== null
3751 ? $wgExtendedLoginCookieExpiration
3752 : $wgCookieExpiration;
3767 if ( 0 == $this->mId ) {
3771 $session = $this->
getRequest()->getSession();
3773 $session = $session->sessionWithRequest(
$request );
3775 $delay = $session->delaySave();
3777 if ( !$session->getUser()->equals( $this ) ) {
3778 if ( !$session->canSetUser() ) {
3780 ->warning( __METHOD__ .
3781 ": Cannot save user \"$this\" to a user \"{$session->getUser()}\"'s immutable session"
3785 $session->setUser( $this );
3788 $session->setRememberUser( $rememberMe );
3789 if ( $secure !== null ) {
3790 $session->setForceHTTPS( $secure );
3793 $session->persist();
3795 ScopedCallback::consume( $delay );
3802 if (
Hooks::run(
'UserLogout', [ &$this ] ) ) {
3812 $session = $this->
getRequest()->getSession();
3813 if ( !$session->canSetUser() ) {
3815 ->warning( __METHOD__ .
": Cannot log out of an immutable session" );
3816 $error =
'immutable';
3817 } elseif ( !$session->getUser()->equals( $this ) ) {
3819 ->warning( __METHOD__ .
3820 ": Cannot log user \"$this\" out of a user \"{$session->getUser()}\"'s session"
3824 $error =
'wronguser';
3827 $delay = $session->delaySave();
3828 $session->unpersist();
3829 $session->setLoggedOutTimestamp( time() );
3830 $session->setUser(
new User );
3831 $session->set(
'wsUserID', 0 );
3832 $session->resetAllTokens();
3833 ScopedCallback::consume( $delay );
3837 'event' =>
'logout',
3838 'successful' => $error ===
false,
3839 'status' => $error ?:
'success',
3853 "Could not update user with ID '{$this->mId}'; DB is read-only."
3859 if ( 0 == $this->mId ) {
3869 $dbw->update(
'user',
3871 'user_name' => $this->mName,
3872 'user_real_name' => $this->mRealName,
3873 'user_email' => $this->mEmail,
3874 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
3875 'user_touched' => $dbw->timestamp( $newTouched ),
3876 'user_token' => strval( $this->mToken ),
3878 'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
3880 'user_id' => $this->mId,
3884 if ( !$dbw->affectedRows() ) {
3888 $from = ( $this->queryFlagsUsed & self::READ_LATEST ) ?
'master' :
'replica';
3890 "CAS update failed on user_touched for user ID '{$this->mId}' (read from $from);" .
3891 " the version of the user to be saved is older than the current version."
3895 $this->mTouched = $newTouched;
3915 $db = ( (
$flags & self::READ_LATEST ) == self::READ_LATEST )
3919 $options = ( (
$flags & self::READ_LOCKING ) == self::READ_LOCKING )
3920 ? [
'LOCK IN SHARE MODE' ]
3923 $id = $db->selectField(
'user',
3924 'user_id', [
'user_name' =>
$s ], __METHOD__,
$options );
3945 foreach ( [
'password',
'newpassword',
'newpass_time',
'password_expires' ]
as $field ) {
3946 if ( isset(
$params[$field] ) ) {
3947 wfDeprecated( __METHOD__ .
" with param '$field'",
'1.27' );
3955 if ( isset(
$params[
'options'] ) ) {
3960 $seqVal = $dbw->nextSequenceValue(
'user_user_id_seq' );
3965 'user_id' => $seqVal,
3966 'user_name' =>
$name,
3967 'user_password' => $noPass,
3968 'user_newpassword' => $noPass,
3969 'user_email' =>
$user->mEmail,
3970 'user_email_authenticated' => $dbw->timestampOrNull(
$user->mEmailAuthenticated ),
3971 'user_real_name' =>
$user->mRealName,
3972 'user_token' => strval(
$user->mToken ),
3973 'user_registration' => $dbw->timestamp(
$user->mRegistration ),
3974 'user_editcount' => 0,
3975 'user_touched' => $dbw->timestamp(
$user->newTouchedTimestamp() ),
3978 $fields[
"user_$name"] =
$value;
3980 $dbw->insert(
'user', $fields, __METHOD__, [
'IGNORE' ] );
3981 if ( $dbw->affectedRows() ) {
4017 if ( !$this->mToken ) {
4026 $seqVal = $dbw->nextSequenceValue(
'user_user_id_seq' );
4027 $dbw->insert(
'user',
4029 'user_id' => $seqVal,
4030 'user_name' => $this->mName,
4031 'user_password' => $noPass,
4032 'user_newpassword' => $noPass,
4033 'user_email' => $this->mEmail,
4034 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
4036 'user_token' => strval( $this->mToken ),
4037 'user_registration' => $dbw->timestamp( $this->mRegistration ),
4038 'user_editcount' => 0,
4039 'user_touched' => $dbw->timestamp( $this->mTouched ),
4043 if ( !$dbw->affectedRows() ) {
4045 $this->mId = $dbw->selectField(
4048 [
'user_name' => $this->mName ],
4050 [
'LOCK IN SHARE MODE' ]
4059 throw new MWException( __METHOD__ .
": hit a key conflict attempting " .
4060 "to insert user '{$this->mName}' row, but it was not present in select!" );
4064 $this->mId = $dbw->insertId();
4093 wfDebug( __METHOD__ .
"()\n" );
4095 if ( $this->mId == 0 ) {
4100 if ( !$userblock ) {
4104 return (
bool)$userblock->doAutoblock( $this->
getRequest()->getIP() );
4113 if ( $this->mBlock && $this->mBlock->prevents(
'createaccount' ) ) {
4117 # bug 13611: if the IP address the user is trying to create an account from is
4118 # blocked with createaccount disabled, prevent new account creation there even
4119 # when the user is logged in
4120 if ( $this->mBlockedFromCreateAccount ===
false && !$this->
isAllowed(
'ipblock-exempt' ) ) {
4123 return $this->mBlockedFromCreateAccount instanceof
Block
4124 && $this->mBlockedFromCreateAccount->
prevents(
'createaccount' )
4125 ? $this->mBlockedFromCreateAccount
4135 return $this->mBlock && $this->mBlock->prevents(
'sendemail' );
4162 return $title->getTalkPage();
4171 return !$this->
isAllowed(
'autoconfirmed' );
4181 $manager = AuthManager::singleton();
4182 $reqs = AuthenticationRequest::loadRequestsFromSubmission(
4183 $manager->getAuthenticationRequests( AuthManager::ACTION_LOGIN ),
4185 'username' => $this->
getName(),
4186 'password' => $password,
4189 $res = AuthManager::singleton()->beginAuthentication( $reqs,
'null:' );
4190 switch ( $res->status ) {
4191 case AuthenticationResponse::PASS:
4193 case AuthenticationResponse::FAIL:
4196 ->info( __METHOD__ .
': Authentication failed: ' . $res->message->plain() );
4199 throw new BadMethodCallException(
4200 'AuthManager returned a response unsupported by ' . __METHOD__
4237 return $request->getSession()->getToken( $salt );
4295 $val = substr( $val, 0, strspn( $val,
'0123456789abcdef' ) ) . Token::SUFFIX;
4314 if (
$type ==
'created' ||
$type ===
false ) {
4315 $message =
'confirmemail_body';
4316 } elseif (
$type ===
true ) {
4317 $message =
'confirmemail_body_changed';
4320 $message =
'confirmemail_body_' .
$type;
4328 $wgLang->userTimeAndDate( $expiration, $this ),
4330 $wgLang->userDate( $expiration, $this ),
4331 $wgLang->userTime( $expiration, $this ) )->
text() );
4357 'replyTo' => $replyto,
4378 $hash = md5( $token );
4379 $this->mEmailToken = $hash;
4380 $this->mEmailTokenExpires = $expiration;
4390 return $this->
getTokenUrl(
'ConfirmEmail', $token );
4399 return $this->
getTokenUrl(
'InvalidateEmail', $token );
4419 return $title->getCanonicalURL();
4434 Hooks::run(
'ConfirmEmailComplete', [ $this ] );
4448 $this->mEmailToken = null;
4449 $this->mEmailTokenExpires = null;
4452 Hooks::run(
'InvalidateEmailComplete', [ $this ] );
4463 Hooks::run(
'UserSetEmailAuthenticationTimestamp', [ $this, &$this->mEmailAuthenticated ] );
4473 if ( !$wgEnableEmail || !$wgEnableUserEmail || !$this->
isAllowed(
'sendemail' ) ) {
4477 Hooks::run(
'UserCanSendEmail', [ &$this, &$canSend ] );
4504 if (
Hooks::run(
'EmailConfirmed', [ &$this, &$confirmed ] ) ) {
4526 return $wgEmailAuthentication &&
4528 $this->mEmailToken &&
4554 if ( $this->
getId() == 0 ) {
4558 $time =
$dbr->selectField(
'revision',
'rev_timestamp',
4559 [
'rev_user' => $this->
getId() ],
4561 [
'ORDER BY' =>
'rev_timestamp ASC' ]
4576 global $wgGroupPermissions, $wgRevokePermissions;
4579 foreach ( $groups
as $group ) {
4580 if ( isset( $wgGroupPermissions[$group] ) ) {
4581 $rights = array_merge( $rights,
4583 array_keys( array_filter( $wgGroupPermissions[$group] ) ) );
4587 foreach ( $groups
as $group ) {
4588 if ( isset( $wgRevokePermissions[$group] ) ) {
4589 $rights = array_diff( $rights,
4590 array_keys( array_filter( $wgRevokePermissions[$group] ) ) );
4593 return array_unique( $rights );
4603 global $wgGroupPermissions;
4604 $allowedGroups = [];
4605 foreach ( array_keys( $wgGroupPermissions )
as $group ) {
4606 if ( self::groupHasPermission( $group, $role ) ) {
4607 $allowedGroups[] = $group;
4610 return $allowedGroups;
4626 global $wgGroupPermissions, $wgRevokePermissions;
4627 return isset( $wgGroupPermissions[$group][$role] ) && $wgGroupPermissions[$group][$role]
4628 && !( isset( $wgRevokePermissions[$group][$role] ) && $wgRevokePermissions[$group][$role] );
4646 global $wgGroupPermissions, $wgRevokePermissions;
4651 if ( isset(
$cache[$right] ) && !defined(
'MW_PHPUNIT_TEST' ) ) {
4655 if ( !isset( $wgGroupPermissions[
'*'][$right] ) || !$wgGroupPermissions[
'*'][$right] ) {
4661 foreach ( $wgRevokePermissions
as $rights ) {
4662 if ( isset( $rights[$right] ) && $rights[$right] ) {
4670 if ( !defined(
'MW_NO_SESSION' ) ) {
4671 $allowedRights = SessionManager::getGlobalSession()->getAllowedUserRights();
4672 if ( $allowedRights !== null && !in_array( $right, $allowedRights,
true ) ) {
4679 if ( !
Hooks::run(
'UserIsEveryoneAllowed', [ $right ] ) ) {
4696 return $msg->isBlank() ? $group : $msg->text();
4708 return $msg->isBlank() ? $group : $msg->text();
4718 global $wgGroupPermissions, $wgRevokePermissions;
4720 array_merge( array_keys( $wgGroupPermissions ), array_keys( $wgRevokePermissions ) ),
4721 self::getImplicitGroups()
4730 if ( self::$mAllRights ===
false ) {
4731 global $wgAvailableRights;
4732 if ( count( $wgAvailableRights ) ) {
4733 self::$mAllRights = array_unique( array_merge( self::$mCoreRights, $wgAvailableRights ) );
4735 self::$mAllRights = self::$mCoreRights;
4737 Hooks::run(
'UserGetAllRights', [ &self::$mAllRights ] );
4739 return self::$mAllRights;
4747 global $wgImplicitGroups;
4749 $groups = $wgImplicitGroups;
4750 # Deprecated, use $wgImplicitGroups instead
4751 Hooks::run(
'UserGetImplicitGroups', [ &$groups ],
'1.25' );
4763 $msg =
wfMessage(
'grouppage-' . $group )->inContentLanguage();
4764 if ( $msg->exists() ) {
4766 if ( is_object(
$title ) ) {
4782 if ( $text ==
'' ) {
4783 $text = self::getGroupName( $group );
4785 $title = self::getGroupPage( $group );
4789 return htmlspecialchars( $text );
4802 if ( $text ==
'' ) {
4803 $text = self::getGroupName( $group );
4805 $title = self::getGroupPage( $group );
4808 return "[[$page|$text]]";
4824 global $wgAddGroups, $wgRemoveGroups, $wgGroupsAddToSelf, $wgGroupsRemoveFromSelf;
4833 if ( empty( $wgAddGroups[$group] ) ) {
4835 } elseif ( $wgAddGroups[$group] ===
true ) {
4837 $groups[
'add'] = self::getAllGroups();
4838 } elseif ( is_array( $wgAddGroups[$group] ) ) {
4839 $groups[
'add'] = $wgAddGroups[$group];
4843 if ( empty( $wgRemoveGroups[$group] ) ) {
4845 } elseif ( $wgRemoveGroups[$group] ===
true ) {
4846 $groups[
'remove'] = self::getAllGroups();
4847 } elseif ( is_array( $wgRemoveGroups[$group] ) ) {
4848 $groups[
'remove'] = $wgRemoveGroups[$group];
4852 if ( empty( $wgGroupsAddToSelf[
'user'] ) || $wgGroupsAddToSelf[
'user'] !==
true ) {
4853 foreach ( $wgGroupsAddToSelf
as $key =>
$value ) {
4854 if ( is_int( $key ) ) {
4855 $wgGroupsAddToSelf[
'user'][] =
$value;
4860 if ( empty( $wgGroupsRemoveFromSelf[
'user'] ) || $wgGroupsRemoveFromSelf[
'user'] !==
true ) {
4861 foreach ( $wgGroupsRemoveFromSelf
as $key =>
$value ) {
4862 if ( is_int( $key ) ) {
4863 $wgGroupsRemoveFromSelf[
'user'][] =
$value;
4869 if ( empty( $wgGroupsAddToSelf[$group] ) ) {
4871 } elseif ( $wgGroupsAddToSelf[$group] ===
true ) {
4874 } elseif ( is_array( $wgGroupsAddToSelf[$group] ) ) {
4875 $groups[
'add-self'] = $wgGroupsAddToSelf[$group];
4878 if ( empty( $wgGroupsRemoveFromSelf[$group] ) ) {
4880 } elseif ( $wgGroupsRemoveFromSelf[$group] ===
true ) {
4882 } elseif ( is_array( $wgGroupsRemoveFromSelf[$group] ) ) {
4883 $groups[
'remove-self'] = $wgGroupsRemoveFromSelf[$group];
4897 if ( $this->
isAllowed(
'userrights' ) ) {
4920 foreach ( $addergroups
as $addergroup ) {
4921 $groups = array_merge_recursive(
4924 $groups[
'add'] = array_unique( $groups[
'add'] );
4925 $groups[
'remove'] = array_unique( $groups[
'remove'] );
4926 $groups[
'add-self'] = array_unique( $groups[
'add-self'] );
4927 $groups[
'remove-self'] = array_unique( $groups[
'remove-self'] );
4958 [
'user_editcount=user_editcount+1' ],
4959 [
'user_id' => $this->
getId(),
'user_editcount IS NOT NULL' ],
4963 if ( $dbw->affectedRows() == 0 ) {
4966 if (
$dbr !== $dbw ) {
4978 if ( $this->mEditCount === null ) {
4981 $this->mEditCount += (
$dbr !== $dbw ) ? 1 : 0;
4983 $this->mEditCount++;
5003 [
'rev_user' => $this->getId() ],
5011 [
'user_editcount' =>
$count ],
5012 [
'user_id' => $this->
getId() ],
5026 $key =
"right-$right";
5028 return $msg->isBlank() ? $right : $msg->text();
5040 public static function crypt( $password, $salt =
false ) {
5044 $hash = $passwordFactory->newFromPlaintext( $password );
5045 return $hash->toString();
5064 if ( preg_match(
'/^[0-9a-f]{32}$/', $hash ) ) {
5066 if ( $wgPasswordSalt ) {
5067 $password =
":B:{$userId}:{$hash}";
5069 $password =
":A:{$hash}";
5075 $hash = $passwordFactory->newFromCiphertext( $hash );
5076 return $hash->equals( $password );
5127 if ( $this->mOptionsLoaded ) {
5131 $this->mOptions = self::getDefaultOptions();
5133 if ( !$this->
getId() ) {
5138 $variant = $wgContLang->getDefaultVariant();
5139 $this->mOptions[
'variant'] = $variant;
5140 $this->mOptions[
'language'] = $variant;
5141 $this->mOptionsLoaded =
true;
5146 if ( !is_null( $this->mOptionOverrides ) ) {
5147 wfDebug(
"User: loading options for user " . $this->
getId() .
" from override cache.\n" );
5148 foreach ( $this->mOptionOverrides
as $key =>
$value ) {
5149 $this->mOptions[$key] =
$value;
5152 if ( !is_array( $data ) ) {
5153 wfDebug(
"User: loading options for user " . $this->
getId() .
" from database.\n" );
5155 $dbr = ( $this->queryFlagsUsed & self::READ_LATEST )
5161 [
'up_property',
'up_value' ],
5162 [
'up_user' => $this->
getId() ],
5166 $this->mOptionOverrides = [];
5168 foreach (
$res as $row ) {
5169 $data[$row->up_property] = $row->up_value;
5178 $this->mOptionsLoaded =
true;
5180 Hooks::run(
'UserLoadOptions', [ $this, &$this->mOptions ] );
5196 if ( !
Hooks::run(
'UserSaveOptions', [ $this, &$saveOptions ] ) ) {
5200 $userId = $this->
getId();
5203 foreach ( $saveOptions
as $key =>
$value ) {
5205 $defaultOption = self::getDefaultOption( $key );
5206 if ( ( $defaultOption === null &&
$value !==
false &&
$value !== null )
5207 ||
$value != $defaultOption
5210 'up_user' => $userId,
5211 'up_property' => $key,
5219 $res = $dbw->select(
'user_properties',
5220 [
'up_property',
'up_value' ], [
'up_user' => $userId ], __METHOD__ );
5225 foreach (
$res as $row ) {
5226 if ( !isset( $saveOptions[$row->up_property] )
5227 || strcmp( $saveOptions[$row->up_property], $row->up_value ) != 0
5229 $keysDelete[] = $row->up_property;
5233 if ( count( $keysDelete ) ) {
5241 $dbw->delete(
'user_properties',
5242 [
'up_user' => $userId,
'up_property' => $keysDelete ], __METHOD__ );
5245 $dbw->insert(
'user_properties', $insert_rows, __METHOD__, [
'IGNORE' ] );
5286 global $wgMinimalPasswordLength;
5288 if ( $wgMinimalPasswordLength == 0 ) {
5292 # Note that the pattern requirement will always be satisfied if the
5293 # input is empty, so we need required in all cases.
5295 # @todo FIXME: Bug 23769: This needs to not claim the password is required
5296 # if e-mail confirmation is being used. Since HTML5 input validation
5297 # is b0rked anyway in some browsers, just return nothing. When it's
5298 # re-enabled, fix this code to not output required for e-mail
5300 # $ret = array( 'required' );
5303 # We can't actually do this right now, because Opera 9.6 will print out
5304 # the entered password visibly in its error message! When other
5305 # browsers add support for this attribute, or Opera fixes its support,
5306 # we can add support with a version check to avoid doing this on Opera
5307 # versions where it will be a problem. Reported to Opera as
5308 # DSK-262266, but they don't have a public bug tracker for us to follow.
5333 'user_email_authenticated',
5335 'user_email_token_expires',
5336 'user_registration',
5351 $groups = array_map(
5352 [
'User',
'makeGroupLinkWiki' ],
5357 return Status::newFatal(
'badaccess-groups', $wgLang->commaList( $groups ), count( $groups ) );
5373 if ( !$this->
getId() ) {
5378 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.
makeUpdateConditions(Database $db, array $conditions)
Builds update conditions.
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...
matchEditTokenNoSuffix($val, $salt= '', $request=null, $maxage=null)
Check given value against the token value stored in the session, ignoring the suffix.
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.
processing should stop and the error should be shown to the user * false
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.
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
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.
if(!$wgDBerrorLogTZ) $wgRequest
static getCanonicalName($name, $validate= 'valid')
Given unvalidated user input, return a canonical username, or false if the username is invalid...
static newFatal($message)
Factory function for fatal errors.
static getCacheSetOptions(IDatabase $db1)
Merge the result of getSessionLagStatus() for several DBs using the most pessimistic values to estima...
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.
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.
This document describes the state of Postgres support in and is fairly well maintained The main code is very well while extensions are very hit and miss it is probably the most supported database after MySQL Much of the work in making MediaWiki database agnostic came about through the work of creating Postgres as and are nearing end of but without copying over all the usage comments General notes on the but these can almost always be programmed around *Although Postgres has a true BOOLEAN boolean columns are always mapped to as the code does not always treat the column as a boolean(which is limited to accepting true, false, 0, 1, t, or f)*The default data type for all VARCHAR
timestamp($ts=0)
Convert a timestamp in one of the formats accepted by wfTimestamp() to the format used for inserting ...
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.
static findUsersByGroup($groups, $limit=5000, $after=null)
Return the users who are members of the given group(s).
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
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.
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).
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.
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':DEPRECATED!Use HtmlPageLinkRendererBegin instead.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).
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
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.
Deferrable Update for closure/callback updates that should use auto-commit mode.
sendMail($subject, $body, $from=null, $replyto=null)
Send an e-mail to this user's account.
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.
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
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.
either a unescaped string or a HtmlArmor object 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"<
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? ...
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.
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
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 IP 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 newGood($value=null)
Factory function for good results.
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, options, and fallback DB index 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.
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.
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.
static addUpdate(DeferrableUpdate $update, $stage=self::POSTSEND)
Add an update to the deferred list to be run later by execute()
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
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?
static addCallableUpdate($callable, $stage=self::POSTSEND, IDatabase $dbw=null)
Add a callable update.
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.
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
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
static makeTitle($ns, $title, $fragment= '', $interwiki= '')
Create a new Title from a namespace index and a DB key.
if($wgRCFilterByAge) $wgDefaultUserOptions['rcdays']
static $mCacheVars
Array of Strings List of member variables which are saved to the shared cache (memcached).
see documentation in includes Linker php for Linker::makeImageLink & $time
static getGroupsWithPermission($role)
Get all the groups who have a given permission.
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