MediaWiki master
User.php
Go to the documentation of this file.
1<?php
7namespace MediaWiki\User;
8
9use AllowDynamicProperties;
10use ArrayIterator;
11use BadMethodCallException;
12use InvalidArgumentException;
19use MediaWiki\DAO\WikiAwareEntityTrait;
22use MediaWiki\HookContainer\ProtectedHookAccessorTrait;
28use MediaWiki\MainConfigSchema;
45use MWCryptHash;
46use RuntimeException;
47use stdClass;
48use Stringable;
49use UnexpectedValueException;
50use Wikimedia\Assert\Assert;
51use Wikimedia\Assert\PreconditionException;
52use Wikimedia\DebugInfo\DebugInfoTrait;
53use Wikimedia\IPUtils;
62use Wikimedia\ScopedCallback;
63use Wikimedia\Timestamp\ConvertibleTimestamp;
64use Wikimedia\Timestamp\TimestampFormat as TS;
65
129#[AllowDynamicProperties]
130class User implements Stringable, Authority, UserIdentity, UserEmailContact {
131 use DebugInfoTrait;
132 use ProtectedHookAccessorTrait;
133 use WikiAwareEntityTrait;
134
138 public const READ_EXCLUSIVE = IDBAccessObject::READ_EXCLUSIVE;
139
143 public const READ_LOCKING = IDBAccessObject::READ_LOCKING;
144
148 public const TOKEN_LENGTH = 32;
149
153 public const INVALID_TOKEN = '*** INVALID ***';
154
159 private const VERSION = 18;
160
165 public const MAINTENANCE_SCRIPT_USER = 'Maintenance script';
166
174 protected static $mCacheVars = [
175 // user table
176 'mId',
177 'mName',
178 'mRealName',
179 'mEmail',
180 'mTouched',
181 'mToken',
182 'mEmailAuthenticated',
183 'mEmailToken',
184 'mEmailTokenExpires',
185 // actor table
186 'mActorId',
187 ];
188
190 // Some of these are public, including for use by the UserFactory, but they generally
191 // should not be set manually
192 // @{
194 public $mId;
196 public $mName;
202 public $mActorId;
205
207 public $mEmail;
209 public $mTouched;
211 protected $mQuickTouched;
213 protected $mToken;
217 protected $mEmailToken;
220 // @}
221
222 // @{
226 protected $mLoadedItems = [];
227 // @}
228
239 public $mFrom;
240
247 protected $mGlobalBlock;
249 protected $mLocked;
250
252 private $mRequest;
253
255 protected $queryFlagsUsed = IDBAccessObject::READ_NORMAL;
256
261 private $mThisAsAuthority;
262
264 private $isTemp;
265
278 public function __construct() {
279 // By default, this is a lightweight constructor representing
280 // an anonymous user from the current web request and IP.
281 $this->clearInstanceCache( 'defaults' );
282 }
283
289 public function getWikiId(): string|false {
290 return self::LOCAL;
291 }
292
296 public function __toString() {
297 return $this->getName();
298 }
299
300 public function &__get( $name ) {
301 // A shortcut for $mRights deprecation phase
302 if ( $name === 'mRights' ) {
303 // hard deprecated since 1.40
304 wfDeprecated( 'User::$mRights', '1.34' );
306 ->getPermissionManager()
307 ->getUserPermissions( $this );
308 return $copy;
309 } elseif ( !property_exists( $this, $name ) ) {
310 // T227688 - do not break $u->foo['bar'] = 1
311 wfLogWarning( 'tried to get non-existent property' );
312 $this->$name = null;
313 return $this->$name;
314 } else {
315 wfLogWarning( 'tried to get non-visible property' );
316 $null = null;
317 return $null;
318 }
319 }
320
321 public function __set( $name, $value ) {
322 // A shortcut for $mRights deprecation phase, only known legitimate use was for
323 // testing purposes, other uses seem bad in principle
324 if ( $name === 'mRights' ) {
325 // hard deprecated since 1.40
326 wfDeprecated( 'User::$mRights', '1.34' );
327 MediaWikiServices::getInstance()->getPermissionManager()->overrideUserRightsForTesting(
328 $this,
329 $value ?? []
330 );
331 } elseif ( !property_exists( $this, $name ) ) {
332 $this->$name = $value;
333 } else {
334 wfLogWarning( 'tried to set non-visible property' );
335 }
336 }
337
338 public function __sleep(): array {
339 return array_diff(
340 array_keys( get_object_vars( $this ) ),
341 [
342 'mThisAsAuthority', // memoization, will be recreated on demand.
343 'mRequest', // contains Session, reloaded when needed, T400549
344 ]
345 );
346 }
347
362 public function isSafeToLoad() {
363 global $wgFullyInitialised;
364
365 // The user is safe to load if:
366 // * MW_NO_SESSION is undefined AND $wgFullyInitialised is true (safe to use session data)
367 // * mLoadedItems === true (already loaded)
368 // * mFrom !== 'session' (sessions not involved at all)
369
370 return ( !defined( 'MW_NO_SESSION' ) && $wgFullyInitialised ) ||
371 $this->mLoadedItems === true || $this->mFrom !== 'session';
372 }
373
379 public function load( $flags = IDBAccessObject::READ_NORMAL ) {
380 global $wgFullyInitialised;
381
382 if ( $this->mLoadedItems === true ) {
383 return;
384 }
385
386 // Set it now to avoid infinite recursion in accessors
387 $oldLoadedItems = $this->mLoadedItems;
388 $this->mLoadedItems = true;
389 $this->queryFlagsUsed = $flags;
390
391 // If this is called too early, things are likely to break.
392 if ( !$wgFullyInitialised && $this->mFrom === 'session' ) {
393 LoggerFactory::getInstance( 'session' )
394 ->warning( 'User::loadFromSession called before the end of Setup.php', [
395 'userId' => $this->mId,
396 'userName' => $this->mName,
397 'exception' => new RuntimeException(
398 'User::loadFromSession called before the end of Setup.php'
399 ),
400 ] );
401 $this->loadDefaults();
402 $this->mLoadedItems = $oldLoadedItems;
403 return;
404 } elseif ( $this->mFrom === 'session'
405 && defined( 'MW_NO_SESSION' ) && MW_NO_SESSION !== 'warn'
406 ) {
407 // Even though we are throwing an exception, make sure the User object is left in a
408 // clean state as sometimes these exceptions are caught and the object accessed again.
409 $this->loadDefaults();
410 $this->mLoadedItems = $oldLoadedItems;
411 $ep = defined( 'MW_ENTRY_POINT' ) ? MW_ENTRY_POINT : 'this';
412 throw new BadMethodCallException( "Sessions are disabled for $ep entry point" );
413 }
414
415 switch ( $this->mFrom ) {
416 case 'defaults':
417 $this->loadDefaults();
418 break;
419 case 'id':
420 // Make sure this thread sees its own changes, if the ID isn't 0
421 if ( $this->mId != 0 ) {
422 $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
423 if ( $lb->hasOrMadeRecentPrimaryChanges() ) {
424 $flags |= IDBAccessObject::READ_LATEST;
425 $this->queryFlagsUsed = $flags;
426 }
427 }
428
429 $this->loadFromId( $flags );
430 break;
431 case 'actor':
432 case 'name':
433 // Make sure this thread sees its own changes
434 $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
435 if ( $lb->hasOrMadeRecentPrimaryChanges() ) {
436 $flags |= IDBAccessObject::READ_LATEST;
437 $this->queryFlagsUsed = $flags;
438 }
439
440 $dbr = DBAccessObjectUtils::getDBFromRecency(
441 MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
442 $flags
443 );
444 $queryBuilder = $dbr->newSelectQueryBuilder()
445 ->select( [ 'actor_id', 'actor_user', 'actor_name' ] )
446 ->from( 'actor' )
447 ->recency( $flags );
448 if ( $this->mFrom === 'name' ) {
449 // make sure to use normalized form of IP for anonymous users
450 $queryBuilder->where( [ 'actor_name' => IPUtils::sanitizeIP( $this->mName ) ] );
451 } else {
452 $queryBuilder->where( [ 'actor_id' => $this->mActorId ] );
453 }
454 $row = $queryBuilder->caller( __METHOD__ )->fetchRow();
455
456 if ( !$row ) {
457 // Ugh.
458 $this->loadDefaults( $this->mFrom === 'name' ? $this->mName : false );
459 } elseif ( $row->actor_user ) {
460 $this->mId = $row->actor_user;
461 $this->loadFromId( $flags );
462 } else {
463 $this->loadDefaults( $row->actor_name, $row->actor_id );
464 }
465 break;
466 case 'session':
467 if ( !$this->loadFromSession() ) {
468 // Loading from session failed. Load defaults.
469 $this->loadDefaults();
470 }
471 $this->getHookRunner()->onUserLoadAfterLoadFromSession( $this );
472 break;
473 default:
474 throw new UnexpectedValueException(
475 "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
476 }
477 }
478
484 public function loadFromId( $flags = IDBAccessObject::READ_NORMAL ) {
485 if ( $this->mId == 0 ) {
486 // Anonymous users are not in the database (don't need cache)
487 $this->loadDefaults();
488 return false;
489 }
490
491 // Try cache (unless this needs data from the primary DB).
492 // NOTE: if this thread called saveSettings(), the cache was cleared.
493 $latest = DBAccessObjectUtils::hasFlags( $flags, IDBAccessObject::READ_LATEST );
494 if ( $latest ) {
495 if ( !$this->loadFromDatabase( $flags ) ) {
496 // Can't load from ID
497 return false;
498 }
499 } else {
500 $this->loadFromCache();
501 }
502
503 $this->mLoadedItems = true;
504 $this->queryFlagsUsed = $flags;
505
506 return true;
507 }
508
514 public static function purge( $dbDomain, $userId ) {
515 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
516 $key = $cache->makeGlobalKey( 'user', 'id', $dbDomain, $userId );
517 $cache->delete( $key );
518 }
519
525 protected function getCacheKey( WANObjectCache $cache ) {
526 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
527
528 return $cache->makeGlobalKey( 'user', 'id',
529 $lbFactory->getLocalDomainID(), $this->mId );
530 }
531
538 protected function loadFromCache() {
539 global $wgFullyInitialised;
540
541 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
542 $data = $cache->getWithSetCallback(
543 $this->getCacheKey( $cache ),
544 $cache::TTL_HOUR,
545 function ( $oldValue, &$ttl, array &$setOpts ) use ( $cache, $wgFullyInitialised ) {
546 $setOpts += Database::getCacheSetOptions(
547 MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase()
548 );
549 wfDebug( "User: cache miss for user {$this->mId}" );
550
551 $this->loadFromDatabase( IDBAccessObject::READ_NORMAL );
552
553 $data = [];
554 foreach ( self::$mCacheVars as $name ) {
555 $data[$name] = $this->$name;
556 }
557
558 $ttl = $cache->adaptiveTTL(
559 (int)wfTimestamp( TS::UNIX, $this->mTouched ),
560 $ttl
561 );
562
563 if ( $wgFullyInitialised ) {
564 $groupMemberships = MediaWikiServices::getInstance()
565 ->getUserGroupManager()
566 ->getUserGroupMemberships( $this, $this->queryFlagsUsed );
567
568 // if a user group membership is about to expire, the cache needs to
569 // expire at that time (T163691)
570 foreach ( $groupMemberships as $ugm ) {
571 if ( $ugm->getExpiry() ) {
572 $secondsUntilExpiry =
573 (int)wfTimestamp( TS::UNIX, $ugm->getExpiry() ) - time();
574
575 if ( $secondsUntilExpiry > 0 && $secondsUntilExpiry < $ttl ) {
576 $ttl = $secondsUntilExpiry;
577 }
578 }
579 }
580 }
581
582 return $data;
583 },
584 [ 'pcTTL' => $cache::TTL_PROC_LONG, 'version' => self::VERSION ]
585 );
586
587 // Restore from cache
588 foreach ( self::$mCacheVars as $name ) {
589 $this->$name = $data[$name];
590 }
591
592 return true;
593 }
594
595 /***************************************************************************/
596 // region newFrom*() static factory methods
622 public static function newFromName( $name, $validate = 'valid' ) {
623 // Backwards compatibility with strings / false
624 $validation = match ( $validate ) {
625 'valid' => UserRigorOptions::RIGOR_VALID,
626 'usable' => UserRigorOptions::RIGOR_USABLE,
627 'creatable' => UserRigorOptions::RIGOR_CREATABLE,
628 true => UserRigorOptions::RIGOR_VALID,
629 false => UserRigorOptions::RIGOR_NONE,
630 // Not a recognized value, probably a test for unsupported validation
631 // levels, regardless, just pass it along
632 default => $validate,
633 };
634 return MediaWikiServices::getInstance()->getUserFactory()
635 ->newFromName( (string)$name, $validation ) ?? false;
636 }
637
648 public static function newFromId( $id ) {
649 return MediaWikiServices::getInstance()
650 ->getUserFactory()
651 ->newFromId( (int)$id );
652 }
653
665 public static function newFromActorId( $id ) {
666 return MediaWikiServices::getInstance()
667 ->getUserFactory()
668 ->newFromActorId( (int)$id );
669 }
670
684 public static function newFromIdentity( UserIdentity $identity ) {
685 // Don't use the service if we already have a User object,
686 // so that User::newFromIdentity calls don't break things in unit tests.
687 if ( $identity instanceof User ) {
688 return $identity;
689 }
690
691 return MediaWikiServices::getInstance()
692 ->getUserFactory()
693 ->newFromUserIdentity( $identity );
694 }
695
714 public static function newFromAnyId( $userId, $userName, $actorId, $dbDomain = false ) {
715 return MediaWikiServices::getInstance()
716 ->getUserFactory()
717 ->newFromAnyId( $userId, $userName, $actorId, $dbDomain );
718 }
719
735 public static function newFromConfirmationCode( $code, $flags = IDBAccessObject::READ_NORMAL ) {
736 return MediaWikiServices::getInstance()
737 ->getUserFactory()
738 ->newFromConfirmationCode( (string)$code, $flags );
739 }
740
748 public static function newFromSession( ?WebRequest $request = null ) {
749 $user = new User;
750 $user->mFrom = 'session';
751 $user->mRequest = $request;
752 return $user;
753 }
754
770 public static function newFromRow( $row, $data = null ) {
771 $user = new User;
772 $user->loadFromRow( $row, $data );
773 return $user;
774 }
775
820 public static function newSystemUser( $name, $options = [] ) {
821 $options += [
822 'validate' => UserRigorOptions::RIGOR_VALID,
823 'create' => true,
824 'steal' => false,
825 ];
826
827 // Username validation
828 $validate = $options['validate'];
829 // Backwards compatibility with strings / false
830 $validation = match ( $validate ) {
831 'valid' => UserRigorOptions::RIGOR_VALID,
832 'usable' => UserRigorOptions::RIGOR_USABLE,
833 'creatable' => UserRigorOptions::RIGOR_CREATABLE,
834 false => UserRigorOptions::RIGOR_NONE,
835 // Not a recognized value, probably a test for unsupported validation
836 // levels, regardless, just pass it along
837 default => $validate,
838 };
839
840 if ( $validation !== UserRigorOptions::RIGOR_VALID ) {
842 __METHOD__ . ' options["validation"] parameter must be omitted or set to "valid".',
843 '1.36'
844 );
845 }
846 $services = MediaWikiServices::getInstance();
847 $userNameUtils = $services->getUserNameUtils();
848
849 $name = $userNameUtils->getCanonical( (string)$name, $validation );
850 if ( $name === false ) {
851 return null;
852 }
853
854 $dbProvider = $services->getDBLoadBalancerFactory();
855 $dbr = $dbProvider->getReplicaDatabase();
856
857 $userQuery = self::newQueryBuilder( $dbr )
858 ->where( [ 'user_name' => $name ] )
859 ->caller( __METHOD__ );
860 $row = $userQuery->fetchRow();
861 if ( !$row ) {
862 // Try the primary database
863 $userQuery->connection( $dbProvider->getPrimaryDatabase() );
864 // Lock the row to prevent insertNewUser() returning null due to race conditions
865 $userQuery->forUpdate();
866 $row = $userQuery->fetchRow();
867 }
868
869 if ( !$row ) {
870 // No user. Create it?
871 if ( !$options['create'] ) {
872 // No.
873 return null;
874 }
875
876 // If it's a reserved user that had an anonymous actor created for it at
877 // some point, we need special handling.
878 return self::insertNewUser( static function ( UserIdentity $actor, IDatabase $dbw ) {
879 return MediaWikiServices::getInstance()->getActorStore()
880 ->acquireSystemActorId( $actor, $dbw );
881 }, $name, [ 'token' => self::INVALID_TOKEN ] );
882 }
883
884 $user = self::newFromRow( $row );
885
886 if ( !$user->isSystemUser() ) {
887 // User exists. Steal it?
888 if ( !$options['steal'] ) {
889 return null;
890 }
891
892 $services->getAuthManager()->revokeAccessForUser( $name );
893
894 $user->invalidateEmail();
895 $user->mToken = self::INVALID_TOKEN;
896 $user->saveSettings();
897 $manager = $services->getSessionManager();
898 if ( $manager instanceof SessionManager ) {
899 $manager->preventSessionsForUser( $user->getName() );
900 }
901 }
902
903 return $user;
904 }
905
907 // endregion -- end of newFrom*() static factory methods
908
919 public static function findUsersByGroup( $groups, $limit = 5000, $after = null ) {
920 if ( $groups === [] ) {
921 return UserArrayFromResult::newFromIDs( [] );
922 }
923 $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
924 $queryBuilder = $dbr->newSelectQueryBuilder()
925 ->select( 'ug_user' )
926 ->distinct()
927 ->from( 'user_groups' )
928 ->where( [ 'ug_group' => array_unique( (array)$groups ) ] )
929 ->orderBy( 'ug_user' )
930 ->limit( min( 5000, $limit ) );
931
932 if ( $after !== null ) {
933 $queryBuilder->andWhere( $dbr->expr( 'ug_user', '>', (int)$after ) );
934 }
935
936 $ids = $queryBuilder->caller( __METHOD__ )->fetchFieldValues() ?: [];
937 return UserArray::newFromIDs( $ids );
938 }
939
946 public function isValidPassword( $password ) {
947 // simple boolean wrapper for checkPasswordValidity
948 return $this->checkPasswordValidity( $password )->isGood();
949 }
950
972 public function checkPasswordValidity( $password ) {
973 $services = MediaWikiServices::getInstance();
974 $userNameUtils = $services->getUserNameUtils();
975 if ( $userNameUtils->isTemp( $this->getName() ) ) {
976 return Status::newFatal( 'error-temporary-accounts-cannot-have-passwords' );
977 }
978
979 $passwordPolicy = $services->getMainConfig()->get( MainConfigNames::PasswordPolicy );
980
981 $upp = new UserPasswordPolicy(
982 $passwordPolicy['policies'],
983 $passwordPolicy['checks']
984 );
985
986 $status = Status::newGood( [] );
987 $result = false; // init $result to false for the internal checks
988
989 if ( !$this->getHookRunner()->onIsValidPassword( $password, $result, $this ) ) {
990 $status->error( $result );
991 return $status;
992 }
993
994 if ( $result === false ) {
995 $status->merge( $upp->checkUserPassword( $this, $password ), true );
996 return $status;
997 }
998
999 if ( $result === true ) {
1000 return $status;
1001 }
1002
1003 $status->error( $result );
1004 return $status; // the isValidPassword hook set a string $result and returned true
1005 }
1006
1016 public function loadDefaults( $name = false, $actorId = null ) {
1017 $this->mId = 0;
1018 $this->mName = $name;
1019 $this->mActorId = $actorId;
1020 $this->mRealName = '';
1021 $this->mEmail = '';
1022 $this->isTemp = null;
1023
1024 $loggedOut = $this->mRequest && !defined( 'MW_NO_SESSION' )
1025 ? $this->mRequest->getSession()->getLoggedOutTimestamp() : 0;
1026 if ( $loggedOut !== 0 ) {
1027 $this->mTouched = wfTimestamp( TS::MW, $loggedOut );
1028 } else {
1029 $this->mTouched = '1'; # Allow any pages to be cached
1030 }
1031
1032 $this->mToken = null; // Don't run cryptographic functions till we need a token
1033 $this->mEmailAuthenticated = null;
1034 $this->mEmailToken = '';
1035 $this->mEmailTokenExpires = null;
1036
1037 $this->getHookRunner()->onUserLoadDefaults( $this, $name );
1038 }
1039
1052 public function isItemLoaded( $item, $all = 'all' ) {
1053 return ( $this->mLoadedItems === true && $all === 'all' ) ||
1054 ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] === true );
1055 }
1056
1064 public function setItemLoaded( $item ) {
1065 if ( is_array( $this->mLoadedItems ) ) {
1066 $this->mLoadedItems[$item] = true;
1067 }
1068 }
1069
1075 private function loadFromSession() {
1076 // MediaWiki\Session\Session already did the necessary authentication of the user
1077 // returned here, so just use it if applicable.
1078 $session = $this->getRequest()->getSession();
1079 $user = $session->getUser();
1080 if ( $user->isRegistered() ) {
1081 $this->loadFromUserObject( $user );
1082
1083 // Other code expects these to be set in the session, so set them.
1084 $session->set( 'wsUserID', $this->getId() );
1085 $session->set( 'wsUserName', $this->getName() );
1086 $session->set( 'wsToken', $this->getToken() );
1087
1088 return true;
1089 }
1090
1091 return false;
1092 }
1093
1101 public function loadFromDatabase( $flags = IDBAccessObject::READ_LATEST ) {
1102 // Paranoia
1103 $this->mId = intval( $this->mId );
1104
1105 if ( !$this->mId ) {
1106 // Anonymous users are not in the database
1107 $this->loadDefaults();
1108 return false;
1109 }
1110
1111 $db = DBAccessObjectUtils::getDBFromRecency(
1112 MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
1113 $flags
1114 );
1115 $row = self::newQueryBuilder( $db )
1116 ->where( [ 'user_id' => $this->mId ] )
1117 ->recency( $flags )
1118 ->caller( __METHOD__ )
1119 ->fetchRow();
1120
1121 $this->queryFlagsUsed = $flags;
1122
1123 if ( $row !== false ) {
1124 // Initialise user table data
1125 $this->loadFromRow( $row );
1126 return true;
1127 }
1128
1129 // Invalid user_id
1130 $this->mId = 0;
1131 $this->loadDefaults( 'Unknown user' );
1132
1133 return false;
1134 }
1135
1147 protected function loadFromRow( $row, $data = null ) {
1148 if ( !( $row instanceof stdClass ) ) {
1149 throw new InvalidArgumentException( '$row must be an object' );
1150 }
1151
1152 $all = true;
1153
1154 if ( isset( $row->actor_id ) ) {
1155 $this->mActorId = (int)$row->actor_id;
1156 if ( $this->mActorId !== 0 ) {
1157 $this->mFrom = 'actor';
1158 }
1159 $this->setItemLoaded( 'actor' );
1160 } else {
1161 $all = false;
1162 }
1163
1164 if ( isset( $row->user_name ) && $row->user_name !== '' ) {
1165 $this->mName = $row->user_name;
1166 $this->mFrom = 'name';
1167 $this->setItemLoaded( 'name' );
1168 } else {
1169 $all = false;
1170 }
1171
1172 if ( isset( $row->user_real_name ) ) {
1173 $this->mRealName = $row->user_real_name;
1174 $this->setItemLoaded( 'realname' );
1175 } else {
1176 $all = false;
1177 }
1178
1179 if ( isset( $row->user_id ) ) {
1180 $this->mId = intval( $row->user_id );
1181 if ( $this->mId !== 0 ) {
1182 $this->mFrom = 'id';
1183 }
1184 $this->setItemLoaded( 'id' );
1185 } else {
1186 $all = false;
1187 }
1188
1189 if ( isset( $row->user_editcount ) ) {
1190 // Don't try to set edit count for anonymous users
1191 // We check the id here and not in UserEditTracker because calling
1192 // User::getId() can trigger some other loading. This will result in
1193 // discarding the user_editcount field for rows if the id wasn't set.
1194 if ( $this->mId !== null && $this->mId !== 0 ) {
1195 MediaWikiServices::getInstance()
1196 ->getUserEditTracker()
1197 ->setCachedUserEditCount( $this, (int)$row->user_editcount );
1198 }
1199 } else {
1200 $all = false;
1201 }
1202
1203 if ( isset( $row->user_touched ) ) {
1204 $this->mTouched = wfTimestamp( TS::MW, $row->user_touched );
1205 } else {
1206 $all = false;
1207 }
1208
1209 if ( isset( $row->user_token ) ) {
1210 // The definition for the column is binary(32), so trim the NULs
1211 // that appends. The previous definition was char(32), so trim
1212 // spaces too.
1213 $this->mToken = rtrim( $row->user_token, " \0" );
1214 if ( $this->mToken === '' ) {
1215 $this->mToken = null;
1216 }
1217 } else {
1218 $all = false;
1219 }
1220
1221 if ( isset( $row->user_email ) ) {
1222 $this->mEmail = $row->user_email;
1223 $this->mEmailAuthenticated = wfTimestampOrNull( TS::MW, $row->user_email_authenticated );
1224 $this->mEmailToken = $row->user_email_token;
1225 $this->mEmailTokenExpires = wfTimestampOrNull( TS::MW, $row->user_email_token_expires );
1226 $registration = wfTimestampOrNull( TS::MW, $row->user_registration );
1227 MediaWikiServices::getInstance()
1228 ->getUserRegistrationLookup()
1229 ->setCachedRegistration( $this, $registration );
1230 } else {
1231 $all = false;
1232 }
1233
1234 if ( $all ) {
1235 $this->mLoadedItems = true;
1236 }
1237
1238 if ( is_array( $data ) ) {
1239
1240 if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) {
1241 MediaWikiServices::getInstance()
1242 ->getUserGroupManager()
1243 ->loadGroupMembershipsFromArray(
1244 $this,
1245 $data['user_groups'],
1246 $this->queryFlagsUsed
1247 );
1248 }
1249 }
1250 }
1251
1257 protected function loadFromUserObject( $user ) {
1258 $user->load();
1259 foreach ( self::$mCacheVars as $var ) {
1260 $this->$var = $user->$var;
1261 }
1262 }
1263
1271 protected function makeUpdateConditions( IReadableDatabase $db ) {
1272 if ( $this->mTouched ) {
1273 // CAS check: only update if the row wasn't changed since it was loaded.
1274 return [ 'user_touched' => $db->timestamp( $this->mTouched ) ];
1275 }
1276 return [];
1277 }
1278
1289 public function checkAndSetTouched() {
1290 $this->load();
1291
1292 if ( !$this->mId ) {
1293 return false; // anon
1294 }
1295
1296 // Get a new user_touched that is higher than the old one
1297 $newTouched = $this->newTouchedTimestamp();
1298
1299 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
1300 $dbw->newUpdateQueryBuilder()
1301 ->update( 'user' )
1302 ->set( [ 'user_touched' => $dbw->timestamp( $newTouched ) ] )
1303 ->where( [ 'user_id' => $this->mId ] )
1304 ->andWhere( $this->makeUpdateConditions( $dbw ) )
1305 ->caller( __METHOD__ )->execute();
1306 $success = ( $dbw->affectedRows() > 0 );
1307
1308 if ( $success ) {
1309 $this->mTouched = $newTouched;
1310 $this->clearSharedCache( 'changed' );
1311 } else {
1312 // Clears on failure too since that is desired if the cache is stale
1313 $this->clearSharedCache( 'refresh' );
1314 }
1315
1316 return $success;
1317 }
1318
1326 public function clearInstanceCache( $reloadFrom = false ) {
1327 global $wgFullyInitialised;
1328
1329 $this->mDatePreference = null;
1330 $this->mThisAsAuthority = null;
1331
1332 if ( $wgFullyInitialised && $this->mFrom ) {
1333 $services = MediaWikiServices::getInstance();
1334
1335 if ( $services->peekService( 'PermissionManager' ) ) {
1336 $services->getPermissionManager()->invalidateUsersRightsCache( $this );
1337 }
1338
1339 if ( $services->peekService( 'UserOptionsManager' ) ) {
1340 $services->getUserOptionsManager()->clearUserOptionsCache( $this );
1341 }
1342
1343 if ( $services->peekService( 'TalkPageNotificationManager' ) ) {
1344 $services->getTalkPageNotificationManager()->clearInstanceCache( $this );
1345 }
1346
1347 if ( $services->peekService( 'UserGroupManager' ) ) {
1348 $services->getUserGroupManager()->clearCache( $this );
1349 }
1350
1351 if ( $services->peekService( 'UserEditTracker' ) ) {
1352 $services->getUserEditTracker()->clearUserEditCache( $this );
1353 }
1354
1355 if ( $services->peekService( 'BlockManager' ) ) {
1356 $services->getBlockManager()->clearUserCache( $this );
1357 }
1358 }
1359
1360 if ( $reloadFrom ) {
1361 if ( in_array( $reloadFrom, [ 'name', 'id', 'actor' ] ) ) {
1362 $this->mLoadedItems = [ $reloadFrom => true ];
1363 } else {
1364 $this->mLoadedItems = [];
1365 }
1366 $this->mFrom = $reloadFrom;
1367 }
1368 }
1369
1375 public function isPingLimitable() {
1376 $limiter = MediaWikiServices::getInstance()->getRateLimiter();
1377 $subject = $this->toRateLimitSubject();
1378 return !$limiter->isExempt( $subject );
1379 }
1380
1396 public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
1397 return $this->getThisAsAuthority()->limit( $action, $incrBy, null );
1398 }
1399
1405 $flags = [
1406 'exempt' => $this->isAllowed( 'noratelimit' ),
1407 'newbie' => $this->isNewbie(),
1408 ];
1409
1410 return new RateLimitSubject( $this, $this->getRequest()->getIP(), $flags );
1411 }
1412
1425 public function getBlock(
1426 $freshness = IDBAccessObject::READ_NORMAL,
1427 $disableIpBlockExemptChecking = false
1428 ): ?Block {
1429 if ( is_bool( $freshness ) ) {
1430 $fromReplica = $freshness;
1431 } else {
1432 $fromReplica = ( $freshness !== IDBAccessObject::READ_LATEST );
1433 }
1434
1435 if ( $disableIpBlockExemptChecking ) {
1436 $isExempt = false;
1437 } else {
1438 $isExempt = $this->isAllowed( 'ipblock-exempt' );
1439 }
1440
1441 // TODO: Block checking shouldn't really be done from the User object. Block
1442 // checking can involve checking for IP blocks, cookie blocks, and/or XFF blocks,
1443 // which need more knowledge of the request context than the User should have.
1444 // Since we do currently check blocks from the User, we have to do the following
1445 // here:
1446 // - Check if this is the user associated with the main request
1447 // - If so, pass the relevant request information to the block manager
1448 $request = null;
1449 if ( !$isExempt && $this->isGlobalSessionUser() ) {
1450 // This is the global user, so we need to pass the request
1451 $request = $this->getRequest();
1452 }
1453
1454 return MediaWikiServices::getInstance()->getBlockManager()->getBlock(
1455 $this,
1456 $request,
1457 $fromReplica,
1458 );
1459 }
1460
1466 public function isLocked() {
1467 if ( $this->mLocked !== null ) {
1468 return $this->mLocked;
1469 }
1470 // Reset for hook
1471 $this->mLocked = false;
1472 $this->getHookRunner()->onUserIsLocked( $this, $this->mLocked );
1473 return $this->mLocked;
1474 }
1475
1481 public function isHidden() {
1482 $block = $this->getBlock();
1483 return $block ? $block->getHideName() : false;
1484 }
1485
1491 public function getId( $wikiId = self::LOCAL ): int {
1492 $this->assertWiki( $wikiId );
1493 if ( $this->mId === null && $this->mName !== null ) {
1494 $userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils();
1495 if ( $userNameUtils->isIP( $this->mName ) || ExternalUserNames::isExternal( $this->mName ) ) {
1496 // Special case, we know the user is anonymous
1497 // Note that "external" users are "local" (they have an actor ID that is relative to
1498 // the local wiki).
1499 return 0;
1500 }
1501 }
1502
1503 if ( !$this->isItemLoaded( 'id' ) ) {
1504 // Don't load if this was initialized from an ID
1505 $this->load();
1506 }
1507
1508 return (int)$this->mId;
1509 }
1510
1515 public function setId( $v ) {
1516 $this->mId = $v;
1517 $this->clearInstanceCache( 'id' );
1518 }
1519
1524 public function getName(): string {
1525 if ( $this->isItemLoaded( 'name', 'only' ) ) {
1526 // Special case optimisation
1527 return $this->mName;
1528 }
1529
1530 $this->load();
1531 if ( $this->mName === false ) {
1532 // Clean up IPs
1533 $this->mName = IPUtils::sanitizeIP( $this->getRequest()->getIP() );
1534 }
1535
1536 return $this->mName;
1537 }
1538
1552 public function setName( $str ) {
1553 $this->load();
1554 $this->mName = $str;
1555 }
1556
1570 public function getActorId( $dbwOrWikiId = self::LOCAL ): int {
1571 if ( $dbwOrWikiId ) {
1572 wfDeprecatedMsg( 'Passing a parameter to getActorId() is deprecated', '1.36' );
1573 }
1574
1575 if ( is_string( $dbwOrWikiId ) ) {
1576 $this->assertWiki( $dbwOrWikiId );
1577 }
1578
1579 if ( !$this->isItemLoaded( 'actor' ) ) {
1580 $this->load();
1581 }
1582
1583 if ( !$this->mActorId && $dbwOrWikiId instanceof IDatabase ) {
1584 MediaWikiServices::getInstance()
1585 ->getActorStoreFactory()
1586 ->getActorNormalization( $dbwOrWikiId->getDomainID() )
1587 ->acquireActorId( $this, $dbwOrWikiId );
1588 // acquireActorId will call setActorId on $this
1589 Assert::postcondition(
1590 $this->mActorId !== null,
1591 "Failed to acquire actor ID for user id {$this->mId} name {$this->mName}"
1592 );
1593 }
1594
1595 return (int)$this->mActorId;
1596 }
1597
1607 public function setActorId( int $actorId ) {
1608 $this->mActorId = $actorId;
1609 $this->setItemLoaded( 'actor' );
1610 }
1611
1616 public function getTitleKey(): string {
1617 return str_replace( ' ', '_', $this->getName() );
1618 }
1619
1626 private function newTouchedTimestamp() {
1627 $time = (int)ConvertibleTimestamp::now( TS::UNIX );
1628 if ( $this->mTouched ) {
1629 $time = max( $time, (int)ConvertibleTimestamp::convert( TS::UNIX, $this->mTouched ) + 1 );
1630 }
1631
1632 return ConvertibleTimestamp::convert( TS::MW, $time );
1633 }
1634
1645 public function clearSharedCache( $mode = 'refresh' ) {
1646 if ( !$this->getId() ) {
1647 return;
1648 }
1649
1650 $dbProvider = MediaWikiServices::getInstance()->getConnectionProvider();
1651 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1652 $key = $this->getCacheKey( $cache );
1653
1654 if ( $mode === 'refresh' ) {
1655 $cache->delete( $key, 1 ); // low tombstone/"hold-off" TTL
1656 } else {
1657 $dbProvider->getPrimaryDatabase()->onTransactionPreCommitOrIdle(
1658 static function () use ( $cache, $key ) {
1659 $cache->delete( $key );
1660 },
1661 __METHOD__
1662 );
1663 }
1664 }
1665
1671 public function invalidateCache() {
1672 $this->touch();
1673 $this->clearSharedCache( 'changed' );
1674 }
1675
1688 public function touch() {
1689 $id = $this->getId();
1690 if ( $id ) {
1691 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1692 $key = $cache->makeKey( 'user-quicktouched', 'id', $id );
1693 $cache->touchCheckKey( $key );
1694 $this->mQuickTouched = null;
1695 }
1696 }
1697
1703 public function debouncedDBTouch() {
1704 $oldTouched = (int)ConvertibleTimestamp::convert( TS::UNIX, $this->getDBTouched() );
1705 $newTouched = (int)ConvertibleTimestamp::now( TS::UNIX );
1706
1707 if ( ( $newTouched - $oldTouched ) < ( 300 + mt_rand( 1, 20 ) ) ) {
1708 // Touched would be updated too soon, skip this round
1709 // Adding jitter to avoid stampede.
1710 return;
1711 }
1712
1713 // Too old, definitely update.
1714 $this->checkAndSetTouched();
1715 }
1716
1722 public function validateCache( $timestamp ) {
1723 return ( $timestamp >= $this->getTouched() );
1724 }
1725
1734 public function getTouched() {
1735 $this->load();
1736
1737 if ( $this->mId ) {
1738 if ( $this->mQuickTouched === null ) {
1739 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1740 $key = $cache->makeKey( 'user-quicktouched', 'id', $this->mId );
1741
1742 $this->mQuickTouched = wfTimestamp( TS::MW, $cache->getCheckKeyTime( $key ) );
1743 }
1744
1745 return max( $this->mTouched, $this->mQuickTouched );
1746 }
1747
1748 return $this->mTouched;
1749 }
1750
1756 public function getDBTouched() {
1757 $this->load();
1758
1759 return $this->mTouched;
1760 }
1761
1774 public function changeAuthenticationData( array $data ) {
1775 $manager = MediaWikiServices::getInstance()->getAuthManager();
1776 $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
1777 $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
1778
1779 $status = Status::newGood( 'ignored' );
1780 foreach ( $reqs as $req ) {
1781 $status->merge( $manager->allowsAuthenticationDataChange( $req ), true );
1782 }
1783 if ( $status->getValue() === 'ignored' ) {
1784 $status->warning( 'authenticationdatachange-ignored' );
1785 }
1786
1787 if ( $status->isGood() ) {
1788 foreach ( $reqs as $req ) {
1789 $manager->changeAuthenticationData( $req );
1790 }
1791 }
1792 return $status;
1793 }
1794
1801 public function getToken( $forceCreation = true ) {
1802 $authenticationTokenVersion = MediaWikiServices::getInstance()
1803 ->getMainConfig()->get( MainConfigNames::AuthenticationTokenVersion );
1804
1805 $this->load();
1806 if ( !$this->mToken && $forceCreation ) {
1807 $this->setToken();
1808 }
1809
1810 if ( !$this->mToken ) {
1811 // The user doesn't have a token, return null to indicate that.
1812 return null;
1813 }
1814
1815 if ( $this->mToken === self::INVALID_TOKEN ) {
1816 // We return a random value here so existing token checks are very
1817 // likely to fail.
1818 return MWCryptRand::generateHex( self::TOKEN_LENGTH );
1819 }
1820
1821 if ( $authenticationTokenVersion === null ) {
1822 // $wgAuthenticationTokenVersion not in use, so return the raw secret
1823 return $this->mToken;
1824 }
1825
1826 // $wgAuthenticationTokenVersion in use, so hmac it.
1827 $ret = MWCryptHash::hmac( $authenticationTokenVersion, $this->mToken, false );
1828
1829 // The raw hash can be overly long. Shorten it up.
1830 $len = max( 32, self::TOKEN_LENGTH );
1831 if ( strlen( $ret ) < $len ) {
1832 // Should never happen, even md5 is 128 bits
1833 throw new \UnexpectedValueException( 'Hmac returned less than 128 bits' );
1834 }
1835
1836 return substr( $ret, -$len );
1837 }
1838
1845 public function setToken( $token = false ) {
1846 $this->load();
1847 if ( $this->mToken === self::INVALID_TOKEN ) {
1848 LoggerFactory::getInstance( 'session' )
1849 ->debug( __METHOD__ . ": Ignoring attempt to set token for system user \"$this\"" );
1850 } elseif ( !$token ) {
1851 $this->mToken = MWCryptRand::generateHex( self::TOKEN_LENGTH );
1852 } else {
1853 $this->mToken = $token;
1854 }
1855 }
1856
1861 public function getEmail(): string {
1862 $this->load();
1863 $email = $this->mEmail;
1864 $this->getHookRunner()->onUserGetEmail( $this, $email );
1865 // In case a hook handler returns e.g. null
1866 $this->mEmail = is_string( $email ) ? $email : '';
1867 return $this->mEmail;
1868 }
1869
1875 $this->load();
1876 $this->getHookRunner()->onUserGetEmailAuthenticationTimestamp(
1877 $this, $this->mEmailAuthenticated );
1878 return $this->mEmailAuthenticated;
1879 }
1880
1885 public function setEmail( string $str ) {
1886 $this->load();
1887 if ( $str == $this->getEmail() ) {
1888 return;
1889 }
1890 $this->invalidateEmail();
1891 $this->mEmail = $str;
1892 $this->getHookRunner()->onUserSetEmail( $this, $this->mEmail );
1893 }
1894
1902 public function setEmailWithConfirmation( string $str ) {
1903 $config = MediaWikiServices::getInstance()->getMainConfig();
1904 $enableEmail = $config->get( MainConfigNames::EnableEmail );
1905
1906 if ( !$enableEmail ) {
1907 return Status::newFatal( 'emaildisabled' );
1908 }
1909
1910 $oldaddr = $this->getEmail();
1911 if ( $str === $oldaddr ) {
1912 return Status::newGood( true );
1913 }
1914
1915 $type = $oldaddr != '' ? 'changed' : 'set';
1916 $notificationResult = null;
1917
1918 $emailAuthentication = $config->get( MainConfigNames::EmailAuthentication );
1919
1920 if ( $emailAuthentication && $type === 'changed' && $this->isEmailConfirmed() ) {
1921 $change = $str != '' ? 'changed' : 'removed';
1922 $notificationResult = Status::wrap(
1923 MediaWikiServices::getInstance()->getNotificationEmailSender()->sendNotificationMail(
1924 RequestContext::getMain(),
1925 $this,
1926 $change,
1927 $str
1928 )
1929 );
1930 }
1931
1932 $this->setEmail( $str );
1933
1934 if ( $str !== '' && $emailAuthentication ) {
1935 // Send a confirmation request to the new address if needed
1936 $result = $this->sendConfirmationMail( $type );
1937
1938 if ( $notificationResult !== null ) {
1939 $result->merge( $notificationResult );
1940 }
1941
1942 if ( $result->isGood() ) {
1943 // Say to the caller that a confirmation and notification mail has been sent
1944 $result->value = 'eauth';
1945 }
1946 } else {
1947 $result = Status::newGood( true );
1948 }
1949
1950 return $result;
1951 }
1952
1957 public function getRealName(): string {
1958 if ( !$this->isItemLoaded( 'realname' ) ) {
1959 $this->load();
1960 }
1961
1962 return $this->mRealName;
1963 }
1964
1969 public function setRealName( string $str ) {
1970 $this->load();
1971 $this->mRealName = $str;
1972 }
1973
1984 public function getTokenFromOption( $oname ) {
1985 $hiddenPrefs =
1986 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::HiddenPrefs );
1987
1988 $id = $this->getId();
1989 if ( !$id || in_array( $oname, $hiddenPrefs ) ) {
1990 return false;
1991 }
1992
1993 $userOptionsLookup = MediaWikiServices::getInstance()
1994 ->getUserOptionsLookup();
1995 $token = $userOptionsLookup->getOption( $this, (string)$oname );
1996 if ( !$token ) {
1997 // Default to a value based on the user token to avoid space
1998 // wasted on storing tokens for all users. When this option
1999 // is set manually by the user, only then is it stored.
2000 $token = hash_hmac( 'sha1', "$oname:$id", $this->getToken() );
2001 }
2002
2003 return $token;
2004 }
2005
2015 public function resetTokenFromOption( $oname ) {
2016 $hiddenPrefs =
2017 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::HiddenPrefs );
2018 if ( in_array( $oname, $hiddenPrefs ) ) {
2019 return false;
2020 }
2021
2022 $token = MWCryptRand::generateHex( 40 );
2023 MediaWikiServices::getInstance()
2024 ->getUserOptionsManager()
2025 ->setOption( $this, $oname, $token );
2026 return $token;
2027 }
2028
2033 public function getDatePreference() {
2034 // Important migration for old data rows
2035 if ( $this->mDatePreference === null ) {
2036 global $wgLang;
2037 $userOptionsLookup = MediaWikiServices::getInstance()
2038 ->getUserOptionsLookup();
2039 $value = $userOptionsLookup->getOption( $this, 'date' ) ?? 'default';
2040 $map = $wgLang->getDatePreferenceMigrationMap();
2041 if ( isset( $map[$value] ) ) {
2042 $value = $map[$value];
2043 }
2044 $this->mDatePreference = $value;
2045 }
2046 return $this->mDatePreference;
2047 }
2048
2055 public function requiresHTTPS() {
2056 if ( !$this->isRegistered() ) {
2057 return false;
2058 }
2059
2060 $services = MediaWikiServices::getInstance();
2061 $config = $services->getMainConfig();
2062 if ( $config->get( MainConfigNames::ForceHTTPS ) ) {
2063 return true;
2064 }
2065 if ( !$config->get( MainConfigNames::SecureLogin ) ) {
2066 return false;
2067 }
2068 return $services->getUserOptionsLookup()
2069 ->getBoolOption( $this, 'prefershttps' );
2070 }
2071
2076 public function getEditCount() {
2077 return MediaWikiServices::getInstance()
2078 ->getUserEditTracker()
2079 ->getUserEditCount( $this );
2080 }
2081
2090 public function isRegistered(): bool {
2091 return $this->getId() != 0;
2092 }
2093
2098 public function isAnon() {
2099 return !$this->isRegistered();
2100 }
2101
2106 public function isBot() {
2107 $userGroupManager = MediaWikiServices::getInstance()->getUserGroupManager();
2108 if ( in_array( 'bot', $userGroupManager->getUserGroups( $this ) )
2109 && $this->isAllowed( 'bot' )
2110 ) {
2111 return true;
2112 }
2113
2114 $isBot = false;
2115 $this->getHookRunner()->onUserIsBot( $this, $isBot );
2116
2117 return $isBot;
2118 }
2119
2129 public function isSystemUser() {
2130 $this->load();
2131 if ( $this->getEmail() || $this->mToken !== self::INVALID_TOKEN ||
2132 MediaWikiServices::getInstance()->getAuthManager()->userCanAuthenticate( $this->mName )
2133 ) {
2134 return false;
2135 }
2136 return true;
2137 }
2138
2140 public function isAllowedAny( ...$permissions ): bool {
2141 return $this->getThisAsAuthority()->isAllowedAny( ...$permissions );
2142 }
2143
2145 public function isAllowedAll( ...$permissions ): bool {
2146 return $this->getThisAsAuthority()->isAllowedAll( ...$permissions );
2147 }
2148
2149 public function isAllowed( string $permission, ?PermissionStatus $status = null ): bool {
2150 return $this->getThisAsAuthority()->isAllowed( $permission, $status );
2151 }
2152
2157 public function useRCPatrol() {
2158 $useRCPatrol =
2159 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseRCPatrol );
2160 return $useRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
2161 }
2162
2167 public function useNPPatrol() {
2168 $useRCPatrol =
2169 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseRCPatrol );
2170 $useNPPatrol =
2171 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseNPPatrol );
2172 return (
2173 ( $useRCPatrol || $useNPPatrol )
2174 && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
2175 );
2176 }
2177
2182 public function useFilePatrol() {
2183 $useRCPatrol =
2184 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseRCPatrol );
2185 $useFilePatrol = MediaWikiServices::getInstance()->getMainConfig()
2186 ->get( MainConfigNames::UseFilePatrol );
2187 return (
2188 ( $useRCPatrol || $useFilePatrol )
2189 && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
2190 );
2191 }
2192
2196 public function getRequest(): WebRequest {
2197 return $this->mRequest ?? RequestContext::getMain()->getRequest();
2198 }
2199
2205 public function getExperienceLevel() {
2206 $mainConfig = MediaWikiServices::getInstance()->getMainConfig();
2207 $learnerEdits = $mainConfig->get( MainConfigNames::LearnerEdits );
2208 $experiencedUserEdits = $mainConfig->get( MainConfigNames::ExperiencedUserEdits );
2209 $learnerMemberSince = $mainConfig->get( MainConfigNames::LearnerMemberSince );
2210 $experiencedUserMemberSince =
2211 $mainConfig->get( MainConfigNames::ExperiencedUserMemberSince );
2212 if ( $this->isAnon() ) {
2213 return false;
2214 }
2215
2216 $editCount = $this->getEditCount();
2217 $registration = $this->getRegistration();
2218 $now = time();
2219 $learnerRegistration = wfTimestamp( TS::MW, $now - $learnerMemberSince * 86400 );
2220 $experiencedRegistration = wfTimestamp( TS::MW, $now - $experiencedUserMemberSince * 86400 );
2221 if ( $registration === null ) {
2222 // for some very old accounts, this information is missing in the database
2223 // treat them as old enough to be 'experienced'
2224 $registration = $experiencedRegistration;
2225 }
2226
2227 if ( $editCount < $learnerEdits ||
2228 $registration > $learnerRegistration ) {
2229 return 'newcomer';
2230 }
2231
2232 if ( $editCount > $experiencedUserEdits &&
2233 $registration <= $experiencedRegistration
2234 ) {
2235 return 'experienced';
2236 }
2237
2238 return 'learner';
2239 }
2240
2249 public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
2250 $this->load();
2251 if ( $this->mId == 0 ) {
2252 return;
2253 }
2254
2255 $session = $this->getRequest()->getSession();
2256 if ( $request && $session->getRequest() !== $request ) {
2257 $session = $session->sessionWithRequest( $request );
2258 }
2259 $delay = $session->delaySave();
2260
2261 if ( !$session->getUser()->equals( $this ) ) {
2262 if ( !$session->canSetUser() ) {
2263 LoggerFactory::getInstance( 'session' )
2264 ->warning( __METHOD__ .
2265 ": Cannot save user \"$this\" to a user " .
2266 "\"{$session->getUser()}\"'s immutable session"
2267 );
2268 return;
2269 }
2270 $session->setUser( $this );
2271 }
2272
2273 $session->setRememberUser( $rememberMe );
2274 if ( $secure !== null ) {
2275 $session->setForceHTTPS( $secure );
2276 }
2277
2278 $session->persist();
2279
2280 ScopedCallback::consume( $delay );
2281 }
2282
2286 public function logout() {
2287 if ( $this->getHookRunner()->onUserLogout( $this ) ) {
2288 $this->doLogout();
2289 }
2290 }
2291
2296 public function doLogout() {
2297 $session = $this->getRequest()->getSession();
2298 $accountType = MediaWikiServices::getInstance()->getUserIdentityUtils()->getShortUserTypeInternal( $this );
2299 if ( !$session->canSetUser() ) {
2300 LoggerFactory::getInstance( 'session' )
2301 ->warning( __METHOD__ . ": Cannot log out of an immutable session" );
2302 $error = 'immutable';
2303 } elseif ( !$session->getUser()->equals( $this ) ) {
2304 LoggerFactory::getInstance( 'session' )
2305 ->warning( __METHOD__ .
2306 ": Cannot log user \"$this\" out of a user \"{$session->getUser()}\"'s session"
2307 );
2308 // But we still may as well make this user object anon
2309 $this->clearInstanceCache( 'defaults' );
2310 $error = 'wronguser';
2311 } else {
2312 $this->clearInstanceCache( 'defaults' );
2313 $delay = $session->delaySave();
2314 $session->unpersist(); // Clear cookies (T127436)
2315 $session->setLoggedOutTimestamp( time() );
2316 $session->setUser( new User );
2317 $session->set( 'wsUserID', 0 ); // Other code expects this
2318 $session->resetAllTokens();
2319 ScopedCallback::consume( $delay );
2320 $error = false;
2321 }
2322 LoggerFactory::getInstance( 'authevents' )->info( 'Logout', [
2323 'event' => 'logout',
2324 'successful' => $error === false,
2325 'status' => $error ?: 'success',
2326 'accountType' => $accountType,
2327 ] );
2328 }
2329
2334 public function saveSettings() {
2335 if ( MediaWikiServices::getInstance()->getReadOnlyMode()->isReadOnly() ) {
2336 // @TODO: caller should deal with this instead!
2337 // This should really just be an exception.
2338 MWExceptionHandler::logException( new DBExpectedError(
2339 null,
2340 "Could not update user with ID '{$this->mId}'; DB is read-only."
2341 ) );
2342 return;
2343 }
2344
2345 $this->load();
2346 if ( $this->mId == 0 ) {
2347 return; // anon
2348 }
2349
2350 // Get a new user_touched that is higher than the old one.
2351 // This will be used for a CAS check as a last-resort safety
2352 // check against race conditions and replica DB lag.
2353 $newTouched = $this->newTouchedTimestamp();
2354
2355 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
2356 $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $newTouched ) {
2357 $dbw->newUpdateQueryBuilder()
2358 ->update( 'user' )
2359 ->set( [
2360 'user_name' => $this->mName,
2361 'user_real_name' => $this->mRealName,
2362 'user_email' => $this->mEmail,
2363 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
2364 'user_touched' => $dbw->timestamp( $newTouched ),
2365 'user_token' => strval( $this->mToken ),
2366 'user_email_token' => $this->mEmailToken,
2367 'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
2368 ] )
2369 ->where( [ 'user_id' => $this->mId ] )
2370 ->andWhere( $this->makeUpdateConditions( $dbw ) )
2371 ->caller( $fname )->execute();
2372
2373 if ( !$dbw->affectedRows() ) {
2374 // Maybe the problem was a missed cache update; clear it to be safe
2375 $this->clearSharedCache( 'refresh' );
2376 // User was changed in the meantime or loaded with stale data
2377 $from = ( $this->queryFlagsUsed & IDBAccessObject::READ_LATEST ) ? 'primary' : 'replica';
2378 LoggerFactory::getInstance( 'preferences' )->warning(
2379 "CAS update failed on user_touched for user ID '{user_id}' ({db_flag} read)",
2380 [ 'user_id' => $this->mId, 'db_flag' => $from ]
2381 );
2382 throw new RuntimeException( "CAS update failed on user_touched. " .
2383 "The version of the user to be saved is older than the current version."
2384 );
2385 }
2386
2387 $dbw->newUpdateQueryBuilder()
2388 ->update( 'actor' )
2389 ->set( [ 'actor_name' => $this->mName ] )
2390 ->where( [ 'actor_user' => $this->mId ] )
2391 ->caller( $fname )->execute();
2392 MediaWikiServices::getInstance()->getActorStore()->deleteUserIdentityFromCache( $this );
2393 } );
2394
2395 $this->mTouched = $newTouched;
2396 if ( $this->isNamed() ) {
2397 MediaWikiServices::getInstance()->getUserOptionsManager()->saveOptionsInternal( $this );
2398 }
2399
2400 $this->getHookRunner()->onUserSaveSettings( $this );
2401 $this->clearSharedCache( 'changed' );
2402 $hcu = MediaWikiServices::getInstance()->getHTMLCacheUpdater();
2403 $hcu->purgeTitleUrls( $this->getUserPage(), $hcu::PURGE_INTENT_TXROUND_REFLECTED );
2404 }
2405
2412 public function idForName( $flags = IDBAccessObject::READ_NORMAL ) {
2413 $s = trim( $this->getName() );
2414 if ( $s === '' ) {
2415 return 0;
2416 }
2417
2418 $db = DBAccessObjectUtils::getDBFromRecency(
2419 MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
2420 $flags
2421 );
2422 $id = $db->newSelectQueryBuilder()
2423 ->select( 'user_id' )
2424 ->from( 'user' )
2425 ->where( [ 'user_name' => $s ] )
2426 ->recency( $flags )
2427 ->caller( __METHOD__ )->fetchField();
2428
2429 return (int)$id;
2430 }
2431
2445 public static function createNew( $name, $params = [] ) {
2446 return self::insertNewUser( static function ( UserIdentity $actor, IDatabase $dbw ) {
2447 return MediaWikiServices::getInstance()->getActorStore()->createNewActor( $actor, $dbw );
2448 }, $name, $params );
2449 }
2450
2458 private static function insertNewUser( callable $insertActor, $name, $params = [] ) {
2459 foreach ( [ 'password', 'newpassword', 'newpass_time', 'password_expires' ] as $field ) {
2460 if ( isset( $params[$field] ) ) {
2461 wfDeprecated( __METHOD__ . " with param '$field'", '1.27' );
2462 unset( $params[$field] );
2463 }
2464 }
2465
2466 $user = new User;
2467 $user->load();
2468 $user->setToken(); // init token
2469 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
2470
2471 $noPass = PasswordFactory::newInvalidPassword()->toString();
2472
2473 $fields = [
2474 'user_name' => $name,
2475 'user_password' => $noPass,
2476 'user_newpassword' => $noPass,
2477 'user_email' => $user->mEmail,
2478 'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
2479 'user_real_name' => $user->mRealName,
2480 'user_token' => strval( $user->mToken ),
2481 'user_registration' => $dbw->timestamp(),
2482 'user_editcount' => 0,
2483 'user_touched' => $dbw->timestamp( $user->newTouchedTimestamp() ),
2484 ];
2485 foreach ( $params as $name => $value ) {
2486 $fields["user_$name"] = $value;
2487 }
2488
2489 return $dbw->doAtomicSection( __METHOD__, static function ( IDatabase $dbw, $fname )
2490 use ( $fields, $insertActor )
2491 {
2492 $dbw->newInsertQueryBuilder()
2493 ->insertInto( 'user' )
2494 ->ignore()
2495 ->row( $fields )
2496 ->caller( $fname )->execute();
2497 if ( $dbw->affectedRows() ) {
2498 $newUser = self::newFromId( $dbw->insertId() );
2499 $newUser->mName = $fields['user_name'];
2500 // Don't pass $this, since calling ::getId, ::getName might force ::load
2501 // and this user might not be ready for the yet.
2502 $newUser->mActorId = $insertActor(
2503 new UserIdentityValue( $newUser->mId, $newUser->mName ),
2504 $dbw
2505 );
2506 // Load the user from primary DB to avoid replica lag
2507 $newUser->load( IDBAccessObject::READ_LATEST );
2508 } else {
2509 $newUser = null;
2510 }
2511 return $newUser;
2512 } );
2513 }
2514
2540 public function addToDatabase() {
2541 $this->load();
2542 if ( !$this->mToken ) {
2543 $this->setToken(); // init token
2544 }
2545
2546 if ( !is_string( $this->mName ) ) {
2547 throw new RuntimeException( "User name field is not set." );
2548 }
2549
2550 $this->mTouched = $this->newTouchedTimestamp();
2551
2552 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
2553 $status = $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) {
2554 $noPass = PasswordFactory::newInvalidPassword()->toString();
2555 $dbw->newInsertQueryBuilder()
2556 ->insertInto( 'user' )
2557 ->ignore()
2558 ->row( [
2559 'user_name' => $this->mName,
2560 'user_password' => $noPass,
2561 'user_newpassword' => $noPass,
2562 'user_email' => $this->mEmail,
2563 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
2564 'user_real_name' => $this->mRealName,
2565 'user_token' => strval( $this->mToken ),
2566 'user_registration' => $dbw->timestamp(),
2567 'user_editcount' => 0,
2568 'user_touched' => $dbw->timestamp( $this->mTouched ),
2569 'user_is_temp' => $this->isTemp(),
2570 ] )
2571 ->caller( $fname )->execute();
2572 if ( !$dbw->affectedRows() ) {
2573 // Use locking reads to bypass any REPEATABLE-READ snapshot.
2574 $this->mId = $dbw->newSelectQueryBuilder()
2575 ->select( 'user_id' )
2576 ->lockInShareMode()
2577 ->from( 'user' )
2578 ->where( [ 'user_name' => $this->mName ] )
2579 ->caller( $fname )->fetchField();
2580 $loaded = false;
2581 if ( $this->mId && $this->loadFromDatabase( IDBAccessObject::READ_LOCKING ) ) {
2582 $loaded = true;
2583 }
2584 if ( !$loaded ) {
2585 throw new RuntimeException( $fname . ": hit a key conflict attempting " .
2586 "to insert user '{$this->mName}' row, but it was not present in select!" );
2587 }
2588 return Status::newFatal( 'userexists' );
2589 }
2590 $this->mId = $dbw->insertId();
2591 $this->queryFlagsUsed = IDBAccessObject::READ_LATEST;
2592
2593 // Don't pass $this, since calling ::getId, ::getName might force ::load
2594 // and this user might not be ready for that yet.
2595 $this->mActorId = MediaWikiServices::getInstance()
2596 ->getActorNormalization()
2597 ->acquireActorId( new UserIdentityValue( $this->mId, $this->mName ), $dbw );
2598 return Status::newGood();
2599 } );
2600 if ( !$status->isGood() ) {
2601 return $status;
2602 }
2603
2604 // Clear instance cache other than user table data and actor, which is already accurate
2605 $this->clearInstanceCache();
2606
2607 if ( $this->isNamed() ) {
2608 MediaWikiServices::getInstance()->getUserOptionsManager()->saveOptions( $this );
2609 }
2610 return Status::newGood();
2611 }
2612
2619 public function scheduleSpreadBlock() {
2620 DeferredUpdates::addCallableUpdate( function () {
2621 // Permit master queries in a GET request
2622 $scope = Profiler::instance()->getTransactionProfiler()->silenceForScope();
2623 $this->spreadAnyEditBlock();
2624 ScopedCallback::consume( $scope );
2625 } );
2626 }
2627
2634 public function spreadAnyEditBlock() {
2635 if ( !$this->isRegistered() ) {
2636 return false;
2637 }
2638
2639 $blockWasSpread = false;
2640 $this->getHookRunner()->onSpreadAnyEditBlock( $this, $blockWasSpread );
2641
2642 $block = $this->getBlock();
2643 if ( $block ) {
2644 $blockWasSpread = $blockWasSpread || $this->spreadBlock( $block );
2645 }
2646
2647 return $blockWasSpread;
2648 }
2649
2656 protected function spreadBlock( Block $block ): bool {
2657 wfDebug( __METHOD__ . "()" );
2658 $this->load();
2659 if ( $this->mId == 0 ) {
2660 return false;
2661 }
2662
2663 $blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
2664 foreach ( $block->toArray() as $singleBlock ) {
2665 if ( $singleBlock instanceof DatabaseBlock && $singleBlock->isAutoblocking() ) {
2666 return (bool)$blockStore->doAutoblock( $singleBlock, $this->getRequest()->getIP() );
2667 }
2668 }
2669 return false;
2670 }
2671
2679 public function isBlockedFromEmailuser() {
2680 wfDeprecated( __METHOD__, '1.41' );
2681 $block = $this->getBlock();
2682 return $block && $block->appliesToRight( 'sendemail' );
2683 }
2684
2691 public function isBlockedFromUpload() {
2692 $block = $this->getBlock();
2693 return $block && $block->appliesToRight( 'upload' );
2694 }
2695
2700 public function isAllowedToCreateAccount() {
2701 return $this->getThisAsAuthority()->isDefinitelyAllowed( 'createaccount' );
2702 }
2703
2709 public function getUserPage() {
2710 return Title::makeTitle( NS_USER, $this->getName() );
2711 }
2712
2718 public function getTalkPage() {
2719 $title = $this->getUserPage();
2720 return $title->getTalkPage();
2721 }
2722
2730 public function isNewbie() {
2731 // IP users and temp account users are excluded from the autoconfirmed group.
2732 return !$this->isAllowed( 'autoconfirmed' );
2733 }
2734
2747 public function getEditTokenObject( $salt = '', $request = null ) {
2748 if ( $this->isAnon() ) {
2749 return new LoggedOutEditToken();
2750 }
2751
2752 if ( !$request ) {
2753 $request = $this->getRequest();
2754 }
2755 return $request->getSession()->getToken( $salt );
2756 }
2757
2772 public function getEditToken( $salt = '', $request = null ) {
2773 return $this->getEditTokenObject( $salt, $request )->toString();
2774 }
2775
2789 public function matchEditToken( $val, $salt = '', $request = null, $maxage = null ) {
2790 return $this->getEditTokenObject( $salt, $request )->match( $val, $maxage );
2791 }
2792
2801 public function sendConfirmationMail( $type = 'created' ) {
2802 $emailer = MediaWikiServices::getInstance()->getConfirmEmailSender();
2803 $expiration = null; // gets passed-by-ref and defined in next line
2804 $token = $this->getConfirmationToken( $expiration );
2805 $confirmationUrl = $this->getConfirmationTokenUrl( $token );
2806 $invalidateUrl = $this->getInvalidationTokenUrl( $token );
2807 $this->saveSettings();
2808
2809 return Status::wrap( $emailer->sendConfirmationMail(
2810 RequestContext::getMain(),
2811 $type,
2812 new ConfirmEmailData(
2813 $this->getUser(),
2814 $confirmationUrl,
2815 $invalidateUrl,
2816 $expiration
2817 )
2818 ) );
2819 }
2820
2832 public function sendMail( $subject, $body, $from = null, $replyto = null ) {
2833 $passwordSender = MediaWikiServices::getInstance()->getMainConfig()
2834 ->get( MainConfigNames::PasswordSender );
2835
2836 if ( $from instanceof User ) {
2837 $sender = MailAddress::newFromUser( $from );
2838 } else {
2839 $sender = new MailAddress( $passwordSender,
2840 wfMessage( 'emailsender' )->inContentLanguage()->text() );
2841 }
2842 $to = MailAddress::newFromUser( $this );
2843
2844 if ( is_array( $body ) ) {
2845 $bodyText = $body['text'] ?? '';
2846 $bodyHtml = $body['html'] ?? null;
2847 } else {
2848 $bodyText = $body;
2849 $bodyHtml = null;
2850 }
2851
2852 return Status::wrap( MediaWikiServices::getInstance()->getEmailer()
2853 ->send(
2854 [ $to ],
2855 $sender,
2856 $subject,
2857 $bodyText,
2858 $bodyHtml,
2859 [ 'replyTo' => $replyto ]
2860 ) );
2861 }
2862
2878 public function getConfirmationToken(
2879 ?string &$expiration,
2880 ?int $tokenLifeTimeSeconds = null
2881 ): string {
2882 $tokenLifeTimeSeconds ??= MediaWikiServices::getInstance()
2883 ->getMainConfig()->get( MainConfigNames::UserEmailConfirmationTokenExpiry );
2884 $now = ConvertibleTimestamp::time();
2885
2886 $expires = $now + $tokenLifeTimeSeconds;
2887 $expiration = wfTimestamp( TS::MW, $expires );
2888 $this->load();
2889 $token = MWCryptRand::generateHex( 32 );
2890 $hash = md5( $token );
2891 $this->mEmailToken = $hash;
2892 $this->mEmailTokenExpires = $expiration;
2893 return $token;
2894 }
2895
2902 protected function confirmationToken( &$expiration ) {
2903 return $this->getConfirmationToken( $expiration );
2904 }
2905
2912 public static function isWellFormedConfirmationToken( string $token ): bool {
2913 return preg_match( '/^[a-f0-9]{32}$/', $token );
2914 }
2915
2923 public function getConfirmationTokenUrl( string $token ): string {
2924 return $this->getTokenUrl( 'ConfirmEmail', $token );
2925 }
2926
2934 public function getInvalidationTokenUrl( string $token ): string {
2935 return $this->getTokenUrl( 'InvalidateEmail', $token );
2936 }
2937
2945 protected function invalidationTokenUrl( $token ) {
2946 return $this->getTokenUrl( 'InvalidateEmail', $token );
2947 }
2948
2964 public function getTokenUrl( string $page, string $token ): string {
2965 // Hack to bypass localization of 'Special:'
2966 $title = Title::makeTitle( NS_MAIN, "Special:$page/$token" );
2967 return $title->getCanonicalURL();
2968 }
2969
2977 public function confirmEmail() {
2978 // Check if it's already confirmed, so we don't touch the database
2979 // and fire the ConfirmEmailComplete hook on redundant confirmations.
2980 if ( !$this->isEmailConfirmed() ) {
2981 $this->setEmailAuthenticationTimestamp( wfTimestampNow() );
2982 $this->getHookRunner()->onConfirmEmailComplete( $this );
2983 $logContext = [ 'event' => 'email_confirmed' ];
2984 if ( $this->mEmailTokenExpires !== null ) {
2985 $tokenLifetime = MediaWikiServices::getInstance()->getMainConfig()
2986 ->get( MainConfigNames::UserEmailConfirmationTokenExpiry );
2987 $tokenExpiry = wfTimestamp( TS_UNIX, $this->mEmailTokenExpires );
2988 if ( is_numeric( $tokenLifetime ) && $tokenExpiry !== false ) {
2989 $emailSentAt = (int)$tokenExpiry - (int)$tokenLifetime;
2990 $delaySec = max( 0, (int)ConvertibleTimestamp::time() - $emailSentAt );
2991 $logContext['confirmation_delay_seconds'] = $delaySec;
2992 }
2993 }
2994 LoggerFactory::getInstance( 'confirmemail' )->info( 'Email address confirmed', $logContext );
2995 }
2996 return true;
2997 }
2998
3006 public function invalidateEmail() {
3007 $this->load();
3008 $this->mEmailToken = null;
3009 $this->mEmailTokenExpires = null;
3010 $this->setEmailAuthenticationTimestamp( null );
3011 $this->mEmail = '';
3012 $this->getHookRunner()->onInvalidateEmailComplete( $this );
3013 return true;
3014 }
3015
3020 public function setEmailAuthenticationTimestamp( $timestamp ) {
3021 $this->load();
3022 $this->mEmailAuthenticated = $timestamp;
3023 $this->getHookRunner()->onUserSetEmailAuthenticationTimestamp(
3024 $this, $this->mEmailAuthenticated );
3025 }
3026
3034 public function canSendEmail() {
3035 wfDeprecated( __METHOD__, '1.41' );
3036 $permError = MediaWikiServices::getInstance()->getEmailUserFactory()
3037 ->newEmailUser( $this->getThisAsAuthority() )
3038 ->canSend();
3039 return $permError->isGood();
3040 }
3041
3047 public function canReceiveEmail() {
3048 $userOptionsLookup = MediaWikiServices::getInstance()
3049 ->getUserOptionsLookup();
3050 return $this->isEmailConfirmed() && !$userOptionsLookup->getOption( $this, 'disablemail' );
3051 }
3052
3063 public function isEmailConfirmed(): bool {
3064 $emailAuthentication = MediaWikiServices::getInstance()->getMainConfig()
3065 ->get( MainConfigNames::EmailAuthentication );
3066 $this->load();
3067 $confirmed = true;
3068 if ( $this->getHookRunner()->onEmailConfirmed( $this, $confirmed ) ) {
3069 return !$this->isAnon() &&
3070 Sanitizer::validateEmail( $this->getEmail() ) &&
3071 ( !$emailAuthentication || $this->getEmailAuthenticationTimestamp() );
3072 }
3073
3074 return $confirmed;
3075 }
3076
3081 public function isEmailConfirmationPending() {
3082 $emailAuthentication = MediaWikiServices::getInstance()->getMainConfig()
3083 ->get( MainConfigNames::EmailAuthentication );
3084 return $emailAuthentication &&
3085 !$this->isEmailConfirmed() &&
3086 $this->mEmailToken &&
3087 $this->mEmailTokenExpires > wfTimestamp();
3088 }
3089
3098 public function getRegistration() {
3099 return MediaWikiServices::getInstance()
3100 ->getUserRegistrationLookup()
3101 ->getRegistration( $this );
3102 }
3103
3111 public static function getRightDescription( $right ) {
3112 $key = "right-$right";
3113 $msg = wfMessage( $key );
3114 return $msg->isDisabled() ? $right : $msg->text();
3115 }
3116
3124 public static function getRightDescriptionHtml( $right ) {
3125 return wfMessage( "right-$right" )->parse();
3126 }
3127
3141 public static function getQueryInfo() {
3142 $ret = [
3143 'tables' => [ 'user', 'user_actor' => 'actor' ],
3144 'fields' => [
3145 'user_id',
3146 'user_name',
3147 'user_real_name',
3148 'user_email',
3149 'user_touched',
3150 'user_token',
3151 'user_email_authenticated',
3152 'user_email_token',
3153 'user_email_token_expires',
3154 'user_registration',
3155 'user_editcount',
3156 'user_actor.actor_id',
3157 ],
3158 'joins' => [
3159 'user_actor' => [ 'JOIN', 'user_actor.actor_user = user_id' ],
3160 ],
3161 ];
3162
3163 return $ret;
3164 }
3165
3175 public static function newQueryBuilder( IReadableDatabase $db ) {
3176 return $db->newSelectQueryBuilder()
3177 ->select( [
3178 'user_id',
3179 'user_name',
3180 'user_real_name',
3181 'user_email',
3182 'user_touched',
3183 'user_token',
3184 'user_email_authenticated',
3185 'user_email_token',
3186 'user_email_token_expires',
3187 'user_registration',
3188 'user_editcount',
3189 'user_actor.actor_id',
3190 ] )
3191 ->from( 'user' )
3192 ->join( 'actor', 'user_actor', 'user_actor.actor_user = user_id' );
3193 }
3194
3205 public static function newFatalPermissionDeniedStatus( $permission ) {
3206 return Status::wrap( MediaWikiServices::getInstance()->getPermissionManager()
3207 ->newFatalPermissionDeniedStatus(
3208 $permission,
3209 RequestContext::getMain()
3210 ) );
3211 }
3212
3228 public function getInstanceForUpdate() {
3229 wfDeprecated( __METHOD__, '1.46' );
3230 return $this->getInstanceFromPrimary( IDBAccessObject::READ_EXCLUSIVE );
3231 }
3232
3250 public function getInstanceFromPrimary( int $loadFlags = IDBAccessObject::READ_LATEST ): ?User {
3251 if ( $this->isAnon() ) {
3252 return null;
3253 } elseif ( ( $loadFlags & $this->queryFlagsUsed ) === $loadFlags ) {
3254 return $this;
3255 }
3256
3257 $user = self::newFromId( $this->getId() );
3258 if ( !$user->loadFromId( $loadFlags ) ) {
3259 return null;
3260 }
3261
3262 return $user;
3263 }
3264
3272 public function equals( ?UserIdentity $user ): bool {
3273 if ( !$user ) {
3274 return false;
3275 }
3276 // XXX it's not clear whether central ID providers are supposed to obey this
3277 return $this->getName() === $user->getName();
3278 }
3279
3285 public function getUser(): UserIdentity {
3286 return $this;
3287 }
3288
3296 public function probablyCan(
3297 string $action,
3298 PageIdentity $target,
3299 ?PermissionStatus $status = null
3300 ): bool {
3301 return $this->getThisAsAuthority()->probablyCan( $action, $target, $status );
3302 }
3303
3311 public function definitelyCan(
3312 string $action,
3313 PageIdentity $target,
3314 ?PermissionStatus $status = null
3315 ): bool {
3316 return $this->getThisAsAuthority()->definitelyCan( $action, $target, $status );
3317 }
3318
3327 public function isDefinitelyAllowed( string $action, ?PermissionStatus $status = null ): bool {
3328 return $this->getThisAsAuthority()->isDefinitelyAllowed( $action, $status );
3329 }
3330
3339 public function authorizeAction( string $action, ?PermissionStatus $status = null ): bool {
3340 return $this->getThisAsAuthority()->authorizeAction( $action, $status );
3341 }
3342
3350 public function authorizeRead(
3351 string $action,
3352 PageIdentity $target,
3353 ?PermissionStatus $status = null
3354 ): bool {
3355 return $this->getThisAsAuthority()->authorizeRead( $action, $target, $status );
3356 }
3357
3365 public function authorizeWrite(
3366 string $action, PageIdentity $target,
3367 ?PermissionStatus $status = null
3368 ): bool {
3369 return $this->getThisAsAuthority()->authorizeWrite( $action, $target, $status );
3370 }
3371
3376 private function getThisAsAuthority(): UserAuthority {
3377 if ( !$this->mThisAsAuthority ) {
3378 // TODO: For users that are not User::isGlobalSessionUser,
3379 // creating a UserAuthority here is incorrect, since it depends
3380 // on global WebRequest, but that is what we've used to do before Authority.
3381 // When PermissionManager is refactored into Authority, we need
3382 // to provide base implementation, based on just user groups/rights,
3383 // and use it here.
3384 $request = $this->getRequest();
3385 $uiContext = RequestContext::getMain();
3386
3387 $services = MediaWikiServices::getInstance();
3388 $this->mThisAsAuthority = new UserAuthority(
3389 $this,
3390 $request,
3391 $uiContext,
3392 $services->getPermissionManager(),
3393 $services->getRateLimiter(),
3394 $services->getFormatterFactory()->getBlockErrorFormatter( $uiContext )
3395 );
3396 }
3397
3398 return $this->mThisAsAuthority;
3399 }
3400
3404 private function isGlobalSessionUser(): bool {
3405 // The session user is set up towards the end of Setup.php. Until then,
3406 // assume it's a logged-out user.
3407 $sessionUser = RequestContext::getMain()->getUser();
3408 $globalUserName = $sessionUser->isSafeToLoad()
3409 ? $sessionUser->getName()
3410 : IPUtils::sanitizeIP( $sessionUser->getRequest()->getIP() );
3411
3412 return $this->getName() === $globalUserName;
3413 }
3414
3420 public function isTemp(): bool {
3421 if ( $this->isTemp === null ) {
3422 $this->isTemp = MediaWikiServices::getInstance()->getUserIdentityUtils()
3423 ->isTemp( $this );
3424 }
3425 return $this->isTemp;
3426 }
3427
3434 public function isNamed(): bool {
3435 return $this->isRegistered() && !$this->isTemp();
3436 }
3437}
3438
3440class_alias( User::class, 'User' );
const NS_USER
Definition Defines.php:53
const NS_MAIN
Definition Defines.php:51
wfTimestampOrNull( $outputtype=TS::UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(MW_ENTRY_POINT==='index') if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgLang
Definition Setup.php:551
global $wgFullyInitialised
Definition Setup.php:579
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:69
const MW_ENTRY_POINT
Definition api.php:21
Utility functions for generating hashes.
AuthManager is the authentication system in MediaWiki and serves entry point for authentication.
This is a value object for authentication requests.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
isAutoblocking( $x=null)
Does the block cause autoblocks to be created?
Group all the pieces relevant to the context of a request into one instance.
Defer callable updates to run later in the PHP process.
Handler class for MWExceptions.
Create PSR-3 logger objects.
Value class wrapping variables present in the confirmation email.
Represent and format a single name and email address pair for SMTP.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
HTML sanitizer for MediaWiki.
Definition Sanitizer.php:32
Factory class for creating and checking Password objects.
Check if a user's password complies with any password policies that apply to that user,...
A StatusValue for permission errors.
Represents the subject that rate limits are applied to.
Represents the authority of a given User.
Profiler base class that defines the interface and some shared functionality.
Definition Profiler.php:25
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...
This serves as the entry point to the MediaWiki session handling system.
Value object representing a CSRF token.
Definition Token.php:19
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:44
Represents a title within MediaWiki.
Definition Title.php:69
getCanonicalURL( $query='')
Get the URL for a canonical link, for use in things like IRC and e-mail notifications.
Definition Title.php:2359
Value object representing a MediaWiki edit token for logged-out users.
getOption(UserIdentity $user, string $oname, $defaultOverride=null, bool $ignoreHidden=false, int $queryFlags=IDBAccessObject::READ_NORMAL)
Get the user's current setting for a given option.
Value object representing a user's identity.
User class for the MediaWiki software.
Definition User.php:130
authorizeAction(string $action, ?PermissionStatus $status=null)
Authorize an action.This should be used immediately before performing the action.Calling this method ...
Definition User.php:3339
isAllowedToCreateAccount()
Get whether the user is allowed to create an account.
Definition User.php:2700
string null $mDatePreference
Lazy-initialized variables, invalidated with clearInstanceCache.
Definition User.php:245
touch()
Update the "touched" timestamp for the user.
Definition User.php:1688
isAllowed(string $permission, ?PermissionStatus $status=null)
Checks whether this authority has the given permission in general.
Definition User.php:2149
static newFromConfirmationCode( $code, $flags=IDBAccessObject::READ_NORMAL)
Factory method to fetch whichever user has a given email confirmation code.
Definition User.php:735
& __get( $name)
Definition User.php:300
logout()
Log this user out.
Definition User.php:2286
getRegistration()
Get the timestamp of account creation.
Definition User.php:3098
getWikiId()
Returns self::LOCAL to indicate the user is associated with the local wiki.
Definition User.php:289
int $queryFlagsUsed
IDBAccessObject::READ_* constant bitfield used to load data.
Definition User.php:255
getInstanceFromPrimary(int $loadFlags=IDBAccessObject::READ_LATEST)
Get an instance of this user that was loaded from the primary DB.
Definition User.php:3250
useRCPatrol()
Check whether to enable recent changes patrol features for this user.
Definition User.php:2157
isAllowedAny(... $permissions)
Checks whether this authority has any of the given permissions in general.Implementations must ensure...
Definition User.php:2140
const READ_EXCLUSIVE
Definition User.php:138
requiresHTTPS()
Determine based on the wiki configuration and the user's options, whether this user must be over HTTP...
Definition User.php:2055
getEditTokenObject( $salt='', $request=null)
Initialize (if necessary) and return a session token value which can be used in edit forms to show th...
Definition User.php:2747
getEditToken( $salt='', $request=null)
Initialize (if necessary) and return a session token value which can be used in edit forms to show th...
Definition User.php:2772
confirmationToken(&$expiration)
Deprecated alias for getConfirmationToken() for CentralAuth.
Definition User.php:2902
static findUsersByGroup( $groups, $limit=5000, $after=null)
Return the users who are members of the given group(s).
Definition User.php:919
setToken( $token=false)
Set the random token (used for persistent authentication) Called from loadDefaults() among other plac...
Definition User.php:1845
canReceiveEmail()
Is this user allowed to receive e-mails within limits of current site configuration?
Definition User.php:3047
getId( $wikiId=self::LOCAL)
Get the user's ID.
Definition User.php:1491
getCacheKey(WANObjectCache $cache)
Definition User.php:525
loadFromCache()
Load user data from shared cache, given mId has already been set.
Definition User.php:538
getDBTouched()
Get the user_touched timestamp field (time of last DB updates)
Definition User.php:1756
clearInstanceCache( $reloadFrom=false)
Clear various cached data stored in this object.
Definition User.php:1326
checkPasswordValidity( $password)
Check if this is a valid password for this user.
Definition User.php:972
static string[] $mCacheVars
List of member variables which are saved to the shared cache (memcached).
Definition User.php:174
authorizeRead(string $action, PageIdentity $target, ?PermissionStatus $status=null)
Definition User.php:3350
getExperienceLevel()
Compute experienced level based on edit count and registration date.
Definition User.php:2205
isNamed()
Is the user a normal non-temporary registered user?
Definition User.php:3434
setEmailWithConfirmation(string $str)
Set the user's e-mail address and send a confirmation mail if needed.
Definition User.php:1902
loadFromUserObject( $user)
Load the data for this user object from another user object.
Definition User.php:1257
getUserPage()
Get this user's personal page title.
Definition User.php:2709
isSafeToLoad()
Test if it's safe to load this User object.
Definition User.php:362
isEmailConfirmed()
Is this user's e-mail address valid-looking and confirmed within limits of the current site configura...
Definition User.php:3063
invalidationTokenUrl( $token)
Deprecated alias for getInvalidationTokenUrl() for CentralAuth.
Definition User.php:2945
AbstractBlock false null $mGlobalBlock
Null when uninitialized, false when there is no block.
Definition User.php:247
isPingLimitable()
Is this user subject to rate limiting?
Definition User.php:1375
confirmEmail()
Mark the e-mail address confirmed.
Definition User.php:2977
getConfirmationToken(?string &$expiration, ?int $tokenLifeTimeSeconds=null)
Generate, store, and return a new e-mail confirmation code.
Definition User.php:2878
isNewbie()
Determine whether the user is a newbie.
Definition User.php:2730
resetTokenFromOption( $oname)
Reset a token stored in the preferences (like the watchlist one).
Definition User.php:2015
isBlockedFromEmailuser()
Get whether the user is blocked from using Special:Emailuser.
Definition User.php:2679
isLocked()
Check if user account is locked.
Definition User.php:1466
isBlockedFromUpload()
Get whether the user is blocked from using Special:Upload.
Definition User.php:2691
static newQueryBuilder(IReadableDatabase $db)
Get a SelectQueryBuilder with the tables, fields and join conditions needed to create a new User obje...
Definition User.php:3175
setCookies( $request=null, $secure=null, $rememberMe=false)
Persist this user's session (e.g.
Definition User.php:2249
int $mId
Cache variables.
Definition User.php:194
addToDatabase()
Add this existing user object to the database.
Definition User.php:2540
getBlock( $freshness=IDBAccessObject::READ_NORMAL, $disableIpBlockExemptChecking=false)
Get the block affecting the user, or null if the user is not blocked.
Definition User.php:1425
getTokenUrl(string $page, string $token)
Function to create a special page URL with a token path parameter.
Definition User.php:2964
setEmail(string $str)
Set the user's e-mail address.
Definition User.php:1885
static newFatalPermissionDeniedStatus( $permission)
Factory function for fatal permission-denied errors.
Definition User.php:3205
static purge( $dbDomain, $userId)
Definition User.php:514
string $mFrom
Initialization data source if mLoadedItems!==true.
Definition User.php:239
probablyCan(string $action, PageIdentity $target, ?PermissionStatus $status=null)
Definition User.php:3296
static newFromActorId( $id)
Static factory method for creation from a given actor ID.
Definition User.php:665
loadFromRow( $row, $data=null)
Initialize this object from a row from the user table.
Definition User.php:1147
checkAndSetTouched()
Bump user_touched if it didn't change since this object was loaded.
Definition User.php:1289
load( $flags=IDBAccessObject::READ_NORMAL)
Load the user table data for this object from the source given by mFrom.
Definition User.php:379
loadFromDatabase( $flags=IDBAccessObject::READ_LATEST)
Load user data from the database.
Definition User.php:1101
getEditCount()
Get the user's edit count.
Definition User.php:2076
doLogout()
Clear the user's session, and reset the instance cache.
Definition User.php:2296
getDatePreference()
Get the user's preferred date format.
Definition User.php:2033
clearSharedCache( $mode='refresh')
Clear user data from memcached.
Definition User.php:1645
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition User.php:648
setActorId(int $actorId)
Sets the actor id.
Definition User.php:1607
setItemLoaded( $item)
Set that an item has been loaded.
Definition User.php:1064
static newSystemUser( $name, $options=[])
Static factory method for creation of a "system" user from username.
Definition User.php:820
loadFromId( $flags=IDBAccessObject::READ_NORMAL)
Load user table data, given mId has already been set.
Definition User.php:484
static newFromRow( $row, $data=null)
Create a new user object from a user row.
Definition User.php:770
isAnon()
Get whether the user is anonymous.
Definition User.php:2098
sendMail( $subject, $body, $from=null, $replyto=null)
Send an e-mail to this user's account.
Definition User.php:2832
changeAuthenticationData(array $data)
Changes credentials of the user.
Definition User.php:1774
static newFromAnyId( $userId, $userName, $actorId, $dbDomain=false)
Static factory method for creation from an ID, name, and/or actor ID.
Definition User.php:714
definitelyCan(string $action, PageIdentity $target, ?PermissionStatus $status=null)
Definition User.php:3311
string $mRealName
Definition User.php:204
isSystemUser()
Get whether the user is a system user.
Definition User.php:2129
getInvalidationTokenUrl(string $token)
Return a URL the user can use to invalidate their email address.
Definition User.php:2934
isItemLoaded( $item, $all='all')
Return whether an item has been loaded.
Definition User.php:1052
const TOKEN_LENGTH
Number of characters required for the user_token field.
Definition User.php:148
setId( $v)
Set the user and reload all fields according to a given ID.
Definition User.php:1515
string null $mToken
Definition User.php:213
isAllowedAll(... $permissions)
Checks whether this authority has any of the given permissions in general.Implementations must ensure...
Definition User.php:2145
getInstanceForUpdate()
Get a new instance of this user that was loaded from the primary DB via a locking read.
Definition User.php:3228
getTokenFromOption( $oname)
Get a token stored in the preferences (like the watchlist one), resetting it if it's empty (and savin...
Definition User.php:1984
isDefinitelyAllowed(string $action, ?PermissionStatus $status=null)
Checks whether this authority is allowed to perform the given action.This method performs a thorough ...
Definition User.php:3327
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new user object.
Definition User.php:3141
equals(?UserIdentity $user)
Checks if two user objects point to the same user.
Definition User.php:3272
isTemp()
Is the user an autocreated temporary user?
Definition User.php:3420
const MAINTENANCE_SCRIPT_USER
Username used for various maintenance scripts.
Definition User.php:165
isEmailConfirmationPending()
Check whether there is an outstanding request for e-mail confirmation.
Definition User.php:3081
getRealName()
Get the user's real name.
Definition User.php:1957
string $mTouched
TS::MW timestamp from the DB.
Definition User.php:209
getTitleKey()
Get the user's name escaped by underscores.
Definition User.php:1616
string null $mEmailTokenExpires
Definition User.php:219
bool null $mLocked
Definition User.php:249
getActorId( $dbwOrWikiId=self::LOCAL)
Get the user's actor ID.
Definition User.php:1570
string null $mQuickTouched
TS::MW timestamp from cache.
Definition User.php:211
validateCache( $timestamp)
Validate the cache for this account.
Definition User.php:1722
getEmailAuthenticationTimestamp()
Get the timestamp of the user's e-mail authentication.
Definition User.php:1874
authorizeWrite(string $action, PageIdentity $target, ?PermissionStatus $status=null)
Definition User.php:3365
__set( $name, $value)
Definition User.php:321
useFilePatrol()
Check whether to enable new files patrol features for this user.
Definition User.php:2182
static newFromSession(?WebRequest $request=null)
Create a new user object using data from session.
Definition User.php:748
canSendEmail()
Is this user allowed to send e-mails within limits of current site configuration?
Definition User.php:3034
static isWellFormedConfirmationToken(string $token)
Check if the given email confirmation token is well-formed (to detect mangling by email clients).
Definition User.php:2912
static createNew( $name, $params=[])
Add a user to the database, return the user object.
Definition User.php:2445
getRequest()
Get the WebRequest object to use with this object.
Definition User.php:2196
saveSettings()
Save this user's settings into the database.
Definition User.php:2334
loadDefaults( $name=false, $actorId=null)
Set cached properties to default.
Definition User.php:1016
useNPPatrol()
Check whether to enable new pages patrol features for this user.
Definition User.php:2167
const INVALID_TOKEN
An invalid string value for the user_token field.
Definition User.php:153
pingLimiter( $action='edit', $incrBy=1)
Primitive rate limits: enforce maximum actions per time period to put a brake on flooding.
Definition User.php:1396
matchEditToken( $val, $salt='', $request=null, $maxage=null)
Check given value against the token value stored in the session.
Definition User.php:2789
invalidateEmail()
Invalidate the user's e-mail confirmation, and unauthenticate the e-mail address if it was already co...
Definition User.php:3006
isRegistered()
Get whether the user is registered.
Definition User.php:2090
getTalkPage()
Get this user's talk page title.
Definition User.php:2718
static newFromIdentity(UserIdentity $identity)
Returns a User object corresponding to the given UserIdentity.
Definition User.php:684
makeUpdateConditions(IReadableDatabase $db)
Build additional update conditions to protect against race conditions using a compare-and-set (CAS) m...
Definition User.php:1271
string null $mEmailToken
Definition User.php:217
int null $mActorId
Switched from protected to public for use in UserFactory.
Definition User.php:202
getToken( $forceCreation=true)
Get the user's current token.
Definition User.php:1801
setEmailAuthenticationTimestamp( $timestamp)
Set the e-mail authentication timestamp.
Definition User.php:3020
isHidden()
Check if user account is hidden.
Definition User.php:1481
static getRightDescription( $right)
Get the description of a given right as wikitext.
Definition User.php:3111
setName( $str)
Set the user name.
Definition User.php:1552
static getRightDescriptionHtml( $right)
Get the description of a given right as rendered HTML.
Definition User.php:3124
string null $mEmailAuthenticated
Definition User.php:215
debouncedDBTouch()
Update the db touched timestamp for the user if it hasn't been updated recently.
Definition User.php:1703
isValidPassword( $password)
Is the input a valid password for this user?
Definition User.php:946
getEmail()
Get the user's e-mail address.
Definition User.php:1861
getName()
Get the user name, or the IP of an anonymous user.
Definition User.php:1524
setRealName(string $str)
Set the user's real name.
Definition User.php:1969
spreadAnyEditBlock()
If this user is logged-in and blocked, block any IP address they've successfully logged in from.
Definition User.php:2634
getTouched()
Get the user touched timestamp.
Definition User.php:1734
static newFromName( $name, $validate='valid')
Definition User.php:622
invalidateCache()
Immediately touch the user data cache for this account.
Definition User.php:1671
scheduleSpreadBlock()
Schedule a deferred update which will block the IP address of the current user, if they are blocked w...
Definition User.php:2619
spreadBlock(Block $block)
If this (non-anonymous) user is blocked, block the IP address they've successfully logged in from.
Definition User.php:2656
getConfirmationTokenUrl(string $token)
Return a URL the user can use to confirm their email address.
Definition User.php:2923
idForName( $flags=IDBAccessObject::READ_NORMAL)
If only this user's username is known, and it exists, return the user ID.
Definition User.php:2412
sendConfirmationMail( $type='created')
Generate a new e-mail confirmation token and send a confirmation/invalidation mail to the user's give...
Definition User.php:2801
array bool $mLoadedItems
Array with already loaded items or true if all items have been loaded.
Definition User.php:226
A cryptographic random generator class used for generating secret keys.
Multi-datacenter aware caching interface.
makeGlobalKey( $keygroup,... $components)
Base class for the more common types of database errors.
Build SELECT queries with a fluent interface.
return[ 'config-schema-inverse'=>['default'=>['ConfigRegistry'=>['main'=> 'MediaWiki\\Config\\GlobalVarConfig::newInstance',], 'Sitename'=> 'MediaWiki', 'Server'=> false, 'CanonicalServer'=> false, 'ServerName'=> false, 'AssumeProxiesUseDefaultProtocolPorts'=> true, 'HttpsPort'=> 443, 'ForceHTTPS'=> false, 'ScriptPath'=> '/wiki', 'UsePathInfo'=> null, 'Script'=> false, 'LoadScript'=> false, 'RestPath'=> false, 'StylePath'=> false, 'LocalStylePath'=> false, 'ExtensionAssetsPath'=> false, 'ExtensionDirectory'=> null, 'StyleDirectory'=> null, 'ArticlePath'=> false, 'UploadPath'=> false, 'ImgAuthPath'=> false, 'ThumbPath'=> false, 'UploadDirectory'=> false, 'FileCacheDirectory'=> false, 'Logo'=> false, 'Logos'=> false, 'Favicon'=> '/favicon.ico', 'AppleTouchIcon'=> false, 'ReferrerPolicy'=> false, 'TmpDirectory'=> false, 'UploadBaseUrl'=> '', 'UploadStashScalerBaseUrl'=> false, 'ActionPaths'=>[], 'MainPageIsDomainRoot'=> false, 'EnableUploads'=> false, 'UploadStashMaxAge'=> 21600, 'EnableAsyncUploads'=> false, 'EnableAsyncUploadsByURL'=> false, 'UploadMaintenance'=> false, 'IllegalFileChars'=> ':\\/\\\\', 'DeletedDirectory'=> false, 'ImgAuthDetails'=> false, 'ImgAuthUrlPathMap'=>[], 'LocalFileRepo'=>['class'=> 'MediaWiki\\FileRepo\\LocalRepo', 'name'=> 'local', 'directory'=> null, 'scriptDirUrl'=> null, 'favicon'=> null, 'url'=> null, 'hashLevels'=> null, 'thumbScriptUrl'=> null, 'transformVia404'=> null, 'deletedDir'=> null, 'deletedHashLevels'=> null, 'updateCompatibleMetadata'=> null, 'reserializeMetadata'=> null,], 'ForeignFileRepos'=>[], 'UseInstantCommons'=> false, 'UseSharedUploads'=> false, 'SharedUploadDirectory'=> null, 'SharedUploadPath'=> null, 'HashedSharedUploadDirectory'=> true, 'RepositoryBaseUrl'=> 'https:'FetchCommonsDescriptions'=> false, 'SharedUploadDBname'=> false, 'SharedUploadDBprefix'=> '', 'CacheSharedUploads'=> true, 'ForeignUploadTargets'=>['local',], 'UploadDialog'=>['fields'=>['description'=> true, 'date'=> false, 'categories'=> false,], 'licensemessages'=>['local'=> 'generic-local', 'foreign'=> 'generic-foreign',], 'comment'=>['local'=> '', 'foreign'=> '',], 'format'=>['filepage'=> ' $DESCRIPTION', 'description'=> ' $TEXT', 'ownwork'=> '', 'license'=> '', 'uncategorized'=> '',],], 'FileBackends'=>[], 'LockManagers'=>[], 'ShowEXIF'=> null, 'UpdateCompatibleMetadata'=> false, 'AllowCopyUploads'=> false, 'CopyUploadsDomains'=>[], 'CopyUploadsFromSpecialUpload'=> false, 'CopyUploadProxy'=> false, 'CopyUploadTimeout'=> false, 'CopyUploadAllowOnWikiDomainConfig'=> false, 'MaxUploadSize'=> 104857600, 'MinUploadChunkSize'=> 1024, 'UploadNavigationUrl'=> false, 'UploadMissingFileUrl'=> false, 'ThumbnailScriptPath'=> false, 'SharedThumbnailScriptPath'=> false, 'HashedUploadDirectory'=> true, 'CSPUploadEntryPoint'=> true, 'FileExtensions'=>['png', 'gif', 'jpg', 'jpeg', 'webp',], 'ProhibitedFileExtensions'=>['html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht', 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar', 'shtml', 'jhtml', 'pl', 'py', 'cgi', 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl', 'xml',], 'MimeTypeExclusions'=>['text/html', 'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile', 'application/java', 'application/xml', 'text/xml',], 'CheckFileExtensions'=> true, 'StrictFileExtensions'=> true, 'DisableUploadScriptChecks'=> false, 'UploadSizeWarning'=> false, 'TrustedMediaFormats'=>['BITMAP', 'AUDIO', 'VIDEO', 'image/svg+xml', 'application/pdf',], 'MediaHandlers'=>[], 'NativeImageLazyLoading'=> false, 'ParserTestMediaHandlers'=>['image/jpeg'=> 'MockBitmapHandler', 'image/png'=> 'MockBitmapHandler', 'image/gif'=> 'MockBitmapHandler', 'image/tiff'=> 'MockBitmapHandler', 'image/webp'=> 'MockBitmapHandler', 'image/x-ms-bmp'=> 'MockBitmapHandler', 'image/x-bmp'=> 'MockBitmapHandler', 'image/x-xcf'=> 'MockBitmapHandler', 'image/svg+xml'=> 'MockSvgHandler', 'image/vnd.djvu'=> 'MockDjVuHandler',], 'UseImageResize'=> true, 'UseImageMagick'=> false, 'ImageMagickConvertCommand'=> '/usr/bin/convert', 'MaxInterlacingAreas'=>[], 'SharpenParameter'=> '0x0.4', 'SharpenReductionThreshold'=> 0.85, 'ImageMagickTempDir'=> false, 'CustomConvertCommand'=> false, 'JpegTran'=> '/usr/bin/jpegtran', 'JpegPixelFormat'=> 'yuv420', 'JpegQuality'=> 80, 'Exiv2Command'=> '/usr/bin/exiv2', 'Exiftool'=> '/usr/bin/exiftool', 'SVGConverters'=>['ImageMagick'=> ' $path/convert -background "#ffffff00" -thumbnail $widthx$height\\! $input PNG:$output', 'inkscape'=> ' $path/inkscape -w $width -o $output $input', 'batik'=> 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg'=> ' $path/rsvg-convert -w $width -h $height -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 220, 250, 300, 400,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailStepsRatio'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'TrackMediaRequestProvenance'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'UserEmailConfirmationUseHTML'=> false, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'UseSessionCookieForBotPasswords'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'UseLegacyMediaStyles' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCache' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => false, 'ParserOptionsLogUnsafeSampleRate' => 0, ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailStepsRatio' => [ 'number', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'UserEmailConfirmationUseHTML' => 'boolean', 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCache' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'file' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], ], ], 'ShellboxUrls' => [ 'additionalProperties' => [ 'type' => [ 'string', 'boolean', 'null', ], ], ], ], 'obsolete-config' => [ 'MangleFlashPolicy' => 'Since 1.39; no longer has any effect.', 'EnableOpenSearchSuggest' => 'Since 1.35, no longer used', 'AutoloadAttemptLowercase' => 'Since 1.40; no longer has any effect.', ],]
Represents a block that may prevent users from performing specific operations.
Definition Block.php:31
toArray()
Convert a block to an array of blocks.
const LOCAL
Wiki ID value to use with instances that are defined relative to the local wiki.
Interface for objects (potentially) representing an editable wiki page.
This interface represents the authority associated with the current execution context,...
Definition Authority.php:23
Interface for objects representing user identity.
Interface for database access objects.
Interface to a relational database.
Definition IDatabase.php:31
newUpdateQueryBuilder()
Get an UpdateQueryBuilder bound to this connection.
affectedRows()
Get the number of rows affected by the last query method call.
insertId()
Get the sequence-based ID assigned by the last query method call.
newInsertQueryBuilder()
Get an InsertQueryBuilder bound to this connection.
A database connection without write operations.
newSelectQueryBuilder()
Create an empty SelectQueryBuilder which can be used to run queries against this connection.
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...
timestampOrNull( $ts=null)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...
const MW_NO_SESSION
Definition load.php:18