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 RuntimeException;
46use stdClass;
47use Stringable;
48use UnexpectedValueException;
49use Wikimedia\Assert\Assert;
50use Wikimedia\Assert\PreconditionException;
51use Wikimedia\DebugInfo\DebugInfoTrait;
52use 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
364 public function isSafeToLoad() {
365 global $wgFullyInitialised;
366
367 // The user is safe to load if:
368 // * MW_NO_SESSION is undefined AND $wgFullyInitialised is true (safe to use session data)
369 // * mLoadedItems === true (already loaded)
370 // * mFrom !== 'session' (sessions not involved at all)
371
372 return ( !defined( 'MW_NO_SESSION' ) && $wgFullyInitialised ) ||
373 $this->mLoadedItems === true || $this->mFrom !== 'session';
374 }
375
381 public function load( $flags = IDBAccessObject::READ_NORMAL ) {
382 global $wgFullyInitialised;
383
384 if ( $this->mLoadedItems === true ) {
385 return;
386 }
387
388 // Set it now to avoid infinite recursion in accessors
389 $oldLoadedItems = $this->mLoadedItems;
390 $this->mLoadedItems = true;
391 $this->queryFlagsUsed = $flags;
392
393 // If this is called too early, things are likely to break.
394 if ( !$wgFullyInitialised && $this->mFrom === 'session' ) {
395 LoggerFactory::getInstance( 'session' )
396 ->warning( 'User::loadFromSession called before the end of Setup.php', [
397 'userId' => $this->mId,
398 'userName' => $this->mName,
399 'exception' => new RuntimeException(
400 'User::loadFromSession called before the end of Setup.php'
401 ),
402 ] );
403 $this->loadDefaults();
404 $this->mLoadedItems = $oldLoadedItems;
405 return;
406 } elseif ( $this->mFrom === 'session'
407 && defined( 'MW_NO_SESSION' ) && MW_NO_SESSION !== 'warn'
408 ) {
409 // Even though we are throwing an exception, make sure the User object is left in a
410 // clean state as sometimes these exceptions are caught and the object accessed again.
411 $this->loadDefaults();
412 $this->mLoadedItems = $oldLoadedItems;
413 $ep = defined( 'MW_ENTRY_POINT' ) ? MW_ENTRY_POINT : 'this';
414 throw new BadMethodCallException( "Sessions are disabled for $ep entry point" );
415 }
416
417 switch ( $this->mFrom ) {
418 case 'defaults':
419 $this->loadDefaults();
420 break;
421 case 'id':
422 // Make sure this thread sees its own changes, if the ID isn't 0
423 if ( $this->mId != 0 ) {
424 $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
425 if ( $lb->hasOrMadeRecentPrimaryChanges() ) {
426 $flags |= IDBAccessObject::READ_LATEST;
427 $this->queryFlagsUsed = $flags;
428 }
429 }
430
431 $this->loadFromId( $flags );
432 break;
433 case 'actor':
434 case 'name':
435 // Make sure this thread sees its own changes
436 $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
437 if ( $lb->hasOrMadeRecentPrimaryChanges() ) {
438 $flags |= IDBAccessObject::READ_LATEST;
439 $this->queryFlagsUsed = $flags;
440 }
441
442 $dbr = DBAccessObjectUtils::getDBFromRecency(
443 MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
444 $flags
445 );
446 $queryBuilder = $dbr->newSelectQueryBuilder()
447 ->select( [ 'actor_id', 'actor_user', 'actor_name' ] )
448 ->from( 'actor' )
449 ->recency( $flags );
450 if ( $this->mFrom === 'name' ) {
451 // make sure to use normalized form of IP for anonymous users
452 $queryBuilder->where( [ 'actor_name' => IPUtils::sanitizeIP( $this->mName ) ] );
453 } else {
454 $queryBuilder->where( [ 'actor_id' => $this->mActorId ] );
455 }
456 $row = $queryBuilder->caller( __METHOD__ )->fetchRow();
457
458 if ( !$row ) {
459 // Ugh.
460 $this->loadDefaults( $this->mFrom === 'name' ? $this->mName : false );
461 } elseif ( $row->actor_user ) {
462 $this->mId = $row->actor_user;
463 $this->loadFromId( $flags );
464 } else {
465 $this->loadDefaults( $row->actor_name, $row->actor_id );
466 }
467 break;
468 case 'session':
469 if ( !$this->loadFromSession() ) {
470 // Loading from session failed. Load defaults.
471 $this->loadDefaults();
472 }
473 $this->getHookRunner()->onUserLoadAfterLoadFromSession( $this );
474 break;
475 default:
476 throw new UnexpectedValueException(
477 "Unrecognised value for User->mFrom: \"{$this->mFrom}\"" );
478 }
479 }
480
486 public function loadFromId( $flags = IDBAccessObject::READ_NORMAL ) {
487 if ( $this->mId == 0 ) {
488 // Anonymous users are not in the database (don't need cache)
489 $this->loadDefaults();
490 return false;
491 }
492
493 // Try cache (unless this needs data from the primary DB).
494 // NOTE: if this thread called saveSettings(), the cache was cleared.
495 $latest = DBAccessObjectUtils::hasFlags( $flags, IDBAccessObject::READ_LATEST );
496 if ( $latest ) {
497 if ( !$this->loadFromDatabase( $flags ) ) {
498 // Can't load from ID
499 return false;
500 }
501 } else {
502 $this->loadFromCache();
503 }
504
505 $this->mLoadedItems = true;
506 $this->queryFlagsUsed = $flags;
507
508 return true;
509 }
510
516 public static function purge( $dbDomain, $userId ) {
517 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
518 $key = $cache->makeGlobalKey( 'user', 'id', $dbDomain, $userId );
519 $cache->delete( $key );
520 }
521
527 protected function getCacheKey( WANObjectCache $cache ) {
528 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
529
530 return $cache->makeGlobalKey( 'user', 'id',
531 $lbFactory->getLocalDomainID(), $this->mId );
532 }
533
540 protected function loadFromCache() {
541 global $wgFullyInitialised;
542
543 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
544 $data = $cache->getWithSetCallback(
545 $this->getCacheKey( $cache ),
546 $cache::TTL_HOUR,
547 function ( $oldValue, &$ttl, array &$setOpts ) use ( $cache, $wgFullyInitialised ) {
548 $setOpts += Database::getCacheSetOptions(
549 MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase()
550 );
551 wfDebug( "User: cache miss for user {$this->mId}" );
552
553 $this->loadFromDatabase( IDBAccessObject::READ_NORMAL );
554
555 $data = [];
556 foreach ( self::$mCacheVars as $name ) {
557 $data[$name] = $this->$name;
558 }
559
560 $ttl = $cache->adaptiveTTL(
561 (int)wfTimestamp( TS::UNIX, $this->mTouched ),
562 $ttl
563 );
564
565 if ( $wgFullyInitialised ) {
566 $groupMemberships = MediaWikiServices::getInstance()
567 ->getUserGroupManager()
568 ->getUserGroupMemberships( $this, $this->queryFlagsUsed );
569
570 // if a user group membership is about to expire, the cache needs to
571 // expire at that time (T163691)
572 foreach ( $groupMemberships as $ugm ) {
573 if ( $ugm->getExpiry() ) {
574 $secondsUntilExpiry =
575 (int)wfTimestamp( TS::UNIX, $ugm->getExpiry() ) - time();
576
577 if ( $secondsUntilExpiry > 0 && $secondsUntilExpiry < $ttl ) {
578 $ttl = $secondsUntilExpiry;
579 }
580 }
581 }
582 }
583
584 return $data;
585 },
586 [ 'pcTTL' => $cache::TTL_PROC_LONG, 'version' => self::VERSION ]
587 );
588
589 // Restore from cache
590 foreach ( self::$mCacheVars as $name ) {
591 $this->$name = $data[$name];
592 }
593
594 return true;
595 }
596
597 /***************************************************************************/
598 // region newFrom*() static factory methods
624 public static function newFromName( $name, $validate = 'valid' ) {
625 // Backwards compatibility with strings / false
626 $validation = match ( $validate ) {
627 'valid' => UserRigorOptions::RIGOR_VALID,
628 'usable' => UserRigorOptions::RIGOR_USABLE,
629 'creatable' => UserRigorOptions::RIGOR_CREATABLE,
630 true => UserRigorOptions::RIGOR_VALID,
631 false => UserRigorOptions::RIGOR_NONE,
632 // Not a recognized value, probably a test for unsupported validation
633 // levels, regardless, just pass it along
634 default => $validate,
635 };
636 return MediaWikiServices::getInstance()->getUserFactory()
637 ->newFromName( (string)$name, $validation ) ?? false;
638 }
639
650 public static function newFromId( $id ) {
651 return MediaWikiServices::getInstance()
652 ->getUserFactory()
653 ->newFromId( (int)$id );
654 }
655
667 public static function newFromActorId( $id ) {
668 return MediaWikiServices::getInstance()
669 ->getUserFactory()
670 ->newFromActorId( (int)$id );
671 }
672
686 public static function newFromIdentity( UserIdentity $identity ) {
687 // Don't use the service if we already have a User object,
688 // so that User::newFromIdentity calls don't break things in unit tests.
689 if ( $identity instanceof User ) {
690 return $identity;
691 }
692
693 return MediaWikiServices::getInstance()
694 ->getUserFactory()
695 ->newFromUserIdentity( $identity );
696 }
697
716 public static function newFromAnyId( $userId, $userName, $actorId, $dbDomain = false ) {
717 return MediaWikiServices::getInstance()
718 ->getUserFactory()
719 ->newFromAnyId( $userId, $userName, $actorId, $dbDomain );
720 }
721
737 public static function newFromConfirmationCode( $code, $flags = IDBAccessObject::READ_NORMAL ) {
738 return MediaWikiServices::getInstance()
739 ->getUserFactory()
740 ->newFromConfirmationCode( (string)$code, $flags );
741 }
742
750 public static function newFromSession( ?WebRequest $request = null ) {
751 $user = new User;
752 $user->mFrom = 'session';
753 $user->mRequest = $request;
754 return $user;
755 }
756
772 public static function newFromRow( $row, $data = null ) {
773 $user = new User;
774 $user->loadFromRow( $row, $data );
775 return $user;
776 }
777
822 public static function newSystemUser( $name, $options = [] ) {
823 $options += [
824 'validate' => UserRigorOptions::RIGOR_VALID,
825 'create' => true,
826 'steal' => false,
827 ];
828
829 // Username validation
830 $validate = $options['validate'];
831 // Backwards compatibility with strings / false
832 $validation = match ( $validate ) {
833 'valid' => UserRigorOptions::RIGOR_VALID,
834 'usable' => UserRigorOptions::RIGOR_USABLE,
835 'creatable' => UserRigorOptions::RIGOR_CREATABLE,
836 false => UserRigorOptions::RIGOR_NONE,
837 // Not a recognized value, probably a test for unsupported validation
838 // levels, regardless, just pass it along
839 default => $validate,
840 };
841
842 if ( $validation !== UserRigorOptions::RIGOR_VALID ) {
844 __METHOD__ . ' options["validation"] parameter must be omitted or set to "valid".',
845 '1.36'
846 );
847 }
848 $services = MediaWikiServices::getInstance();
849 $userNameUtils = $services->getUserNameUtils();
850
851 $name = $userNameUtils->getCanonical( (string)$name, $validation );
852 if ( $name === false ) {
853 return null;
854 }
855
856 $dbProvider = $services->getDBLoadBalancerFactory();
857 $dbr = $dbProvider->getReplicaDatabase();
858
859 $userQuery = self::newQueryBuilder( $dbr )
860 ->where( [ 'user_name' => $name ] )
861 ->caller( __METHOD__ );
862 $row = $userQuery->fetchRow();
863 if ( !$row ) {
864 // Try the primary database
865 $userQuery->connection( $dbProvider->getPrimaryDatabase() );
866 // Lock the row to prevent insertNewUser() returning null due to race conditions
867 $userQuery->forUpdate();
868 $row = $userQuery->fetchRow();
869 }
870
871 if ( !$row ) {
872 // No user. Create it?
873 if ( !$options['create'] ) {
874 // No.
875 return null;
876 }
877
878 // If it's a reserved user that had an anonymous actor created for it at
879 // some point, we need special handling.
880 return self::insertNewUser( static function ( UserIdentity $actor, IDatabase $dbw ) {
881 return MediaWikiServices::getInstance()->getActorStore()
882 ->acquireSystemActorId( $actor, $dbw );
883 }, $name, [ 'token' => self::INVALID_TOKEN ] );
884 }
885
886 $user = self::newFromRow( $row );
887
888 if ( !$user->isSystemUser() ) {
889 // User exists. Steal it?
890 if ( !$options['steal'] ) {
891 return null;
892 }
893
894 $services->getAuthManager()->revokeAccessForUser( $name );
895
896 $user->invalidateEmail();
897 $user->mToken = self::INVALID_TOKEN;
898 $user->saveSettings();
899 $manager = $services->getSessionManager();
900 if ( $manager instanceof SessionManager ) {
901 $manager->preventSessionsForUser( $user->getName() );
902 }
903 }
904
905 return $user;
906 }
907
909 // endregion -- end of newFrom*() static factory methods
910
921 public static function findUsersByGroup( $groups, $limit = 5000, $after = null ) {
922 if ( $groups === [] ) {
923 return UserArrayFromResult::newFromIDs( [] );
924 }
925 $dbr = MediaWikiServices::getInstance()->getConnectionProvider()->getReplicaDatabase();
926 $queryBuilder = $dbr->newSelectQueryBuilder()
927 ->select( 'ug_user' )
928 ->distinct()
929 ->from( 'user_groups' )
930 ->where( [ 'ug_group' => array_unique( (array)$groups ) ] )
931 ->orderBy( 'ug_user' )
932 ->limit( min( 5000, $limit ) );
933
934 if ( $after !== null ) {
935 $queryBuilder->andWhere( $dbr->expr( 'ug_user', '>', (int)$after ) );
936 }
937
938 $ids = $queryBuilder->caller( __METHOD__ )->fetchFieldValues() ?: [];
939 return UserArray::newFromIDs( $ids );
940 }
941
948 public function isValidPassword( $password ) {
949 // simple boolean wrapper for checkPasswordValidity
950 return $this->checkPasswordValidity( $password )->isGood();
951 }
952
974 public function checkPasswordValidity( $password ) {
975 $services = MediaWikiServices::getInstance();
976 $userNameUtils = $services->getUserNameUtils();
977 if ( $userNameUtils->isTemp( $this->getName() ) ) {
978 return Status::newFatal( 'error-temporary-accounts-cannot-have-passwords' );
979 }
980
981 $passwordPolicy = $services->getMainConfig()->get( MainConfigNames::PasswordPolicy );
982
983 $upp = new UserPasswordPolicy(
984 $passwordPolicy['policies'],
985 $passwordPolicy['checks']
986 );
987
988 $status = Status::newGood( [] );
989 $result = false; // init $result to false for the internal checks
990
991 if ( !$this->getHookRunner()->onIsValidPassword( $password, $result, $this ) ) {
992 $status->error( $result );
993 return $status;
994 }
995
996 if ( $result === false ) {
997 $status->merge( $upp->checkUserPassword( $this, $password ), true );
998 return $status;
999 }
1000
1001 if ( $result === true ) {
1002 return $status;
1003 }
1004
1005 $status->error( $result );
1006 return $status; // the isValidPassword hook set a string $result and returned true
1007 }
1008
1018 public function loadDefaults( $name = false, $actorId = null ) {
1019 $this->mId = 0;
1020 $this->mName = $name;
1021 $this->mActorId = $actorId;
1022 $this->mRealName = '';
1023 $this->mEmail = '';
1024 $this->isTemp = null;
1025
1026 $loggedOut = $this->mRequest && !defined( 'MW_NO_SESSION' )
1027 ? $this->mRequest->getSession()->getLoggedOutTimestamp() : 0;
1028 if ( $loggedOut !== 0 ) {
1029 $this->mTouched = wfTimestamp( TS::MW, $loggedOut );
1030 } else {
1031 $this->mTouched = '1'; # Allow any pages to be cached
1032 }
1033
1034 $this->mToken = null; // Don't run cryptographic functions till we need a token
1035 $this->mEmailAuthenticated = null;
1036 $this->mEmailToken = '';
1037 $this->mEmailTokenExpires = null;
1038
1039 $this->getHookRunner()->onUserLoadDefaults( $this, $name );
1040 }
1041
1054 public function isItemLoaded( $item, $all = 'all' ) {
1055 return ( $this->mLoadedItems === true && $all === 'all' ) ||
1056 ( isset( $this->mLoadedItems[$item] ) && $this->mLoadedItems[$item] === true );
1057 }
1058
1066 public function setItemLoaded( $item ) {
1067 if ( is_array( $this->mLoadedItems ) ) {
1068 $this->mLoadedItems[$item] = true;
1069 }
1070 }
1071
1077 private function loadFromSession() {
1078 // MediaWiki\Session\Session already did the necessary authentication of the user
1079 // returned here, so just use it if applicable.
1080 $session = $this->getRequest()->getSession();
1081 $user = $session->getUser();
1082 if ( $user->isRegistered() ) {
1083 $this->loadFromUserObject( $user );
1084
1085 // Other code expects these to be set in the session, so set them.
1086 $session->set( 'wsUserID', $this->getId() );
1087 $session->set( 'wsUserName', $this->getName() );
1088
1089 return true;
1090 }
1091
1092 return false;
1093 }
1094
1102 public function loadFromDatabase( $flags = IDBAccessObject::READ_LATEST ) {
1103 // Paranoia
1104 $this->mId = intval( $this->mId );
1105
1106 if ( !$this->mId ) {
1107 // Anonymous users are not in the database
1108 $this->loadDefaults();
1109 return false;
1110 }
1111
1112 $db = DBAccessObjectUtils::getDBFromRecency(
1113 MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
1114 $flags
1115 );
1116 $row = self::newQueryBuilder( $db )
1117 ->where( [ 'user_id' => $this->mId ] )
1118 ->recency( $flags )
1119 ->caller( __METHOD__ )
1120 ->fetchRow();
1121
1122 $this->queryFlagsUsed = $flags;
1123
1124 if ( $row !== false ) {
1125 // Initialise user table data
1126 $this->loadFromRow( $row );
1127 return true;
1128 }
1129
1130 // Invalid user_id
1131 $this->mId = 0;
1132 $this->loadDefaults( 'Unknown user' );
1133
1134 return false;
1135 }
1136
1148 protected function loadFromRow( $row, $data = null ) {
1149 if ( !( $row instanceof stdClass ) ) {
1150 throw new InvalidArgumentException( '$row must be an object' );
1151 }
1152
1153 $all = true;
1154
1155 if ( isset( $row->actor_id ) ) {
1156 $this->mActorId = (int)$row->actor_id;
1157 if ( $this->mActorId !== 0 ) {
1158 $this->mFrom = 'actor';
1159 }
1160 $this->setItemLoaded( 'actor' );
1161 } else {
1162 $all = false;
1163 }
1164
1165 if ( isset( $row->user_name ) && $row->user_name !== '' ) {
1166 $this->mName = $row->user_name;
1167 $this->mFrom = 'name';
1168 $this->setItemLoaded( 'name' );
1169 } else {
1170 $all = false;
1171 }
1172
1173 if ( isset( $row->user_real_name ) ) {
1174 $this->mRealName = $row->user_real_name;
1175 $this->setItemLoaded( 'realname' );
1176 } else {
1177 $all = false;
1178 }
1179
1180 if ( isset( $row->user_id ) ) {
1181 $this->mId = intval( $row->user_id );
1182 if ( $this->mId !== 0 ) {
1183 $this->mFrom = 'id';
1184 }
1185 $this->setItemLoaded( 'id' );
1186 } else {
1187 $all = false;
1188 }
1189
1190 if ( isset( $row->user_editcount ) ) {
1191 // Don't try to set edit count for anonymous users
1192 // We check the id here and not in UserEditTracker because calling
1193 // User::getId() can trigger some other loading. This will result in
1194 // discarding the user_editcount field for rows if the id wasn't set.
1195 if ( $this->mId !== null && $this->mId !== 0 ) {
1196 MediaWikiServices::getInstance()
1197 ->getUserEditTracker()
1198 ->setCachedUserEditCount( $this, (int)$row->user_editcount );
1199 }
1200 } else {
1201 $all = false;
1202 }
1203
1204 if ( isset( $row->user_touched ) ) {
1205 $this->mTouched = wfTimestamp( TS::MW, $row->user_touched );
1206 } else {
1207 $all = false;
1208 }
1209
1210 if ( isset( $row->user_token ) ) {
1211 // The definition for the column is binary(32), so trim the NULs
1212 // that appends. The previous definition was char(32), so trim
1213 // spaces too.
1214 $this->mToken = rtrim( $row->user_token, " \0" );
1215 if ( $this->mToken === '' ) {
1216 $this->mToken = null;
1217 }
1218 } else {
1219 $all = false;
1220 }
1221
1222 if ( isset( $row->user_email ) ) {
1223 $this->mEmail = $row->user_email;
1224 $this->mEmailAuthenticated = wfTimestampOrNull( TS::MW, $row->user_email_authenticated );
1225 $this->mEmailToken = $row->user_email_token;
1226 $this->mEmailTokenExpires = wfTimestampOrNull( TS::MW, $row->user_email_token_expires );
1227 $registration = wfTimestampOrNull( TS::MW, $row->user_registration );
1228 MediaWikiServices::getInstance()
1229 ->getUserRegistrationLookup()
1230 ->setCachedRegistration( $this, $registration );
1231 } else {
1232 $all = false;
1233 }
1234
1235 if ( $all ) {
1236 $this->mLoadedItems = true;
1237 }
1238
1239 if ( is_array( $data ) ) {
1240
1241 if ( isset( $data['user_groups'] ) && is_array( $data['user_groups'] ) ) {
1242 MediaWikiServices::getInstance()
1243 ->getUserGroupManager()
1244 ->loadGroupMembershipsFromArray(
1245 $this,
1246 $data['user_groups'],
1247 $this->queryFlagsUsed
1248 );
1249 }
1250 }
1251 }
1252
1258 protected function loadFromUserObject( $user ) {
1259 $user->load();
1260 foreach ( self::$mCacheVars as $var ) {
1261 $this->$var = $user->$var;
1262 }
1263 }
1264
1272 protected function makeUpdateConditions( IReadableDatabase $db ) {
1273 if ( $this->mTouched ) {
1274 // CAS check: only update if the row wasn't changed since it was loaded.
1275 return [ 'user_touched' => $db->timestamp( $this->mTouched ) ];
1276 }
1277 return [];
1278 }
1279
1290 public function checkAndSetTouched() {
1291 $this->load();
1292
1293 if ( !$this->mId ) {
1294 return false; // anon
1295 }
1296
1297 // Get a new user_touched that is higher than the old one
1298 $newTouched = $this->newTouchedTimestamp();
1299
1300 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
1301 $dbw->newUpdateQueryBuilder()
1302 ->update( 'user' )
1303 ->set( [ 'user_touched' => $dbw->timestamp( $newTouched ) ] )
1304 ->where( [ 'user_id' => $this->mId ] )
1305 ->andWhere( $this->makeUpdateConditions( $dbw ) )
1306 ->caller( __METHOD__ )->execute();
1307 $success = ( $dbw->affectedRows() > 0 );
1308
1309 if ( $success ) {
1310 $this->mTouched = $newTouched;
1311 $this->clearSharedCache( 'changed' );
1312 } else {
1313 // Clears on failure too since that is desired if the cache is stale
1314 $this->clearSharedCache( 'refresh' );
1315 }
1316
1317 return $success;
1318 }
1319
1327 public function clearInstanceCache( $reloadFrom = false ) {
1328 global $wgFullyInitialised;
1329
1330 $this->mDatePreference = null;
1331 $this->mThisAsAuthority = null;
1332
1333 if ( $wgFullyInitialised && $this->mFrom ) {
1334 $services = MediaWikiServices::getInstance();
1335
1336 if ( $services->peekService( 'PermissionManager' ) ) {
1337 $services->getPermissionManager()->invalidateUsersRightsCache( $this );
1338 }
1339
1340 if ( $services->peekService( 'UserOptionsManager' ) ) {
1341 $services->getUserOptionsManager()->clearUserOptionsCache( $this );
1342 }
1343
1344 if ( $services->peekService( 'TalkPageNotificationManager' ) ) {
1345 $services->getTalkPageNotificationManager()->clearInstanceCache( $this );
1346 }
1347
1348 if ( $services->peekService( 'UserGroupManager' ) ) {
1349 $services->getUserGroupManager()->clearCache( $this );
1350 }
1351
1352 if ( $services->peekService( 'UserEditTracker' ) ) {
1353 $services->getUserEditTracker()->clearUserEditCache( $this );
1354 }
1355
1356 if ( $services->peekService( 'BlockManager' ) ) {
1357 $services->getBlockManager()->clearUserCache( $this );
1358 }
1359 }
1360
1361 if ( $reloadFrom ) {
1362 if ( in_array( $reloadFrom, [ 'name', 'id', 'actor' ] ) ) {
1363 $this->mLoadedItems = [ $reloadFrom => true ];
1364 } else {
1365 $this->mLoadedItems = [];
1366 }
1367 $this->mFrom = $reloadFrom;
1368 }
1369 }
1370
1376 public function isPingLimitable() {
1377 $limiter = MediaWikiServices::getInstance()->getRateLimiter();
1378 $subject = $this->toRateLimitSubject();
1379 return !$limiter->isExempt( $subject );
1380 }
1381
1397 public function pingLimiter( $action = 'edit', $incrBy = 1 ) {
1398 return $this->getThisAsAuthority()->limit( $action, $incrBy, null );
1399 }
1400
1406 $flags = [
1407 'exempt' => $this->isAllowed( 'noratelimit' ),
1408 'newbie' => $this->isNewbie(),
1409 ];
1410
1411 return new RateLimitSubject( $this, $this->getRequest()->getIP(), $flags );
1412 }
1413
1426 public function getBlock(
1427 $freshness = IDBAccessObject::READ_NORMAL,
1428 $disableIpBlockExemptChecking = false
1429 ): ?Block {
1430 if ( is_bool( $freshness ) ) {
1431 $fromReplica = $freshness;
1432 } else {
1433 $fromReplica = ( $freshness !== IDBAccessObject::READ_LATEST );
1434 }
1435
1436 if ( $disableIpBlockExemptChecking ) {
1437 $isExempt = false;
1438 } else {
1439 $isExempt = $this->isAllowed( 'ipblock-exempt' );
1440 }
1441
1442 // TODO: Block checking shouldn't really be done from the User object. Block
1443 // checking can involve checking for IP blocks, cookie blocks, and/or XFF blocks,
1444 // which need more knowledge of the request context than the User should have.
1445 // Since we do currently check blocks from the User, we have to do the following
1446 // here:
1447 // - Check if this is the user associated with the main request
1448 // - If so, pass the relevant request information to the block manager
1449 $request = null;
1450 if ( !$isExempt && $this->isGlobalSessionUser() ) {
1451 // This is the global user, so we need to pass the request
1452 $request = $this->getRequest();
1453 }
1454
1455 return MediaWikiServices::getInstance()->getBlockManager()->getBlock(
1456 $this,
1457 $request,
1458 $fromReplica,
1459 );
1460 }
1461
1467 public function isLocked() {
1468 if ( $this->mLocked !== null ) {
1469 return $this->mLocked;
1470 }
1471 // Reset for hook
1472 $this->mLocked = false;
1473 $this->getHookRunner()->onUserIsLocked( $this, $this->mLocked );
1474 return $this->mLocked;
1475 }
1476
1482 public function isHidden() {
1483 $block = $this->getBlock( disableIpBlockExemptChecking: true );
1484 return $block ? $block->getHideName() : false;
1485 }
1486
1492 public function getId( $wikiId = self::LOCAL ): int {
1493 $this->assertWiki( $wikiId );
1494 if ( $this->mId === null && $this->mName !== null ) {
1495 $userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils();
1496 if ( $userNameUtils->isIP( $this->mName ) || ExternalUserNames::isExternal( $this->mName ) ) {
1497 // Special case, we know the user is anonymous
1498 // Note that "external" users are "local" (they have an actor ID that is relative to
1499 // the local wiki).
1500 return 0;
1501 }
1502 }
1503
1504 if ( !$this->isItemLoaded( 'id' ) ) {
1505 // Don't load if this was initialized from an ID
1506 $this->load();
1507 }
1508
1509 return (int)$this->mId;
1510 }
1511
1516 public function setId( $v ) {
1517 $this->mId = $v;
1518 $this->clearInstanceCache( 'id' );
1519 }
1520
1525 public function getName(): string {
1526 if ( $this->isItemLoaded( 'name', 'only' ) ) {
1527 // Special case optimisation
1528 return $this->mName;
1529 }
1530
1531 $this->load();
1532 if ( $this->mName === false ) {
1533 // Clean up IPs
1534 $this->mName = IPUtils::sanitizeIP( $this->getRequest()->getIP() );
1535 }
1536
1537 return $this->mName;
1538 }
1539
1553 public function setName( $str ) {
1554 $this->load();
1555 $this->mName = $str;
1556 }
1557
1571 public function getActorId( $dbwOrWikiId = self::LOCAL ): int {
1572 if ( $dbwOrWikiId ) {
1573 wfDeprecatedMsg( 'Passing a parameter to getActorId() is deprecated', '1.36' );
1574 }
1575
1576 if ( is_string( $dbwOrWikiId ) ) {
1577 $this->assertWiki( $dbwOrWikiId );
1578 }
1579
1580 if ( !$this->isItemLoaded( 'actor' ) ) {
1581 $this->load();
1582 }
1583
1584 if ( !$this->mActorId && $dbwOrWikiId instanceof IDatabase ) {
1585 MediaWikiServices::getInstance()
1586 ->getActorStoreFactory()
1587 ->getActorNormalization( $dbwOrWikiId->getDomainID() )
1588 ->acquireActorId( $this, $dbwOrWikiId );
1589 // acquireActorId will call setActorId on $this
1590 Assert::postcondition(
1591 $this->mActorId !== null,
1592 "Failed to acquire actor ID for user id {$this->mId} name {$this->mName}"
1593 );
1594 }
1595
1596 return (int)$this->mActorId;
1597 }
1598
1608 public function setActorId( int $actorId ) {
1609 $this->mActorId = $actorId;
1610 $this->setItemLoaded( 'actor' );
1611 }
1612
1617 public function getTitleKey(): string {
1618 return str_replace( ' ', '_', $this->getName() );
1619 }
1620
1627 private function newTouchedTimestamp() {
1628 $time = (int)ConvertibleTimestamp::now( TS::UNIX );
1629 if ( $this->mTouched ) {
1630 $time = max( $time, (int)ConvertibleTimestamp::convert( TS::UNIX, $this->mTouched ) + 1 );
1631 }
1632
1633 return ConvertibleTimestamp::convert( TS::MW, $time );
1634 }
1635
1646 public function clearSharedCache( $mode = 'refresh' ) {
1647 if ( !$this->getId() ) {
1648 return;
1649 }
1650
1651 $dbProvider = MediaWikiServices::getInstance()->getConnectionProvider();
1652 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1653 $key = $this->getCacheKey( $cache );
1654
1655 if ( $mode === 'refresh' ) {
1656 $cache->delete( $key, 1 ); // low tombstone/"hold-off" TTL
1657 } else {
1658 $dbProvider->getPrimaryDatabase()->onTransactionPreCommitOrIdle(
1659 static function () use ( $cache, $key ) {
1660 $cache->delete( $key );
1661 },
1662 __METHOD__
1663 );
1664 }
1665 }
1666
1672 public function invalidateCache() {
1673 $this->touch();
1674 $this->clearSharedCache( 'changed' );
1675 }
1676
1689 public function touch() {
1690 $id = $this->getId();
1691 if ( $id ) {
1692 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1693 $key = $cache->makeKey( 'user-quicktouched', 'id', $id );
1694 $cache->touchCheckKey( $key );
1695 $this->mQuickTouched = null;
1696 }
1697 }
1698
1704 public function debouncedDBTouch() {
1705 $oldTouched = (int)ConvertibleTimestamp::convert( TS::UNIX, $this->getDBTouched() );
1706 $newTouched = (int)ConvertibleTimestamp::now( TS::UNIX );
1707
1708 if ( ( $newTouched - $oldTouched ) < ( 300 + mt_rand( 1, 20 ) ) ) {
1709 // Touched would be updated too soon, skip this round
1710 // Adding jitter to avoid stampede.
1711 return;
1712 }
1713
1714 // Too old, definitely update.
1715 $this->checkAndSetTouched();
1716 }
1717
1723 public function validateCache( $timestamp ) {
1724 return ( $timestamp >= $this->getTouched() );
1725 }
1726
1735 public function getTouched() {
1736 $this->load();
1737
1738 if ( $this->mId ) {
1739 if ( $this->mQuickTouched === null ) {
1740 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
1741 $key = $cache->makeKey( 'user-quicktouched', 'id', $this->mId );
1742
1743 $this->mQuickTouched = wfTimestamp( TS::MW, $cache->getCheckKeyTime( $key ) );
1744 }
1745
1746 return max( $this->mTouched, $this->mQuickTouched );
1747 }
1748
1749 return $this->mTouched;
1750 }
1751
1757 public function getDBTouched() {
1758 $this->load();
1759
1760 return $this->mTouched;
1761 }
1762
1775 public function changeAuthenticationData( array $data ) {
1776 $manager = MediaWikiServices::getInstance()->getAuthManager();
1777 $reqs = $manager->getAuthenticationRequests( AuthManager::ACTION_CHANGE, $this );
1778 $reqs = AuthenticationRequest::loadRequestsFromSubmission( $reqs, $data );
1779
1780 $status = Status::newGood( 'ignored' );
1781 foreach ( $reqs as $req ) {
1782 $status->merge( $manager->allowsAuthenticationDataChange( $req ), true );
1783 }
1784 if ( $status->getValue() === 'ignored' ) {
1785 $status->warning( 'authenticationdatachange-ignored' );
1786 }
1787
1788 if ( $status->isGood() ) {
1789 foreach ( $reqs as $req ) {
1790 $manager->changeAuthenticationData( $req );
1791 }
1792 }
1793 return $status;
1794 }
1795
1802 public function getToken( $forceCreation = true ) {
1803 $authenticationTokenVersion = MediaWikiServices::getInstance()
1804 ->getMainConfig()->get( MainConfigNames::AuthenticationTokenVersion );
1805
1806 $this->load();
1807 if ( !$this->mToken && $forceCreation ) {
1808 $this->setToken();
1809 }
1810
1811 if ( !$this->mToken ) {
1812 // The user doesn't have a token, return null to indicate that.
1813 return null;
1814 }
1815
1816 if ( $this->mToken === self::INVALID_TOKEN ) {
1817 // We return a random value here so existing token checks are very
1818 // likely to fail.
1819 return MWCryptRand::generateHex( self::TOKEN_LENGTH );
1820 }
1821
1822 if ( $authenticationTokenVersion === null ) {
1823 // $wgAuthenticationTokenVersion not in use, so return the raw secret
1824 return $this->mToken;
1825 }
1826
1827 // $wgAuthenticationTokenVersion in use, so hmac it.
1828 $ret = MWCryptHash::hmac( $authenticationTokenVersion, $this->mToken, false );
1829
1830 // The raw hash can be overly long. Shorten it up.
1831 $len = max( 32, self::TOKEN_LENGTH );
1832 if ( strlen( $ret ) < $len ) {
1833 // Should never happen, even md5 is 128 bits
1834 throw new \UnexpectedValueException( 'Hmac returned less than 128 bits' );
1835 }
1836
1837 return substr( $ret, -$len );
1838 }
1839
1846 public function setToken( $token = false ) {
1847 $this->load();
1848 if ( $this->mToken === self::INVALID_TOKEN ) {
1849 LoggerFactory::getInstance( 'session' )
1850 ->debug( __METHOD__ . ": Ignoring attempt to set token for system user \"$this\"" );
1851 } elseif ( !$token ) {
1852 $this->mToken = MWCryptRand::generateHex( self::TOKEN_LENGTH );
1853 } else {
1854 $this->mToken = $token;
1855 }
1856 }
1857
1862 public function getEmail(): string {
1863 $this->load();
1864 $email = $this->mEmail;
1865 $this->getHookRunner()->onUserGetEmail( $this, $email );
1866 // In case a hook handler returns e.g. null
1867 $this->mEmail = is_string( $email ) ? $email : '';
1868 return $this->mEmail;
1869 }
1870
1876 $this->load();
1877 $this->getHookRunner()->onUserGetEmailAuthenticationTimestamp(
1878 $this, $this->mEmailAuthenticated );
1879 return $this->mEmailAuthenticated;
1880 }
1881
1886 public function setEmail( string $str ) {
1887 $this->load();
1888 if ( $str == $this->getEmail() ) {
1889 return;
1890 }
1891 $this->invalidateEmail();
1892 $this->mEmail = $str;
1893 $this->getHookRunner()->onUserSetEmail( $this, $this->mEmail );
1894 }
1895
1903 public function setEmailWithConfirmation( string $str ) {
1904 $config = MediaWikiServices::getInstance()->getMainConfig();
1905 $enableEmail = $config->get( MainConfigNames::EnableEmail );
1906
1907 if ( !$enableEmail ) {
1908 return Status::newFatal( 'emaildisabled' );
1909 }
1910
1911 $oldaddr = $this->getEmail();
1912 if ( $str === $oldaddr ) {
1913 return Status::newGood( true );
1914 }
1915
1916 $type = $oldaddr != '' ? 'changed' : 'set';
1917 $notificationResult = null;
1918
1919 $emailAuthentication = $config->get( MainConfigNames::EmailAuthentication );
1920
1921 if ( $emailAuthentication && $type === 'changed' && $this->isEmailConfirmed() ) {
1922 $change = $str != '' ? 'changed' : 'removed';
1923 $notificationResult = Status::wrap(
1924 MediaWikiServices::getInstance()->getNotificationEmailSender()->sendNotificationMail(
1925 RequestContext::getMain(),
1926 $this,
1927 $change,
1928 $str
1929 )
1930 );
1931 }
1932
1933 $this->setEmail( $str );
1934
1935 if ( $str !== '' && $emailAuthentication ) {
1936 // Send a confirmation request to the new address if needed
1937 $result = $this->sendConfirmationMail( $type );
1938
1939 if ( $notificationResult !== null ) {
1940 $result->merge( $notificationResult );
1941 }
1942
1943 if ( $result->isGood() ) {
1944 // Say to the caller that a confirmation and notification mail has been sent
1945 $result->value = 'eauth';
1946 }
1947 } else {
1948 $result = Status::newGood( true );
1949 }
1950
1951 return $result;
1952 }
1953
1958 public function getRealName(): string {
1959 if ( !$this->isItemLoaded( 'realname' ) ) {
1960 $this->load();
1961 }
1962
1963 return $this->mRealName;
1964 }
1965
1970 public function setRealName( string $str ) {
1971 $this->load();
1972 $this->mRealName = $str;
1973 }
1974
1985 public function getTokenFromOption( $oname ) {
1986 $hiddenPrefs =
1987 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::HiddenPrefs );
1988
1989 $id = $this->getId();
1990 if ( !$id || in_array( $oname, $hiddenPrefs ) ) {
1991 return false;
1992 }
1993
1994 $userOptionsLookup = MediaWikiServices::getInstance()
1995 ->getUserOptionsLookup();
1996 $token = $userOptionsLookup->getOption( $this, (string)$oname );
1997 if ( !$token ) {
1998 // Default to a value based on the user token to avoid space
1999 // wasted on storing tokens for all users. When this option
2000 // is set manually by the user, only then is it stored.
2001 $token = hash_hmac( 'sha1', "$oname:$id", $this->getToken() );
2002 }
2003
2004 return $token;
2005 }
2006
2016 public function resetTokenFromOption( $oname ) {
2017 $hiddenPrefs =
2018 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::HiddenPrefs );
2019 if ( in_array( $oname, $hiddenPrefs ) ) {
2020 return false;
2021 }
2022
2023 $token = MWCryptRand::generateHex( 40 );
2024 MediaWikiServices::getInstance()
2025 ->getUserOptionsManager()
2026 ->setOption( $this, $oname, $token );
2027 return $token;
2028 }
2029
2034 public function getDatePreference() {
2035 // Important migration for old data rows
2036 if ( $this->mDatePreference === null ) {
2037 $lang = RequestContext::getMain()->getLanguage();
2038 $userOptionsLookup = MediaWikiServices::getInstance()
2039 ->getUserOptionsLookup();
2040 $value = $userOptionsLookup->getOption( $this, 'date' ) ?? 'default';
2041 $map = $lang->getDatePreferenceMigrationMap();
2042 if ( isset( $map[$value] ) ) {
2043 $value = $map[$value];
2044 }
2045 $this->mDatePreference = $value;
2046 }
2047 return $this->mDatePreference;
2048 }
2049
2056 public function requiresHTTPS() {
2057 if ( !$this->isRegistered() ) {
2058 return false;
2059 }
2060
2061 $services = MediaWikiServices::getInstance();
2062 $config = $services->getMainConfig();
2063 if ( $config->get( MainConfigNames::ForceHTTPS ) ) {
2064 return true;
2065 }
2066 if ( !$config->get( MainConfigNames::SecureLogin ) ) {
2067 return false;
2068 }
2069 return $services->getUserOptionsLookup()
2070 ->getBoolOption( $this, 'prefershttps' );
2071 }
2072
2077 public function getEditCount() {
2078 return MediaWikiServices::getInstance()
2079 ->getUserEditTracker()
2080 ->getUserEditCount( $this );
2081 }
2082
2091 public function isRegistered(): bool {
2092 return $this->getId() != 0;
2093 }
2094
2099 public function isAnon() {
2100 return !$this->isRegistered();
2101 }
2102
2107 public function isBot() {
2108 $userGroupManager = MediaWikiServices::getInstance()->getUserGroupManager();
2109 if ( in_array( 'bot', $userGroupManager->getUserGroups( $this ) )
2110 && $this->isAllowed( 'bot' )
2111 ) {
2112 return true;
2113 }
2114
2115 $isBot = false;
2116 $this->getHookRunner()->onUserIsBot( $this, $isBot );
2117
2118 return $isBot;
2119 }
2120
2130 public function isSystemUser() {
2131 $this->load();
2132 if ( $this->getEmail() || $this->mToken !== self::INVALID_TOKEN ||
2133 MediaWikiServices::getInstance()->getAuthManager()->userCanAuthenticate( $this->mName )
2134 ) {
2135 return false;
2136 }
2137 return true;
2138 }
2139
2141 public function isAllowedAny( ...$permissions ): bool {
2142 return $this->getThisAsAuthority()->isAllowedAny( ...$permissions );
2143 }
2144
2146 public function isAllowedAll( ...$permissions ): bool {
2147 return $this->getThisAsAuthority()->isAllowedAll( ...$permissions );
2148 }
2149
2150 public function isAllowed( string $permission, ?PermissionStatus $status = null ): bool {
2151 return $this->getThisAsAuthority()->isAllowed( $permission, $status );
2152 }
2153
2158 public function useRCPatrol() {
2159 $useRCPatrol =
2160 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseRCPatrol );
2161 return $useRCPatrol && $this->isAllowedAny( 'patrol', 'patrolmarks' );
2162 }
2163
2168 public function useNPPatrol() {
2169 $useRCPatrol =
2170 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseRCPatrol );
2171 $useNPPatrol =
2172 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseNPPatrol );
2173 return (
2174 ( $useRCPatrol || $useNPPatrol )
2175 && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
2176 );
2177 }
2178
2183 public function useFilePatrol() {
2184 $useRCPatrol =
2185 MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::UseRCPatrol );
2186 $useFilePatrol = MediaWikiServices::getInstance()->getMainConfig()
2187 ->get( MainConfigNames::UseFilePatrol );
2188 return (
2189 ( $useRCPatrol || $useFilePatrol )
2190 && ( $this->isAllowedAny( 'patrol', 'patrolmarks' ) )
2191 );
2192 }
2193
2197 public function getRequest(): WebRequest {
2198 return $this->mRequest ?? RequestContext::getMain()->getRequest();
2199 }
2200
2206 public function getExperienceLevel() {
2207 $mainConfig = MediaWikiServices::getInstance()->getMainConfig();
2208 $learnerEdits = $mainConfig->get( MainConfigNames::LearnerEdits );
2209 $experiencedUserEdits = $mainConfig->get( MainConfigNames::ExperiencedUserEdits );
2210 $learnerMemberSince = $mainConfig->get( MainConfigNames::LearnerMemberSince );
2211 $experiencedUserMemberSince =
2212 $mainConfig->get( MainConfigNames::ExperiencedUserMemberSince );
2213 if ( $this->isAnon() ) {
2214 return false;
2215 }
2216
2217 $editCount = $this->getEditCount();
2218 $registration = $this->getRegistration();
2219 $now = time();
2220 $learnerRegistration = wfTimestamp( TS::MW, $now - $learnerMemberSince * 86400 );
2221 $experiencedRegistration = wfTimestamp( TS::MW, $now - $experiencedUserMemberSince * 86400 );
2222 if ( $registration === null ) {
2223 // for some very old accounts, this information is missing in the database
2224 // treat them as old enough to be 'experienced'
2225 $registration = $experiencedRegistration;
2226 }
2227
2228 if ( $editCount < $learnerEdits ||
2229 $registration > $learnerRegistration ) {
2230 return 'newcomer';
2231 }
2232
2233 if ( $editCount > $experiencedUserEdits &&
2234 $registration <= $experiencedRegistration
2235 ) {
2236 return 'experienced';
2237 }
2238
2239 return 'learner';
2240 }
2241
2250 public function setCookies( $request = null, $secure = null, $rememberMe = false ) {
2251 $this->load();
2252 if ( $this->mId == 0 ) {
2253 return;
2254 }
2255
2256 $session = $this->getRequest()->getSession();
2257 if ( $request && $session->getRequest() !== $request ) {
2258 $session = $session->sessionWithRequest( $request );
2259 }
2260 $delay = $session->delaySave();
2261
2262 if ( !$session->getUser()->equals( $this ) ) {
2263 if ( !$session->canSetUser() ) {
2264 LoggerFactory::getInstance( 'session' )
2265 ->warning( __METHOD__ .
2266 ": Cannot save user \"$this\" to a user " .
2267 "\"{$session->getUser()}\"'s immutable session"
2268 );
2269 return;
2270 }
2271 $session->setUser( $this );
2272 }
2273
2274 $session->setRememberUser( $rememberMe );
2275 if ( $secure !== null ) {
2276 $session->setForceHTTPS( $secure );
2277 }
2278
2279 $session->persist();
2280
2281 ScopedCallback::consume( $delay );
2282 }
2283
2287 public function logout() {
2288 if ( $this->getHookRunner()->onUserLogout( $this ) ) {
2289 $this->doLogout();
2290 }
2291 }
2292
2297 public function doLogout() {
2298 $session = $this->getRequest()->getSession();
2299 $accountType = MediaWikiServices::getInstance()->getUserIdentityUtils()->getShortUserTypeInternal( $this );
2300 if ( !$session->canSetUser() ) {
2301 LoggerFactory::getInstance( 'session' )
2302 ->warning( __METHOD__ . ": Cannot log out of an immutable session" );
2303 $error = 'immutable';
2304 } elseif ( !$session->getUser()->equals( $this ) ) {
2305 LoggerFactory::getInstance( 'session' )
2306 ->warning( __METHOD__ .
2307 ": Cannot log user \"$this\" out of a user \"{$session->getUser()}\"'s session"
2308 );
2309 // But we still may as well make this user object anon
2310 $this->clearInstanceCache( 'defaults' );
2311 $error = 'wronguser';
2312 } else {
2313 $this->clearInstanceCache( 'defaults' );
2314 $delay = $session->delaySave();
2315 $session->unpersist(); // Clear cookies (T127436)
2316 $session->setLoggedOutTimestamp( time() );
2317 $session->setUser( new User );
2318 $session->set( 'wsUserID', 0 ); // Other code expects this
2319 $session->resetAllTokens();
2320 ScopedCallback::consume( $delay );
2321 $error = false;
2322 }
2323 LoggerFactory::getInstance( 'authevents' )->info( 'Logout', [
2324 'event' => 'logout',
2325 'successful' => $error === false,
2326 'status' => $error ?: 'success',
2327 'accountType' => $accountType,
2328 ] );
2329 }
2330
2335 public function saveSettings() {
2336 if ( MediaWikiServices::getInstance()->getReadOnlyMode()->isReadOnly() ) {
2337 // @TODO: caller should deal with this instead!
2338 // This should really just be an exception.
2339 MWExceptionHandler::logException( new DBExpectedError(
2340 null,
2341 "Could not update user with ID '{$this->mId}'; DB is read-only."
2342 ) );
2343 return;
2344 }
2345
2346 $this->load();
2347 if ( $this->mId == 0 ) {
2348 return; // anon
2349 }
2350
2351 // Get a new user_touched that is higher than the old one.
2352 // This will be used for a CAS check as a last-resort safety
2353 // check against race conditions and replica DB lag.
2354 $newTouched = $this->newTouchedTimestamp();
2355
2356 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
2357 $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $newTouched ) {
2358 $dbw->newUpdateQueryBuilder()
2359 ->update( 'user' )
2360 ->set( [
2361 'user_name' => $this->mName,
2362 'user_real_name' => $this->mRealName,
2363 'user_email' => $this->mEmail,
2364 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
2365 'user_touched' => $dbw->timestamp( $newTouched ),
2366 'user_token' => strval( $this->mToken ),
2367 'user_email_token' => $this->mEmailToken,
2368 'user_email_token_expires' => $dbw->timestampOrNull( $this->mEmailTokenExpires ),
2369 ] )
2370 ->where( [ 'user_id' => $this->mId ] )
2371 ->andWhere( $this->makeUpdateConditions( $dbw ) )
2372 ->caller( $fname )->execute();
2373
2374 if ( !$dbw->affectedRows() ) {
2375 // Maybe the problem was a missed cache update; clear it to be safe
2376 $this->clearSharedCache( 'refresh' );
2377 // User was changed in the meantime or loaded with stale data
2378 $from = ( $this->queryFlagsUsed & IDBAccessObject::READ_LATEST ) ? 'primary' : 'replica';
2379 LoggerFactory::getInstance( 'preferences' )->warning(
2380 "CAS update failed on user_touched for user ID '{user_id}' ({db_flag} read)",
2381 [ 'user_id' => $this->mId, 'db_flag' => $from ]
2382 );
2383 throw new RuntimeException( "CAS update failed on user_touched. " .
2384 "The version of the user to be saved is older than the current version."
2385 );
2386 }
2387
2388 $dbw->newUpdateQueryBuilder()
2389 ->update( 'actor' )
2390 ->set( [ 'actor_name' => $this->mName ] )
2391 ->where( [ 'actor_user' => $this->mId ] )
2392 ->caller( $fname )->execute();
2393 MediaWikiServices::getInstance()->getActorStore()->deleteUserIdentityFromCache( $this );
2394 } );
2395
2396 $this->mTouched = $newTouched;
2397 if ( $this->isNamed() ) {
2398 MediaWikiServices::getInstance()->getUserOptionsManager()->saveOptionsInternal( $this );
2399 }
2400
2401 $this->getHookRunner()->onUserSaveSettings( $this );
2402 $this->clearSharedCache( 'changed' );
2403 $hcu = MediaWikiServices::getInstance()->getHTMLCacheUpdater();
2404 $hcu->purgeTitleUrls( $this->getUserPage(), $hcu::PURGE_INTENT_TXROUND_REFLECTED );
2405 }
2406
2413 public function idForName( $flags = IDBAccessObject::READ_NORMAL ) {
2414 $s = trim( $this->getName() );
2415 if ( $s === '' ) {
2416 return 0;
2417 }
2418
2419 $db = DBAccessObjectUtils::getDBFromRecency(
2420 MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
2421 $flags
2422 );
2423 $id = $db->newSelectQueryBuilder()
2424 ->select( 'user_id' )
2425 ->from( 'user' )
2426 ->where( [ 'user_name' => $s ] )
2427 ->recency( $flags )
2428 ->caller( __METHOD__ )->fetchField();
2429
2430 return (int)$id;
2431 }
2432
2446 public static function createNew( $name, $params = [] ) {
2447 return self::insertNewUser( static function ( UserIdentity $actor, IDatabase $dbw ) {
2448 return MediaWikiServices::getInstance()->getActorStore()->createNewActor( $actor, $dbw );
2449 }, $name, $params );
2450 }
2451
2459 private static function insertNewUser( callable $insertActor, $name, $params = [] ) {
2460 foreach ( [ 'password', 'newpassword', 'newpass_time', 'password_expires' ] as $field ) {
2461 if ( isset( $params[$field] ) ) {
2462 wfDeprecated( __METHOD__ . " with param '$field'", '1.27' );
2463 unset( $params[$field] );
2464 }
2465 }
2466
2467 $user = new User;
2468 $user->load();
2469 $user->setToken(); // init token
2470 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
2471
2472 $noPass = PasswordFactory::newInvalidPassword()->toString();
2473
2474 $fields = [
2475 'user_name' => $name,
2476 'user_password' => $noPass,
2477 'user_newpassword' => $noPass,
2478 'user_email' => $user->mEmail,
2479 'user_email_authenticated' => $dbw->timestampOrNull( $user->mEmailAuthenticated ),
2480 'user_real_name' => $user->mRealName,
2481 'user_token' => strval( $user->mToken ),
2482 'user_registration' => $dbw->timestamp(),
2483 'user_editcount' => 0,
2484 'user_touched' => $dbw->timestamp( $user->newTouchedTimestamp() ),
2485 ];
2486 foreach ( $params as $name => $value ) {
2487 $fields["user_$name"] = $value;
2488 }
2489
2490 return $dbw->doAtomicSection( __METHOD__, static function ( IDatabase $dbw, $fname )
2491 use ( $fields, $insertActor )
2492 {
2493 $dbw->newInsertQueryBuilder()
2494 ->insertInto( 'user' )
2495 ->ignore()
2496 ->row( $fields )
2497 ->caller( $fname )->execute();
2498 if ( $dbw->affectedRows() ) {
2499 $newUser = self::newFromId( $dbw->insertId() );
2500 $newUser->mName = $fields['user_name'];
2501 // Don't pass $this, since calling ::getId, ::getName might force ::load
2502 // and this user might not be ready for the yet.
2503 $newUser->mActorId = $insertActor(
2504 new UserIdentityValue( $newUser->mId, $newUser->mName ),
2505 $dbw
2506 );
2507 // Load the user from primary DB to avoid replica lag
2508 $newUser->load( IDBAccessObject::READ_LATEST );
2509 } else {
2510 $newUser = null;
2511 }
2512 return $newUser;
2513 } );
2514 }
2515
2541 public function addToDatabase() {
2542 $this->load();
2543 if ( !$this->mToken ) {
2544 $this->setToken(); // init token
2545 }
2546
2547 if ( !is_string( $this->mName ) ) {
2548 throw new RuntimeException( "User name field is not set." );
2549 }
2550
2551 $this->mTouched = $this->newTouchedTimestamp();
2552
2553 $dbw = MediaWikiServices::getInstance()->getConnectionProvider()->getPrimaryDatabase();
2554 $status = $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) {
2555 $noPass = PasswordFactory::newInvalidPassword()->toString();
2556 $dbw->newInsertQueryBuilder()
2557 ->insertInto( 'user' )
2558 ->ignore()
2559 ->row( [
2560 'user_name' => $this->mName,
2561 'user_password' => $noPass,
2562 'user_newpassword' => $noPass,
2563 'user_email' => $this->mEmail,
2564 'user_email_authenticated' => $dbw->timestampOrNull( $this->mEmailAuthenticated ),
2565 'user_real_name' => $this->mRealName,
2566 'user_token' => strval( $this->mToken ),
2567 'user_registration' => $dbw->timestamp(),
2568 'user_editcount' => 0,
2569 'user_touched' => $dbw->timestamp( $this->mTouched ),
2570 'user_is_temp' => $this->isTemp(),
2571 ] )
2572 ->caller( $fname )->execute();
2573 if ( !$dbw->affectedRows() ) {
2574 // Use locking reads to bypass any REPEATABLE-READ snapshot.
2575 $this->mId = $dbw->newSelectQueryBuilder()
2576 ->select( 'user_id' )
2577 ->lockInShareMode()
2578 ->from( 'user' )
2579 ->where( [ 'user_name' => $this->mName ] )
2580 ->caller( $fname )->fetchField();
2581 $loaded = false;
2582 if ( $this->mId && $this->loadFromDatabase( IDBAccessObject::READ_LOCKING ) ) {
2583 $loaded = true;
2584 }
2585 if ( !$loaded ) {
2586 throw new RuntimeException( $fname . ": hit a key conflict attempting " .
2587 "to insert user '{$this->mName}' row, but it was not present in select!" );
2588 }
2589 return Status::newFatal( 'userexists' );
2590 }
2591 $this->mId = $dbw->insertId();
2592 $this->queryFlagsUsed = IDBAccessObject::READ_LATEST;
2593
2594 // Don't pass $this, since calling ::getId, ::getName might force ::load
2595 // and this user might not be ready for that yet.
2596 $this->mActorId = MediaWikiServices::getInstance()
2597 ->getActorNormalization()
2598 ->acquireActorId( new UserIdentityValue( $this->mId, $this->mName ), $dbw );
2599 return Status::newGood();
2600 } );
2601 if ( !$status->isGood() ) {
2602 return $status;
2603 }
2604
2605 // Clear instance cache other than user table data and actor, which is already accurate
2606 $this->clearInstanceCache();
2607
2608 if ( $this->isNamed() ) {
2609 MediaWikiServices::getInstance()->getUserOptionsManager()->saveOptions( $this );
2610 }
2611 return Status::newGood();
2612 }
2613
2620 public function scheduleSpreadBlock() {
2621 DeferredUpdates::addCallableUpdate( function () {
2622 // Permit master queries in a GET request
2623 $scope = Profiler::instance()->getTransactionProfiler()->silenceForScope();
2624 $this->spreadAnyEditBlock();
2625 ScopedCallback::consume( $scope );
2626 } );
2627 }
2628
2635 public function spreadAnyEditBlock() {
2636 if ( !$this->isRegistered() ) {
2637 return false;
2638 }
2639
2640 $blockWasSpread = false;
2641 $this->getHookRunner()->onSpreadAnyEditBlock( $this, $blockWasSpread );
2642
2643 $block = $this->getBlock();
2644 if ( $block ) {
2645 $blockWasSpread = $blockWasSpread || $this->spreadBlock( $block );
2646 }
2647
2648 return $blockWasSpread;
2649 }
2650
2657 protected function spreadBlock( Block $block ): bool {
2658 wfDebug( __METHOD__ . "()" );
2659 $this->load();
2660 if ( $this->mId == 0 ) {
2661 return false;
2662 }
2663
2664 $blockStore = MediaWikiServices::getInstance()->getDatabaseBlockStore();
2665 foreach ( $block->toArray() as $singleBlock ) {
2666 if ( $singleBlock instanceof DatabaseBlock && $singleBlock->isAutoblocking() ) {
2667 return (bool)$blockStore->doAutoblock( $singleBlock, $this->getRequest()->getIP() );
2668 }
2669 }
2670 return false;
2671 }
2672
2680 public function isBlockedFromEmailuser() {
2681 wfDeprecated( __METHOD__, '1.41' );
2682 $block = $this->getBlock();
2683 return $block && $block->appliesToRight( 'sendemail' );
2684 }
2685
2692 public function isBlockedFromUpload() {
2693 $block = $this->getBlock();
2694 return $block && $block->appliesToRight( 'upload' );
2695 }
2696
2701 public function isAllowedToCreateAccount() {
2702 return $this->getThisAsAuthority()->isDefinitelyAllowed( 'createaccount' );
2703 }
2704
2710 public function getUserPage() {
2711 return Title::makeTitle( NS_USER, $this->getName() );
2712 }
2713
2719 public function getTalkPage() {
2720 $title = $this->getUserPage();
2721 return $title->getTalkPage();
2722 }
2723
2731 public function isNewbie() {
2732 // IP users and temp account users are excluded from the autoconfirmed group.
2733 return !$this->isAllowed( 'autoconfirmed' );
2734 }
2735
2748 public function getEditTokenObject( $salt = '', $request = null ) {
2749 if ( $this->isAnon() ) {
2750 return new LoggedOutEditToken();
2751 }
2752
2753 if ( !$request ) {
2754 $request = $this->getRequest();
2755 }
2756 return $request->getSession()->getToken( $salt );
2757 }
2758
2773 public function getEditToken( $salt = '', $request = null ) {
2774 return $this->getEditTokenObject( $salt, $request )->toString();
2775 }
2776
2790 public function matchEditToken( $val, $salt = '', $request = null, $maxage = null ) {
2791 return $this->getEditTokenObject( $salt, $request )->match( $val, $maxage );
2792 }
2793
2802 public function sendConfirmationMail( $type = 'created' ) {
2803 $emailer = MediaWikiServices::getInstance()->getConfirmEmailSender();
2804 $expiration = null; // gets passed-by-ref and defined in next line
2805 $token = $this->getConfirmationToken( $expiration );
2806 $confirmationUrl = $this->getConfirmationTokenUrl( $token );
2807 $invalidateUrl = $this->getInvalidationTokenUrl( $token );
2808 $this->saveSettings();
2809
2810 return Status::wrap( $emailer->sendConfirmationMail(
2811 RequestContext::getMain(),
2812 $type,
2813 new ConfirmEmailData(
2814 $this->getUser(),
2815 $confirmationUrl,
2816 $invalidateUrl,
2817 $expiration
2818 )
2819 ) );
2820 }
2821
2833 public function sendMail( $subject, $body, $from = null, $replyto = null ) {
2834 $passwordSender = MediaWikiServices::getInstance()->getMainConfig()
2835 ->get( MainConfigNames::PasswordSender );
2836
2837 if ( $from instanceof User ) {
2838 $sender = MailAddress::newFromUser( $from );
2839 } else {
2840 $sender = new MailAddress( $passwordSender,
2841 wfMessage( 'emailsender' )->inContentLanguage()->text() );
2842 }
2843 $to = MailAddress::newFromUser( $this );
2844
2845 if ( is_array( $body ) ) {
2846 $bodyText = $body['text'] ?? '';
2847 $bodyHtml = $body['html'] ?? null;
2848 } else {
2849 $bodyText = $body;
2850 $bodyHtml = null;
2851 }
2852
2853 return Status::wrap( MediaWikiServices::getInstance()->getEmailer()
2854 ->send(
2855 [ $to ],
2856 $sender,
2857 $subject,
2858 $bodyText,
2859 $bodyHtml,
2860 [ 'replyTo' => $replyto ]
2861 ) );
2862 }
2863
2879 public function getConfirmationToken(
2880 ?string &$expiration,
2881 ?int $tokenLifeTimeSeconds = null
2882 ): string {
2883 $tokenLifeTimeSeconds ??= MediaWikiServices::getInstance()
2884 ->getMainConfig()->get( MainConfigNames::UserEmailConfirmationTokenExpiry );
2885 $now = ConvertibleTimestamp::time();
2886
2887 $expires = $now + $tokenLifeTimeSeconds;
2888 $expiration = wfTimestamp( TS::MW, $expires );
2889 $this->load();
2890 $token = MWCryptRand::generateHex( 32 );
2891 $hash = md5( $token );
2892 $this->mEmailToken = $hash;
2893 $this->mEmailTokenExpires = $expiration;
2894 return $token;
2895 }
2896
2903 protected function confirmationToken( &$expiration ) {
2904 return $this->getConfirmationToken( $expiration );
2905 }
2906
2913 public static function isWellFormedConfirmationToken( string $token ): bool {
2914 return preg_match( '/^[a-f0-9]{32}$/', $token );
2915 }
2916
2924 public function getConfirmationTokenUrl( string $token ): string {
2925 return $this->getTokenUrl( 'ConfirmEmail', $token );
2926 }
2927
2935 public function getInvalidationTokenUrl( string $token ): string {
2936 return $this->getTokenUrl( 'InvalidateEmail', $token );
2937 }
2938
2946 protected function invalidationTokenUrl( $token ) {
2947 return $this->getTokenUrl( 'InvalidateEmail', $token );
2948 }
2949
2965 public function getTokenUrl( string $page, string $token ): string {
2966 // Hack to bypass localization of 'Special:'
2967 $title = Title::makeTitle( NS_MAIN, "Special:$page/$token" );
2968 return $title->getCanonicalURL();
2969 }
2970
2978 public function confirmEmail() {
2979 // Check if it's already confirmed, so we don't touch the database
2980 // and fire the ConfirmEmailComplete hook on redundant confirmations.
2981 if ( !$this->isEmailConfirmed() ) {
2982 $this->setEmailAuthenticationTimestamp( wfTimestampNow() );
2983 $this->getHookRunner()->onConfirmEmailComplete( $this );
2984 $logContext = [ 'event' => 'email_confirmed' ];
2985 if ( $this->mEmailTokenExpires !== null ) {
2986 $tokenLifetime = MediaWikiServices::getInstance()->getMainConfig()
2987 ->get( MainConfigNames::UserEmailConfirmationTokenExpiry );
2988 $tokenExpiry = wfTimestamp( TS_UNIX, $this->mEmailTokenExpires );
2989 if ( is_numeric( $tokenLifetime ) && $tokenExpiry !== false ) {
2990 $emailSentAt = (int)$tokenExpiry - (int)$tokenLifetime;
2991 $delaySec = max( 0, (int)ConvertibleTimestamp::time() - $emailSentAt );
2992 $logContext['confirmation_delay_seconds'] = $delaySec;
2993 }
2994 }
2995 LoggerFactory::getInstance( 'confirmemail' )->info( 'Email address confirmed', $logContext );
2996 }
2997 return true;
2998 }
2999
3007 public function invalidateEmail() {
3008 $this->load();
3009 $this->mEmailToken = null;
3010 $this->mEmailTokenExpires = null;
3011 $this->setEmailAuthenticationTimestamp( null );
3012 $this->mEmail = '';
3013 $this->getHookRunner()->onInvalidateEmailComplete( $this );
3014 return true;
3015 }
3016
3021 public function setEmailAuthenticationTimestamp( $timestamp ) {
3022 $this->load();
3023 $this->mEmailAuthenticated = $timestamp;
3024 $this->getHookRunner()->onUserSetEmailAuthenticationTimestamp(
3025 $this, $this->mEmailAuthenticated );
3026 }
3027
3035 public function canSendEmail() {
3036 wfDeprecated( __METHOD__, '1.41' );
3037 $permError = MediaWikiServices::getInstance()->getEmailUserFactory()
3038 ->newEmailUser( $this->getThisAsAuthority() )
3039 ->canSend();
3040 return $permError->isGood();
3041 }
3042
3048 public function canReceiveEmail() {
3049 $userOptionsLookup = MediaWikiServices::getInstance()
3050 ->getUserOptionsLookup();
3051 return $this->isEmailConfirmed() && !$userOptionsLookup->getOption( $this, 'disablemail' );
3052 }
3053
3064 public function isEmailConfirmed(): bool {
3065 $emailAuthentication = MediaWikiServices::getInstance()->getMainConfig()
3066 ->get( MainConfigNames::EmailAuthentication );
3067 $this->load();
3068 $confirmed = true;
3069 if ( $this->getHookRunner()->onEmailConfirmed( $this, $confirmed ) ) {
3070 return !$this->isAnon() &&
3071 Sanitizer::validateEmail( $this->getEmail() ) &&
3072 ( !$emailAuthentication || $this->getEmailAuthenticationTimestamp() );
3073 }
3074
3075 return $confirmed;
3076 }
3077
3082 public function isEmailConfirmationPending() {
3083 $emailAuthentication = MediaWikiServices::getInstance()->getMainConfig()
3084 ->get( MainConfigNames::EmailAuthentication );
3085 return $emailAuthentication &&
3086 !$this->isEmailConfirmed() &&
3087 $this->mEmailToken &&
3088 $this->mEmailTokenExpires > wfTimestamp();
3089 }
3090
3099 public function getRegistration() {
3100 return MediaWikiServices::getInstance()
3101 ->getUserRegistrationLookup()
3102 ->getRegistration( $this );
3103 }
3104
3112 public static function getRightDescription( $right ) {
3113 $key = "right-$right";
3114 $msg = wfMessage( $key );
3115 return $msg->isDisabled() ? $right : $msg->text();
3116 }
3117
3125 public static function getRightDescriptionHtml( $right ) {
3126 return wfMessage( "right-$right" )->parse();
3127 }
3128
3142 public static function getQueryInfo() {
3143 return [
3144 'tables' => [ 'user', 'user_actor' => 'actor' ],
3145 'fields' => [
3146 'user_id',
3147 'user_name',
3148 'user_real_name',
3149 'user_email',
3150 'user_touched',
3151 'user_token',
3152 'user_email_authenticated',
3153 'user_email_token',
3154 'user_email_token_expires',
3155 'user_registration',
3156 'user_editcount',
3157 'user_actor.actor_id',
3158 ],
3159 'joins' => [
3160 'user_actor' => [ 'JOIN', 'user_actor.actor_user = user_id' ],
3161 ],
3162 ];
3163 }
3164
3174 public static function newQueryBuilder( IReadableDatabase $db ) {
3175 return $db->newSelectQueryBuilder()
3176 ->select( [
3177 'user_id',
3178 'user_name',
3179 'user_real_name',
3180 'user_email',
3181 'user_touched',
3182 'user_token',
3183 'user_email_authenticated',
3184 'user_email_token',
3185 'user_email_token_expires',
3186 'user_registration',
3187 'user_editcount',
3188 'user_actor.actor_id',
3189 ] )
3190 ->from( 'user' )
3191 ->join( 'actor', 'user_actor', 'user_actor.actor_user = user_id' );
3192 }
3193
3204 public static function newFatalPermissionDeniedStatus( $permission ) {
3205 return Status::wrap( MediaWikiServices::getInstance()->getPermissionManager()
3206 ->newFatalPermissionDeniedStatus(
3207 $permission,
3208 RequestContext::getMain()
3209 ) );
3210 }
3211
3227 public function getInstanceForUpdate() {
3228 wfDeprecated( __METHOD__, '1.46' );
3229 return $this->getInstanceFromPrimary( IDBAccessObject::READ_EXCLUSIVE );
3230 }
3231
3249 public function getInstanceFromPrimary( int $loadFlags = IDBAccessObject::READ_LATEST ): ?User {
3250 if ( $this->isAnon() ) {
3251 return null;
3252 } elseif ( ( $loadFlags & $this->queryFlagsUsed ) === $loadFlags ) {
3253 return $this;
3254 }
3255
3256 $user = self::newFromId( $this->getId() );
3257 if ( !$user->loadFromId( $loadFlags ) ) {
3258 return null;
3259 }
3260
3261 return $user;
3262 }
3263
3271 public function equals( ?UserIdentity $user ): bool {
3272 if ( !$user ) {
3273 return false;
3274 }
3275 // XXX it's not clear whether central ID providers are supposed to obey this
3276 return $this->getName() === $user->getName();
3277 }
3278
3284 public function getUser(): UserIdentity {
3285 return $this;
3286 }
3287
3295 public function probablyCan(
3296 string $action,
3297 PageIdentity $target,
3298 ?PermissionStatus $status = null
3299 ): bool {
3300 return $this->getThisAsAuthority()->probablyCan( $action, $target, $status );
3301 }
3302
3310 public function definitelyCan(
3311 string $action,
3312 PageIdentity $target,
3313 ?PermissionStatus $status = null
3314 ): bool {
3315 return $this->getThisAsAuthority()->definitelyCan( $action, $target, $status );
3316 }
3317
3326 public function isDefinitelyAllowed( string $action, ?PermissionStatus $status = null ): bool {
3327 return $this->getThisAsAuthority()->isDefinitelyAllowed( $action, $status );
3328 }
3329
3338 public function authorizeAction( string $action, ?PermissionStatus $status = null ): bool {
3339 return $this->getThisAsAuthority()->authorizeAction( $action, $status );
3340 }
3341
3349 public function authorizeRead(
3350 string $action,
3351 PageIdentity $target,
3352 ?PermissionStatus $status = null
3353 ): bool {
3354 return $this->getThisAsAuthority()->authorizeRead( $action, $target, $status );
3355 }
3356
3364 public function authorizeWrite(
3365 string $action, PageIdentity $target,
3366 ?PermissionStatus $status = null
3367 ): bool {
3368 return $this->getThisAsAuthority()->authorizeWrite( $action, $target, $status );
3369 }
3370
3375 private function getThisAsAuthority(): UserAuthority {
3376 if ( !$this->mThisAsAuthority ) {
3377 // TODO: For users that are not User::isGlobalSessionUser,
3378 // creating a UserAuthority here is incorrect, since it depends
3379 // on global WebRequest, but that is what we've used to do before Authority.
3380 // When PermissionManager is refactored into Authority, we need
3381 // to provide base implementation, based on just user groups/rights,
3382 // and use it here.
3383 $request = $this->getRequest();
3384 $uiContext = RequestContext::getMain();
3385
3386 $services = MediaWikiServices::getInstance();
3387 $this->mThisAsAuthority = new UserAuthority(
3388 $this,
3389 $request,
3390 $uiContext,
3391 $services->getPermissionManager(),
3392 $services->getRateLimiter(),
3393 $services->getFormatterFactory()->getBlockErrorFormatter( $uiContext )
3394 );
3395 }
3396
3397 return $this->mThisAsAuthority;
3398 }
3399
3403 private function isGlobalSessionUser(): bool {
3404 // The session user is set up towards the end of Setup.php. Until then,
3405 // assume it's a logged-out user.
3406 $sessionUser = RequestContext::getMain()->getUser();
3407 $globalUserName = $sessionUser->isSafeToLoad()
3408 ? $sessionUser->getName()
3409 : IPUtils::sanitizeIP( $sessionUser->getRequest()->getIP() );
3410
3411 return $this->getName() === $globalUserName;
3412 }
3413
3419 public function isTemp(): bool {
3420 if ( $this->isTemp === null ) {
3421 $this->isTemp = MediaWikiServices::getInstance()->getUserIdentityUtils()
3422 ->isTemp( $this );
3423 }
3424 return $this->isTemp;
3425 }
3426
3433 public function isNamed(): bool {
3434 return $this->isRegistered() && !$this->isTemp();
3435 }
3436}
3437
3439class_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.
global $wgFullyInitialised
Definition Setup.php:591
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:71
const MW_ENTRY_POINT
Definition api.php:21
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:34
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:26
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:2363
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:3338
isAllowedToCreateAccount()
Get whether the user is allowed to create an account.
Definition User.php:2701
string null $mDatePreference
Lazy-initialized variables, invalidated with clearInstanceCache.
Definition User.php:245
touch()
Update the "touched" timestamp for the user.
Definition User.php:1689
isAllowed(string $permission, ?PermissionStatus $status=null)
Checks whether this authority has the given permission in general.
Definition User.php:2150
static newFromConfirmationCode( $code, $flags=IDBAccessObject::READ_NORMAL)
Factory method to fetch whichever user has a given email confirmation code.
Definition User.php:737
& __get( $name)
Definition User.php:300
logout()
Log this user out.
Definition User.php:2287
getRegistration()
Get the timestamp of account creation.
Definition User.php:3099
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:3249
useRCPatrol()
Check whether to enable recent changes patrol features for this user.
Definition User.php:2158
isAllowedAny(... $permissions)
Checks whether this authority has any of the given permissions in general.Implementations must ensure...
Definition User.php:2141
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:2056
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:2748
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:2773
confirmationToken(&$expiration)
Deprecated alias for getConfirmationToken() for CentralAuth.
Definition User.php:2903
static findUsersByGroup( $groups, $limit=5000, $after=null)
Return the users who are members of the given group(s).
Definition User.php:921
setToken( $token=false)
Set the random token (used for persistent authentication) Called from loadDefaults() among other plac...
Definition User.php:1846
canReceiveEmail()
Is this user allowed to receive e-mails within limits of current site configuration?
Definition User.php:3048
getId( $wikiId=self::LOCAL)
Get the user's ID.
Definition User.php:1492
getCacheKey(WANObjectCache $cache)
Definition User.php:527
loadFromCache()
Load user data from shared cache, given mId has already been set.
Definition User.php:540
getDBTouched()
Get the user_touched timestamp field (time of last DB updates)
Definition User.php:1757
clearInstanceCache( $reloadFrom=false)
Clear various cached data stored in this object.
Definition User.php:1327
checkPasswordValidity( $password)
Check if this is a valid password for this user.
Definition User.php:974
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:3349
getExperienceLevel()
Compute experienced level based on edit count and registration date.
Definition User.php:2206
isNamed()
Is the user a normal non-temporary registered user?
Definition User.php:3433
setEmailWithConfirmation(string $str)
Set the user's e-mail address and send a confirmation mail if needed.
Definition User.php:1903
loadFromUserObject( $user)
Load the data for this user object from another user object.
Definition User.php:1258
getUserPage()
Get this user's personal page title.
Definition User.php:2710
isSafeToLoad()
Test if it's safe to load this User object.
Definition User.php:364
isEmailConfirmed()
Is this user's e-mail address valid-looking and confirmed within limits of the current site configura...
Definition User.php:3064
invalidationTokenUrl( $token)
Deprecated alias for getInvalidationTokenUrl() for CentralAuth.
Definition User.php:2946
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:1376
confirmEmail()
Mark the e-mail address confirmed.
Definition User.php:2978
getConfirmationToken(?string &$expiration, ?int $tokenLifeTimeSeconds=null)
Generate, store, and return a new e-mail confirmation code.
Definition User.php:2879
isNewbie()
Determine whether the user is a newbie.
Definition User.php:2731
resetTokenFromOption( $oname)
Reset a token stored in the preferences (like the watchlist one).
Definition User.php:2016
isBlockedFromEmailuser()
Get whether the user is blocked from using Special:Emailuser.
Definition User.php:2680
isLocked()
Check if user account is locked.
Definition User.php:1467
isBlockedFromUpload()
Get whether the user is blocked from using Special:Upload.
Definition User.php:2692
static newQueryBuilder(IReadableDatabase $db)
Get a SelectQueryBuilder with the tables, fields and join conditions needed to create a new User obje...
Definition User.php:3174
setCookies( $request=null, $secure=null, $rememberMe=false)
Persist this user's session (e.g.
Definition User.php:2250
int $mId
Cache variables.
Definition User.php:194
addToDatabase()
Add this existing user object to the database.
Definition User.php:2541
getBlock( $freshness=IDBAccessObject::READ_NORMAL, $disableIpBlockExemptChecking=false)
Get the block affecting the user, or null if the user is not blocked.
Definition User.php:1426
getTokenUrl(string $page, string $token)
Function to create a special page URL with a token path parameter.
Definition User.php:2965
setEmail(string $str)
Set the user's e-mail address.
Definition User.php:1886
static newFatalPermissionDeniedStatus( $permission)
Factory function for fatal permission-denied errors.
Definition User.php:3204
static purge( $dbDomain, $userId)
Definition User.php:516
string $mFrom
Initialization data source if mLoadedItems!==true.
Definition User.php:239
probablyCan(string $action, PageIdentity $target, ?PermissionStatus $status=null)
Definition User.php:3295
static newFromActorId( $id)
Static factory method for creation from a given actor ID.
Definition User.php:667
loadFromRow( $row, $data=null)
Initialize this object from a row from the user table.
Definition User.php:1148
checkAndSetTouched()
Bump user_touched if it didn't change since this object was loaded.
Definition User.php:1290
load( $flags=IDBAccessObject::READ_NORMAL)
Load the user table data for this object from the source given by mFrom.
Definition User.php:381
loadFromDatabase( $flags=IDBAccessObject::READ_LATEST)
Load user data from the database.
Definition User.php:1102
getEditCount()
Get the user's edit count.
Definition User.php:2077
doLogout()
Clear the user's session, and reset the instance cache.
Definition User.php:2297
getDatePreference()
Get the user's preferred date format.
Definition User.php:2034
clearSharedCache( $mode='refresh')
Clear user data from memcached.
Definition User.php:1646
static newFromId( $id)
Static factory method for creation from a given user ID.
Definition User.php:650
setActorId(int $actorId)
Sets the actor id.
Definition User.php:1608
setItemLoaded( $item)
Set that an item has been loaded.
Definition User.php:1066
static newSystemUser( $name, $options=[])
Static factory method for creation of a "system" user from username.
Definition User.php:822
loadFromId( $flags=IDBAccessObject::READ_NORMAL)
Load user table data, given mId has already been set.
Definition User.php:486
static newFromRow( $row, $data=null)
Create a new user object from a user row.
Definition User.php:772
isAnon()
Get whether the user is anonymous.
Definition User.php:2099
sendMail( $subject, $body, $from=null, $replyto=null)
Send an e-mail to this user's account.
Definition User.php:2833
changeAuthenticationData(array $data)
Changes credentials of the user.
Definition User.php:1775
static newFromAnyId( $userId, $userName, $actorId, $dbDomain=false)
Static factory method for creation from an ID, name, and/or actor ID.
Definition User.php:716
definitelyCan(string $action, PageIdentity $target, ?PermissionStatus $status=null)
Definition User.php:3310
string $mRealName
Definition User.php:204
isSystemUser()
Get whether the user is a system user.
Definition User.php:2130
getInvalidationTokenUrl(string $token)
Return a URL the user can use to invalidate their email address.
Definition User.php:2935
isItemLoaded( $item, $all='all')
Return whether an item has been loaded.
Definition User.php:1054
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:1516
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:2146
getInstanceForUpdate()
Get a new instance of this user that was loaded from the primary DB via a locking read.
Definition User.php:3227
getTokenFromOption( $oname)
Get a token stored in the preferences (like the watchlist one), resetting it if it's empty (and savin...
Definition User.php:1985
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:3326
static getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new user object.
Definition User.php:3142
equals(?UserIdentity $user)
Checks if two user objects point to the same user.
Definition User.php:3271
isTemp()
Is the user an autocreated temporary user?
Definition User.php:3419
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:3082
getRealName()
Get the user's real name.
Definition User.php:1958
string $mTouched
TS::MW timestamp from the DB.
Definition User.php:209
getTitleKey()
Get the user's name escaped by underscores.
Definition User.php:1617
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:1571
string null $mQuickTouched
TS::MW timestamp from cache.
Definition User.php:211
validateCache( $timestamp)
Validate the cache for this account.
Definition User.php:1723
getEmailAuthenticationTimestamp()
Get the timestamp of the user's e-mail authentication.
Definition User.php:1875
authorizeWrite(string $action, PageIdentity $target, ?PermissionStatus $status=null)
Definition User.php:3364
__set( $name, $value)
Definition User.php:321
useFilePatrol()
Check whether to enable new files patrol features for this user.
Definition User.php:2183
static newFromSession(?WebRequest $request=null)
Create a new user object using data from session.
Definition User.php:750
canSendEmail()
Is this user allowed to send e-mails within limits of current site configuration?
Definition User.php:3035
static isWellFormedConfirmationToken(string $token)
Check if the given email confirmation token is well-formed (to detect mangling by email clients).
Definition User.php:2913
static createNew( $name, $params=[])
Add a user to the database, return the user object.
Definition User.php:2446
getRequest()
Get the WebRequest object to use with this object.
Definition User.php:2197
saveSettings()
Save this user's settings into the database.
Definition User.php:2335
loadDefaults( $name=false, $actorId=null)
Set cached properties to default.
Definition User.php:1018
useNPPatrol()
Check whether to enable new pages patrol features for this user.
Definition User.php:2168
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:1397
matchEditToken( $val, $salt='', $request=null, $maxage=null)
Check given value against the token value stored in the session.
Definition User.php:2790
invalidateEmail()
Invalidate the user's e-mail confirmation, and unauthenticate the e-mail address if it was already co...
Definition User.php:3007
isRegistered()
Get whether the user is registered.
Definition User.php:2091
getTalkPage()
Get this user's talk page title.
Definition User.php:2719
static newFromIdentity(UserIdentity $identity)
Returns a User object corresponding to the given UserIdentity.
Definition User.php:686
makeUpdateConditions(IReadableDatabase $db)
Build additional update conditions to protect against race conditions using a compare-and-set (CAS) m...
Definition User.php:1272
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:1802
setEmailAuthenticationTimestamp( $timestamp)
Set the e-mail authentication timestamp.
Definition User.php:3021
isHidden()
Check if user account is hidden.
Definition User.php:1482
static getRightDescription( $right)
Get the description of a given right as wikitext.
Definition User.php:3112
setName( $str)
Set the user name.
Definition User.php:1553
static getRightDescriptionHtml( $right)
Get the description of a given right as rendered HTML.
Definition User.php:3125
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:1704
isValidPassword( $password)
Is the input a valid password for this user?
Definition User.php:948
getEmail()
Get the user's e-mail address.
Definition User.php:1862
getName()
Get the user name, or the IP of an anonymous user.
Definition User.php:1525
setRealName(string $str)
Set the user's real name.
Definition User.php:1970
spreadAnyEditBlock()
If this user is logged-in and blocked, block any IP address they've successfully logged in from.
Definition User.php:2635
getTouched()
Get the user touched timestamp.
Definition User.php:1735
static newFromName( $name, $validate='valid')
Definition User.php:624
invalidateCache()
Immediately touch the user data cache for this account.
Definition User.php:1672
scheduleSpreadBlock()
Schedule a deferred update which will block the IP address of the current user, if they are blocked w...
Definition User.php:2620
spreadBlock(Block $block)
If this (non-anonymous) user is blocked, block the IP address they've successfully logged in from.
Definition User.php:2657
getConfirmationTokenUrl(string $token)
Return a URL the user can use to confirm their email address.
Definition User.php:2924
idForName( $flags=IDBAccessObject::READ_NORMAL)
If only this user's username is known, and it exists, return the user ID.
Definition User.php:2413
sendConfirmationMail( $type='created')
Generate a new e-mail confirmation token and send a confirmation/invalidation mail to the user's give...
Definition User.php:2802
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.
Utility functions for generating hashes.
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'=>[], 'DefaultLockManager'=> null, '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, '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, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EmailConfirmationBanner'=> false, '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', 'CodeHighlighter',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'CodeHighlighter',],], '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,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> 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',],],], 'EnableSectionShare'=> false, '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, ], 'NamespacesWithoutAutoSummaries' => [ ], '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, '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, ], 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider', 'services' => [ 'ConnectionProvider', 'UserFactory', ], '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, 'autocreateaccount' => 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, 'createwithcontentmodel' => true, 'logout' => 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, 'createpreviouslyrenamedaccount' => 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' => [ ], 'RestrictUserPageEditing' => false, '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, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => 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, 'createwithcontentmodel' => 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, 'createwithcontentmodel' => 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, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], 'managesessions' => [ 'logout' => 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', 'managesessions' => '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, 'ReauthenticateForActions' => [ 'edituserjs' => 'edituserjscss', 'editusercss' => 'edituserjscss', 'editsitejs' => 'editsitejscss', 'editsitecss' => 'editsitejscss', ], 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPUseReportURIDirective' => 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, 'ApiClientErrorSampleRate' => 1.0, '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: 'https: 'git@github\\.com:(.*?)(\\.git)?' => 'https: ], '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, 'mw-edited-other-users-js' => true, 'mw-edited-other-users-css' => true, ], 'RestrictedTagViewRights' => [ ], '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, 'EnableWatchstarPopover' => 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\\RecentChanges\\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', 'Promise-Non-Write-API-Action', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'RestModuleOverrides' => [ ], 'RestExternalModules' => [ ], '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, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, 'ReturnExperimentalPFragmentTypes' => [ ], ], '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', 'DefaultLockManager' => [ 'string', 'null', ], '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', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EmailConfirmationBanner' => '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', 'NamespacesWithoutAutoSummaries' => 'array', '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', 'RestrictUserPageEditing' => 'boolean', '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', 'ReauthenticateForActions' => 'object', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPUseReportURIDirective' => [ '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', 'RestrictedTagViewRights' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchstarPopover' => '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', 'RestModuleOverrides' => 'object', 'RestExternalModules' => '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', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', 'ReturnExperimentalPFragmentTypes' => 'array', ], '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', 'RestModuleOverrides' => 'array_replace_recursive', 'RestExternalModules' => 'array_replace_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', ], ], 'UseCopyrightUpload' => [ 'deprecated' => 'since 1.47 This feature is being removed.', ], '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', ], ], ], ], 'RestModuleOverrides' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'mode' => [ 'type' => 'string', ], ], 'required' => [ 'mode', ], ], ], 'RestExternalModules' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'info' => [ 'type' => 'object', 'properties' => [ 'version' => [ 'type' => 'string', ], 'title' => [ 'type' => 'string', ], 'x-i18n-title' => [ 'type' => 'string', ], 'description' => [ 'type' => 'string', ], 'x-i18n-description' => [ 'type' => 'string', ], ], 'required' => [ 'version', ], ], 'base' => [ 'type' => 'string', 'format' => 'uri', ], 'spec' => [ 'type' => 'string', 'format' => 'uri', ], ], 'required' => [ 'info', 'base', 'spec', ], ], ], '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