MediaWiki master
DatabaseBlockStore.php
Go to the documentation of this file.
1<?php
9namespace MediaWiki\Block;
10
11use InvalidArgumentException;
24use Psr\Log\LoggerInterface;
25use RuntimeException;
26use stdClass;
27use Wikimedia\IPUtils;
39use Wikimedia\Timestamp\TimestampFormat as TS;
40use function array_key_exists;
41
49 public const AUTO_ALL = 'all';
51 public const AUTO_SPECIFIED = 'specified';
53 public const AUTO_NONE = 'none';
54
58 public const CONSTRUCTOR_OPTIONS = [
64 ];
65
66 private string|false $wikiId;
67
68 private ServiceOptions $options;
69 private LoggerInterface $logger;
70 private ActorStoreFactory $actorStoreFactory;
71 private BlockRestrictionStore $blockRestrictionStore;
72 private CommentStore $commentStore;
73 private HookRunner $hookRunner;
74 private IConnectionProvider $dbProvider;
75 private ReadOnlyMode $readOnlyMode;
76 private UserFactory $userFactory;
77 private TempUserConfig $tempUserConfig;
78 private BlockTargetFactory $blockTargetFactory;
79 private AutoblockExemptionList $autoblockExemptionList;
80 private SessionManagerInterface $sessionManager;
81 private ILockManager $lockManager;
82
83 public function __construct(
84 ServiceOptions $options,
85 LoggerInterface $logger,
86 ActorStoreFactory $actorStoreFactory,
87 BlockRestrictionStore $blockRestrictionStore,
88 CommentStore $commentStore,
89 HookContainer $hookContainer,
90 IConnectionProvider $dbProvider,
91 ReadOnlyMode $readOnlyMode,
92 UserFactory $userFactory,
93 TempUserConfig $tempUserConfig,
94 BlockTargetFactory $blockTargetFactory,
95 AutoblockExemptionList $autoblockExemptionList,
96 SessionManagerInterface $sessionManager,
97 ILockManager $lockManager,
98 string|false $wikiId = DatabaseBlock::LOCAL
99 ) {
100 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
101
102 $this->wikiId = $wikiId;
103
104 $this->options = $options;
105 $this->logger = $logger;
106 $this->actorStoreFactory = $actorStoreFactory;
107 $this->blockRestrictionStore = $blockRestrictionStore;
108 $this->commentStore = $commentStore;
109 $this->hookRunner = new HookRunner( $hookContainer );
110 $this->dbProvider = $dbProvider;
111 $this->readOnlyMode = $readOnlyMode;
112 $this->userFactory = $userFactory;
113 $this->tempUserConfig = $tempUserConfig;
114 $this->blockTargetFactory = $blockTargetFactory;
115 $this->autoblockExemptionList = $autoblockExemptionList;
116 $this->sessionManager = $sessionManager;
117 $this->lockManager = $lockManager;
118 }
119
120 /***************************************************************************/
121 // region Database read methods
133 public function newFromID( $id, $fromPrimary = false, $includeExpired = false ) {
134 $blocks = $this->newListFromConds( [ 'bl_id' => $id ], $fromPrimary, $includeExpired );
135 return $blocks ? $blocks[0] : null;
136 }
137
154 public function getQueryInfo() {
155 $commentQuery = $this->commentStore->getJoin( 'bl_reason' );
156 return [
157 'tables' => [
158 'block',
159 'block_target',
160 'block_by_actor' => 'actor',
161 ] + $commentQuery['tables'],
162 'fields' => [
163 'bl_id',
164 'bt_address',
165 'bt_user',
166 'bt_user_text',
167 'bl_timestamp',
168 'bt_auto',
169 'bl_anon_only',
170 'bl_create_account',
171 'bl_enable_autoblock',
172 'bl_expiry',
173 'bl_deleted',
174 'bl_block_email',
175 'bl_allow_usertalk',
176 'bl_parent_block_id',
177 'bl_sitewide',
178 'bl_by_actor',
179 'bl_by' => 'block_by_actor.actor_user',
180 'bl_by_text' => 'block_by_actor.actor_name',
181 ] + $commentQuery['fields'],
182 'joins' => [
183 'block_target' => [ 'JOIN', 'bt_id=bl_target' ],
184 'block_by_actor' => [ 'JOIN', 'actor_id=bl_by_actor' ],
185 ] + $commentQuery['joins'],
186 ];
187 }
188
201 private function newLoad(
202 $specificTarget,
203 $fromPrimary,
204 $vagueTarget = null,
205 $auto = self::AUTO_ALL
206 ) {
207 if ( $fromPrimary ) {
208 $db = $this->getPrimaryDB();
209 } else {
210 $db = $this->getReplicaDB();
211 }
212
213 $userIds = [];
214 $userNames = [];
215 $addresses = [];
216 $ranges = [];
217 if ( $specificTarget instanceof UserBlockTarget ) {
218 $userId = $specificTarget->getUserIdentity()->getId( $this->wikiId );
219 if ( $userId ) {
220 $userIds[] = $userId;
221 } else {
222 // A nonexistent user can have no blocks.
223 // This case is hit in testing, possibly production too.
224 // Ignoring the user is optimal for production performance.
225 }
226 } elseif ( $specificTarget instanceof AnonIpBlockTarget
227 || $specificTarget instanceof RangeBlockTarget
228 ) {
229 $addresses[] = (string)$specificTarget;
230 }
231
232 // Be aware that the != '' check is explicit, since empty values will be
233 // passed by some callers (T31116)
234 if ( $vagueTarget !== null ) {
235 if ( $vagueTarget instanceof UserBlockTarget ) {
236 // Slightly weird, but who are we to argue?
237 $vagueUser = $vagueTarget->getUserIdentity();
238 $userId = $vagueUser->getId( $this->wikiId );
239 if ( $userId ) {
240 $userIds[] = $userId;
241 } else {
242 $userNames[] = $vagueUser->getName();
243 }
244 } elseif ( $vagueTarget instanceof BlockTargetWithIp ) {
245 $ranges[] = $vagueTarget->toHexRange();
246 } else {
247 $this->logger->debug( "Ignoring invalid vague target" );
248 }
249 }
250
251 $orConds = [];
252 if ( $userIds ) {
253 $orConds[] = $db->expr( 'bt_user', '=', array_values( array_unique( $userIds ) ) );
254 }
255 if ( $userNames ) {
256 // Add bt_ip_hex to the condition since it is in the index
257 $orConds[] = $db->expr( 'bt_ip_hex', '=', null )
258 ->and( 'bt_user_text', '=', array_values( array_unique( $userNames ) ) );
259 }
260 if ( $addresses ) {
261 $orConds[] = $db->expr( 'bt_address', '=', array_values( array_unique( $addresses ) ) );
262 }
263 foreach ( $this->getConditionForRanges( $ranges ) as $cond ) {
264 $orConds[] = new RawSQLExpression( $cond );
265 }
266 if ( !$orConds ) {
267 return [];
268 }
269
270 // Exclude autoblocks unless AUTO_ALL was requested.
271 $autoConds = $auto === self::AUTO_ALL ? [] : [ 'bt_auto' => 0 ];
272
273 $blockQuery = $this->getQueryInfo();
274 $res = $db->newSelectQueryBuilder()
275 ->queryInfo( $blockQuery )
276 ->where( $db->orExpr( $orConds ) )
277 ->andWhere( $autoConds )
278 ->caller( __METHOD__ )
279 ->fetchResultSet();
280
281 $blocks = [];
282 $blockIds = [];
283 $autoBlocks = [];
284 foreach ( $res as $row ) {
285 $block = $this->newFromRow( $db, $row );
286
287 // Don't use expired blocks
288 if ( $block->isExpired() ) {
289 continue;
290 }
291
292 // Don't use anon only blocks on users
293 if (
294 $specificTarget instanceof UserBlockTarget &&
295 !$block->isHardblock() &&
296 !$this->tempUserConfig->isTempName( $specificTarget->toString() )
297 ) {
298 continue;
299 }
300
301 // Check for duplicate autoblocks
302 if ( $block->getType() === Block::TYPE_AUTO ) {
303 $autoBlocks[] = $block;
304 } else {
305 $blocks[] = $block;
306 $blockIds[] = $block->getId( $this->wikiId );
307 }
308 }
309
310 // Only add autoblocks that aren't duplicates
311 foreach ( $autoBlocks as $block ) {
312 if ( !in_array( $block->getParentBlockId(), $blockIds ) ) {
313 $blocks[] = $block;
314 }
315 }
316
317 return $blocks;
318 }
319
328 private function chooseMostSpecificBlock( array $blocks ) {
329 if ( count( $blocks ) === 1 ) {
330 return $blocks[0];
331 }
332
333 // This result could contain a block on the user, a block on the IP, and a russian-doll
334 // set of range blocks. We want to choose the most specific one, so keep a leader board.
335 $bestBlock = null;
336
337 // Lower will be better
338 $bestBlockScore = 100;
339 foreach ( $blocks as $block ) {
340 $score = $block->getTarget()->getSpecificity();
341 if ( $score < $bestBlockScore ) {
342 $bestBlockScore = $score;
343 $bestBlock = $block;
344 }
345 }
346
347 return $bestBlock;
348 }
349
361 public function getConditionForRanges( array $ranges ): array {
362 $dbr = $this->getReplicaDB();
363
364 $conds = [];
365 $individualIPs = [];
366 foreach ( $ranges as [ $start, $end ] ) {
367 // Per T16634, we want to include relevant active range blocks; for
368 // range blocks, we want to include larger ranges which enclose the given
369 // range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
370 // so we can improve performance by filtering on a LIKE clause
371 $chunk = $this->getIpFragment( $start );
372 $end ??= $start;
373
374 $expr = $dbr->expr(
375 'bt_range_start',
376 IExpression::LIKE,
377 new LikeValue( $chunk, $dbr->anyString() )
378 )
379 ->and( 'bt_range_start', '<=', $start )
380 ->and( 'bt_range_end', '>=', $end );
381 if ( $start === $end ) {
382 $individualIPs[] = $start;
383 }
384 $conds[] = $expr->toSql( $dbr );
385 }
386 if ( $individualIPs ) {
387 // Also select single IP blocks for these targets
388 $conds[] = $dbr->expr( 'bt_ip_hex', '=', $individualIPs )
389 ->and( 'bt_range_start', '=', null )
390 ->toSql( $dbr );
391 }
392 return $conds;
393 }
394
405 public function getRangeCond( $start, $end ) {
406 $dbr = $this->getReplicaDB();
407 $conds = $this->getConditionForRanges( [ [ $start, $end ] ] );
408 return $dbr->makeList( $conds, IDatabase::LIST_OR );
409 }
410
418 private function getIpFragment( $hex ) {
419 $blockCIDRLimit = $this->options->get( MainConfigNames::BlockCIDRLimit );
420 if ( str_starts_with( $hex, 'v6-' ) ) {
421 return 'v6-' . substr( substr( $hex, 3 ), 0, (int)floor( $blockCIDRLimit['IPv6'] / 4 ) );
422 } else {
423 return substr( $hex, 0, (int)floor( $blockCIDRLimit['IPv4'] / 4 ) );
424 }
425 }
426
435 public function newFromRow( IReadableDatabase $db, $row ) {
436 return new DatabaseBlock( [
437 'target' => $this->blockTargetFactory->newFromRowRaw( $row ),
438 'wiki' => $this->wikiId,
439 'timestamp' => $row->bl_timestamp,
440 'auto' => (bool)$row->bt_auto,
441 'hideName' => (int)$row->bl_deleted === 1,
442 'hideBlock' => (bool)$row->bl_deleted,
443 'id' => (int)$row->bl_id,
444 // Blocks with no parent ID should have bl_parent_block_id as null,
445 // don't save that as 0 though, see T282890
446 'parentBlockId' => $row->bl_parent_block_id
447 ? (int)$row->bl_parent_block_id : null,
448 'by' => $this->actorStoreFactory
449 ->getActorStore( $this->wikiId )
450 ->newActorFromRowFields( $row->bl_by, $row->bl_by_text, $row->bl_by_actor ),
451 'decodedExpiry' => $db->decodeExpiry( $row->bl_expiry ),
452 'reason' => $this->commentStore->getComment( 'bl_reason', $row ),
453 'anonOnly' => $row->bl_anon_only,
454 'enableAutoblock' => (bool)$row->bl_enable_autoblock,
455 'sitewide' => (bool)$row->bl_sitewide,
456 'createAccount' => (bool)$row->bl_create_account,
457 'blockEmail' => (bool)$row->bl_block_email,
458 'allowUsertalk' => (bool)$row->bl_allow_usertalk
459 ] );
460 }
461
491 public function newFromTarget(
492 $specificTarget,
493 $vagueTarget = null,
494 $fromPrimary = false,
495 $auto = self::AUTO_ALL
496 ) {
497 $blocks = $this->newListFromTarget( $specificTarget, $vagueTarget, $fromPrimary, $auto );
498 return $this->chooseMostSpecificBlock( $blocks );
499 }
500
514 public function newListFromTarget(
515 $specificTarget,
516 $vagueTarget = null,
517 $fromPrimary = false,
518 $auto = self::AUTO_ALL
519 ) {
520 if ( !( $specificTarget instanceof BlockTarget ) ) {
521 $specificTarget = $this->blockTargetFactory->newFromLegacyUnion( $specificTarget );
522 }
523 if ( $vagueTarget !== null && !( $vagueTarget instanceof BlockTarget ) ) {
524 $vagueTarget = $this->blockTargetFactory->newFromLegacyUnion( $vagueTarget );
525 }
526 if ( $specificTarget instanceof AutoBlockTarget ) {
527 if ( $auto === self::AUTO_NONE ) {
528 return [];
529 }
530 $block = $this->newFromID( $specificTarget->getId() );
531 return $block ? [ $block ] : [];
532 } elseif ( $specificTarget === null && $vagueTarget === null ) {
533 // We're not going to find anything useful here
534 return [];
535 } else {
536 return $this->newLoad( $specificTarget, $fromPrimary, $vagueTarget, $auto );
537 }
538 }
539
550 public function newListFromIPs( array $addresses, $applySoftBlocks, $fromPrimary = false ) {
551 $addresses = array_unique( $addresses );
552 if ( $addresses === [] ) {
553 return [];
554 }
555
556 $ranges = [];
557 foreach ( $addresses as $ipaddr ) {
558 $ranges[] = [ IPUtils::toHex( $ipaddr ), null ];
559 }
560 $rangeConds = $this->getConditionForRanges( $ranges );
561
562 if ( $fromPrimary ) {
563 $db = $this->getPrimaryDB();
564 } else {
565 $db = $this->getReplicaDB();
566 }
567 $conds = $db->makeList( $rangeConds, LIST_OR );
568 if ( !$applySoftBlocks ) {
569 $conds = [ $conds, 'bl_anon_only' => 0 ];
570 }
571 $blockQuery = $this->getQueryInfo();
572 $rows = $db->newSelectQueryBuilder()
573 ->queryInfo( $blockQuery )
574 ->fields( [ 'bt_range_start', 'bt_range_end' ] )
575 ->where( $conds )
576 ->caller( __METHOD__ )
577 ->fetchResultSet();
578
579 $blocks = [];
580 foreach ( $rows as $row ) {
581 $block = $this->newFromRow( $db, $row );
582 if ( !$block->isExpired() ) {
583 $blocks[] = $block;
584 }
585 }
586
587 return $blocks;
588 }
589
600 public function newListFromConds( $conds, $fromPrimary = false, $includeExpired = false ) {
601 $db = $fromPrimary ? $this->getPrimaryDB() : $this->getReplicaDB();
602 $conds = self::mapActorAlias( $conds );
603 if ( !$includeExpired ) {
604 $conds[] = $db->expr( 'bl_expiry', '>=', $db->timestamp() );
605 }
606 $res = $db->newSelectQueryBuilder()
607 ->queryInfo( $this->getQueryInfo() )
608 ->conds( $conds )
609 ->caller( __METHOD__ )
610 ->fetchResultSet();
611 $blocks = [];
612 foreach ( $res as $row ) {
613 $blocks[] = $this->newFromRow( $db, $row );
614 }
615 return $blocks;
616 }
617
618 // endregion -- end of database read methods
619
620 /***************************************************************************/
621 // region Database write methods
637 public function newUnsaved( array $options ): DatabaseBlock {
638 if ( isset( $options['targetUser'] ) ) {
639 $options['target'] = $this->blockTargetFactory
640 ->newFromUser( $options['targetUser'] );
641 unset( $options['targetUser'] );
642 }
643 if ( isset( $options['address'] ) ) {
644 $target = $this->blockTargetFactory
645 ->newFromString( $options['address'] );
646 if ( !$target ) {
647 throw new InvalidArgumentException( 'Invalid target address' );
648 }
649 $options['target'] = $target;
650 unset( $options['address'] );
651 }
652 return new DatabaseBlock( $options );
653 }
654
660 public function purgeExpiredBlocks() {
661 if ( $this->readOnlyMode->isReadOnly( $this->wikiId ) ) {
662 return;
663 }
664
665 $dbw = $this->getPrimaryDB();
666
667 DeferredUpdates::addUpdate( new AutoCommitUpdate(
668 $dbw,
669 __METHOD__,
670 function ( IDatabase $dbw, $fname ) {
671 $limit = $this->options->get( MainConfigNames::UpdateRowsPerQuery );
672 $res = $dbw->newSelectQueryBuilder()
673 ->select( [ 'bl_id', 'bl_target' ] )
674 ->from( 'block' )
675 ->where( $dbw->expr( 'bl_expiry', '<', $dbw->timestamp() ) )
676 // Set a limit to avoid causing replication lag (T301742)
677 ->limit( $limit )
678 ->caller( $fname )->fetchResultSet();
679 $this->deleteBlockRows( $res );
680 }
681 ) );
682 }
683
693 public function deleteBlocksMatchingConds( array $conds, $limit = null ) {
694 $dbw = $this->getPrimaryDB();
695 $conds = self::mapActorAlias( $conds );
696 $qb = $dbw->newSelectQueryBuilder()
697 ->select( [ 'bl_id', 'bl_target' ] )
698 ->from( 'block' )
699 // Typical input conds need block_target
700 ->join( 'block_target', null, 'bt_id=bl_target' )
701 ->where( $conds )
702 ->caller( __METHOD__ );
703 if ( self::hasActorAlias( $conds ) ) {
704 $qb->join( 'actor', 'ipblocks_actor', 'actor_id=bl_by_actor' );
705 }
706 if ( $limit !== null ) {
707 $qb->limit( $limit );
708 }
709 $res = $qb->fetchResultSet();
710 return $this->deleteBlockRows( $res );
711 }
712
719 private static function mapActorAlias( $conds ) {
720 return self::mapConds(
721 [
722 'bl_by' => 'ipblocks_actor.actor_user',
723 ],
724 $conds
725 );
726 }
727
732 private static function hasActorAlias( $conds ) {
733 return array_key_exists( 'ipblocks_actor.actor_user', $conds )
734 || array_key_exists( 'ipblocks_actor.actor_name', $conds );
735 }
736
744 private static function mapConds( $map, $conds ) {
745 $newConds = [];
746 foreach ( $conds as $field => $value ) {
747 if ( isset( $map[$field] ) ) {
748 $newConds[$map[$field]] = $value;
749 } else {
750 $newConds[$field] = $value;
751 }
752 }
753 return $newConds;
754 }
755
763 private function deleteBlockRows( $rows ) {
764 $ids = [];
765 $deltasByTarget = [];
766 foreach ( $rows as $row ) {
767 $ids[] = (int)$row->bl_id;
768 $target = (int)$row->bl_target;
769 if ( !isset( $deltasByTarget[$target] ) ) {
770 $deltasByTarget[$target] = 0;
771 }
772 $deltasByTarget[$target]++;
773 }
774 if ( !$ids ) {
775 return 0;
776 }
777 $dbw = $this->getPrimaryDB();
778 $dbw->startAtomic( __METHOD__ );
779
780 $maxTargetCount = max( $deltasByTarget );
781 for ( $delta = 1; $delta <= $maxTargetCount; $delta++ ) {
782 $targetsWithThisDelta = array_keys( $deltasByTarget, $delta, true );
783 if ( $targetsWithThisDelta ) {
784 $this->releaseTargets( $dbw, $targetsWithThisDelta, $delta );
785 }
786 }
787
788 $dbw->newDeleteQueryBuilder()
789 ->deleteFrom( 'block' )
790 ->where( [ 'bl_id' => $ids ] )
791 ->caller( __METHOD__ )->execute();
792 $numDeleted = $dbw->affectedRows();
793 $dbw->endAtomic( __METHOD__ );
794 $this->blockRestrictionStore->deleteByBlockId( $ids );
795 return $numDeleted;
796 }
797
806 private function releaseTargets( IDatabase $dbw, $targetIds, int $delta = 1 ) {
807 if ( !$targetIds ) {
808 return;
809 }
810 $dbw->newUpdateQueryBuilder()
811 ->update( 'block_target' )
812 ->set( [ 'bt_count' => new RawSQLValue( "bt_count-$delta" ) ] )
813 ->where( [ 'bt_id' => $targetIds ] )
814 ->caller( __METHOD__ )
815 ->execute();
816 $dbw->newDeleteQueryBuilder()
817 ->deleteFrom( 'block_target' )
818 ->where( [
819 'bt_count<1',
820 'bt_id' => $targetIds
821 ] )
822 ->caller( __METHOD__ )
823 ->execute();
824 }
825
826 private function getReplicaDB(): IReadableDatabase {
827 return $this->dbProvider->getReplicaDatabase( $this->wikiId );
828 }
829
830 private function getPrimaryDB(): IDatabase {
831 return $this->dbProvider->getPrimaryDatabase( $this->wikiId );
832 }
833
847 public function insertBlock(
848 DatabaseBlock $block,
849 $expectedTargetCount = 0
850 ) {
851 $block->assertWiki( $this->wikiId );
852
853 $blocker = $block->getBlocker();
854 if ( !$blocker || $blocker->getName() === '' ) {
855 throw new InvalidArgumentException( 'Cannot insert a block without a blocker set' );
856 }
857
858 if ( $expectedTargetCount instanceof IDatabase ) {
859 throw new InvalidArgumentException(
860 'Old method signature: Passing a custom database connection to '
861 . 'DatabaseBlockStore::insertBlock is no longer supported'
862 );
863 }
864
865 $this->logger->debug( 'Inserting block; timestamp ' . $block->getTimestamp() );
866
867 // Purge expired blocks. This now just queues a deferred update, so it
868 // is possible for expired blocks to conflict with inserted blocks below.
869 $this->purgeExpiredBlocks();
870
871 $dbw = $this->getPrimaryDB();
872 $dbw->startAtomic( __METHOD__ );
873 $finalTargetCount = $this->attemptInsert( $block, $dbw, $expectedTargetCount );
874 $purgeDone = false;
875
876 // Don't collide with expired blocks.
877 // Do this after trying to insert to avoid locking.
878 if ( !$finalTargetCount ) {
879 if ( $this->purgeExpiredConflicts( $block, $dbw ) ) {
880 $finalTargetCount = $this->attemptInsert( $block, $dbw, $expectedTargetCount );
881 $purgeDone = true;
882 }
883 }
884 $dbw->endAtomic( __METHOD__ );
885
886 if ( $finalTargetCount > 1 && !$purgeDone ) {
887 // Subtract expired blocks from the target count
888 $expiredBlockCount = $this->getExpiredConflictingBlockRows( $block, $dbw )->count();
889 if ( $expiredBlockCount >= $finalTargetCount ) {
890 $finalTargetCount = 1;
891 } else {
892 $finalTargetCount -= $expiredBlockCount;
893 }
894 }
895
896 if ( $finalTargetCount ) {
897 $autoBlockIds = $this->doRetroactiveAutoblock( $block );
898
899 if ( $this->options->get( MainConfigNames::BlockDisablesLogin ) ) {
900 $targetUserIdentity = $block->getTargetUserIdentity();
901 if ( $targetUserIdentity ) {
902 $targetUser = $this->userFactory->newFromUserIdentity( $targetUserIdentity );
903 $this->sessionManager->invalidateSessionsForUser( $targetUser );
904 }
905 }
906
907 return [
908 'id' => $block->getId( $this->wikiId ),
909 'autoIds' => $autoBlockIds,
910 'finalTargetCount' => $finalTargetCount
911 ];
912 }
913
914 return false;
915 }
916
928 public function insertBlockWithParams( array $params ): DatabaseBlock {
929 $block = $this->newUnsaved( $params );
930 $status = $this->insertBlock( $block, $params['expectedTargetCount'] ?? null );
931 if ( !$status ) {
932 throw new RuntimeException( 'Failed to insert block' );
933 }
934 return $block;
935 }
936
946 private function attemptInsert(
947 DatabaseBlock $block,
948 IDatabase $dbw,
949 $expectedTargetCount
950 ) {
951 [ $targetId, $finalCount ] = $this->acquireTarget( $block, $dbw, $expectedTargetCount );
952 if ( !$targetId ) {
953 return false;
954 }
955 $row = $this->getArrayForBlockUpdate( $block, $dbw );
956 $row['bl_target'] = $targetId;
957 $dbw->newInsertQueryBuilder()
958 ->insertInto( 'block' )
959 ->row( $row )
960 ->caller( __METHOD__ )->execute();
961 if ( !$dbw->affectedRows() ) {
962 return false;
963 }
964 $id = $dbw->insertId();
965
966 if ( !$id ) {
967 throw new RuntimeException( 'block insert ID is falsey' );
968 }
969 $block->setId( $id );
970 $restrictions = $block->getRawRestrictions();
971 if ( $restrictions ) {
972 $this->blockRestrictionStore->insert( $restrictions );
973 }
974
975 return $finalCount;
976 }
977
985 private function purgeExpiredConflicts(
986 DatabaseBlock $block,
987 IDatabase $dbw
988 ) {
989 return (bool)$this->deleteBlockRows(
990 $this->getExpiredConflictingBlockRows( $block, $dbw )
991 );
992 }
993
1002 private function getExpiredConflictingBlockRows(
1003 DatabaseBlock $block,
1004 IDatabase $dbw
1005 ) {
1006 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1007 $targetConds = $this->getTargetConds( $block->getTarget() );
1008 return $dbw->newSelectQueryBuilder()
1009 ->select( [ 'bl_id', 'bl_target' ] )
1010 ->from( 'block' )
1011 ->join( 'block_target', null, [ 'bt_id=bl_target' ] )
1012 ->where( $targetConds )
1013 ->andWhere( $dbw->expr( 'bl_expiry', '<', $dbw->timestamp() ) )
1014 ->caller( __METHOD__ )->fetchResultSet();
1015 }
1016
1023 private function getTargetConds( BlockTarget $target ) {
1024 if ( $target instanceof UserBlockTarget ) {
1025 return [
1026 'bt_user' => $target->getUserIdentity()->getId( $this->wikiId )
1027 ];
1028 } elseif ( $target instanceof AnonIpBlockTarget || $target instanceof RangeBlockTarget ) {
1029 return [ 'bt_address' => $target->toString() ];
1030 } else {
1031 throw new \InvalidArgumentException( 'Invalid target type' );
1032 }
1033 }
1034
1049 private function acquireTarget(
1050 DatabaseBlock $block,
1051 IDatabase $dbw,
1052 $expectedTargetCount
1053 ) {
1054 $target = $block->getTarget();
1055 // Note: for new autoblocks, the target is an IpBlockTarget
1056 $isAuto = $block->getType() === Block::TYPE_AUTO;
1057 if ( $target instanceof UserBlockTarget ) {
1058 $targetAddress = null;
1059 $targetUserName = (string)$target;
1060 $targetUserId = $target->getUserIdentity()->getId( $this->wikiId );
1061 $targetConds = [ 'bt_user' => $targetUserId ];
1062 $targetLockKey = $dbw->getDomainID() . ':block:u:' . $targetUserId;
1063 } else {
1064 $targetAddress = (string)$target;
1065 $targetUserName = null;
1066 $targetUserId = null;
1067 $targetConds = [
1068 'bt_address' => $targetAddress,
1069 'bt_auto' => $isAuto,
1070 ];
1071 $targetLockKey = $dbw->getDomainID() . ':block:' .
1072 ( $isAuto ? 'a' : 'i' ) . ':' . $targetAddress;
1073 }
1074
1075 $condsWithCount = $targetConds;
1076 if ( $expectedTargetCount !== null ) {
1077 $condsWithCount['bt_count'] = $expectedTargetCount;
1078 }
1079
1080 $lockManager = $this->lockManager;
1081 $lockManager->lockKey( $targetLockKey );
1082 $dbw->onTransactionCommitOrIdle(
1083 static function () use ( $lockManager, $targetLockKey ) {
1084 $lockManager->unlockKey( $targetLockKey );
1085 },
1086 __METHOD__
1087 );
1088
1089 // This query locks the index gap when the target doesn't exist yet,
1090 // so there is a risk of throttling adjacent block insertions,
1091 // especially on small wikis which have larger gaps. If this proves to
1092 // be a problem, we could have getPrimaryDB() return an autocommit
1093 // connection.
1094 $dbw->newUpdateQueryBuilder()
1095 ->update( 'block_target' )
1096 ->set( [ 'bt_count' => new RawSQLValue( 'bt_count+1' ) ] )
1097 ->where( $condsWithCount )
1098 ->caller( __METHOD__ )->execute();
1099 $numUpdatedRows = $dbw->affectedRows();
1100
1101 // Now that the row is locked, find the target ID
1102 $res = $dbw->newSelectQueryBuilder()
1103 ->select( [ 'bt_id', 'bt_count' ] )
1104 ->from( 'block_target' )
1105 ->where( $targetConds )
1106 ->forUpdate()
1107 ->caller( __METHOD__ )
1108 ->fetchResultSet();
1109 if ( $res->numRows() > 1 ) {
1110 $ids = [];
1111 foreach ( $res as $row ) {
1112 $ids[] = $row->bt_id;
1113 }
1114 throw new RuntimeException( "Duplicate block_target rows detected: " .
1115 implode( ',', $ids ) );
1116 }
1117 $row = $res->fetchObject();
1118
1119 if ( $row ) {
1120 $count = (int)$row->bt_count;
1121 if ( !$numUpdatedRows ) {
1122 // ID found but count update failed -- must be a conflict due to bt_count mismatch
1123 return [ null, $count ];
1124 }
1125 $id = (int)$row->bt_id;
1126 } else {
1127 if ( $numUpdatedRows ) {
1128 throw new RuntimeException(
1129 'block_target row unexpectedly missing after we locked it' );
1130 }
1131 if ( $expectedTargetCount !== 0 && $expectedTargetCount !== null ) {
1132 // Conflict (expectation failure)
1133 return [ null, 0 ];
1134 }
1135
1136 // Insert new row
1137 $targetRow = [
1138 'bt_address' => $targetAddress,
1139 'bt_user' => $targetUserId,
1140 'bt_user_text' => $targetUserName,
1141 'bt_auto' => $isAuto,
1142 'bt_range_start' => $block->getRangeStart(),
1143 'bt_range_end' => $block->getRangeEnd(),
1144 'bt_ip_hex' => $block->getIpHex(),
1145 'bt_count' => 1
1146 ];
1147 $dbw->newInsertQueryBuilder()
1148 ->insertInto( 'block_target' )
1149 ->row( $targetRow )
1150 ->caller( __METHOD__ )->execute();
1151 $id = $dbw->insertId();
1152 if ( !$id ) {
1153 throw new RuntimeException(
1154 'block_target insert ID is falsey despite unconditional insert' );
1155 }
1156 $count = 1;
1157 }
1158
1159 return [ $id, $count ];
1160 }
1161
1173 public function updateBlock( DatabaseBlock $block ) {
1174 $this->logger->debug( 'Updating block; timestamp ' . $block->getTimestamp() );
1175
1176 $block->assertWiki( $this->wikiId );
1177
1178 $blockId = $block->getId( $this->wikiId );
1179 if ( !$blockId ) {
1180 throw new InvalidArgumentException(
1181 __METHOD__ . ' requires that a block id be set'
1182 );
1183 }
1184
1185 // Update bl_timestamp to current when making any updates to a block (T389275)
1186 $block->setTimestamp( wfTimestamp() );
1187
1188 $dbw = $this->getPrimaryDB();
1189
1190 $dbw->startAtomic( __METHOD__ );
1191
1192 $row = $this->getArrayForBlockUpdate( $block, $dbw );
1193 $dbw->newUpdateQueryBuilder()
1194 ->update( 'block' )
1195 ->set( $row )
1196 ->where( [ 'bl_id' => $blockId ] )
1197 ->caller( __METHOD__ )->execute();
1198
1199 // Only update the restrictions if they have been modified.
1200 $result = true;
1201 $restrictions = $block->getRawRestrictions();
1202 if ( $restrictions !== null ) {
1203 // An empty array should remove all of the restrictions.
1204 if ( $restrictions === [] ) {
1205 $result = $this->blockRestrictionStore->deleteByBlockId( $blockId );
1206 } else {
1207 $result = $this->blockRestrictionStore->update( $restrictions );
1208 }
1209 }
1210
1211 if ( $block->isAutoblocking() ) {
1212 // Update corresponding autoblock(s) (T50813)
1213 $dbw->newUpdateQueryBuilder()
1214 ->update( 'block' )
1215 ->set( $this->getArrayForAutoblockUpdate( $block ) )
1216 ->where( [ 'bl_parent_block_id' => $blockId ] )
1217 ->caller( __METHOD__ )->execute();
1218
1219 // Only update the restrictions if they have been modified.
1220 if ( $restrictions !== null ) {
1221 $this->blockRestrictionStore->updateByParentBlockId(
1222 $blockId,
1223 $restrictions
1224 );
1225 }
1226 } else {
1227 // Autoblock no longer required, delete corresponding autoblock(s)
1228 $this->deleteBlocksMatchingConds( [ 'bl_parent_block_id' => $blockId ] );
1229 }
1230
1231 $dbw->endAtomic( __METHOD__ );
1232
1233 if ( $result ) {
1234 $autoBlockIds = $this->doRetroactiveAutoblock( $block );
1235 return [ 'id' => $blockId, 'autoIds' => $autoBlockIds ];
1236 }
1237
1238 return false;
1239 }
1240
1254 public function updateTarget( DatabaseBlock $block, $newTarget ) {
1255 $dbw = $this->getPrimaryDB();
1256 $blockId = $block->getId( $this->wikiId );
1257 if ( !$blockId ) {
1258 throw new InvalidArgumentException(
1259 __METHOD__ . " requires that a block id be set\n"
1260 );
1261 }
1262 if ( !( $newTarget instanceof BlockTarget ) ) {
1263 $newTarget = $this->blockTargetFactory->newFromLegacyUnion( $newTarget );
1264 }
1265
1266 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1267 $oldTargetConds = $this->getTargetConds( $block->getTarget() );
1268 $block->setTarget( $newTarget );
1269
1270 $dbw->startAtomic( __METHOD__ );
1271 [ $targetId, $count ] = $this->acquireTarget( $block, $dbw, null );
1272 if ( !$targetId ) {
1273 // This is an exotic and unlikely error -- perhaps an exception should be thrown
1274 $dbw->endAtomic( __METHOD__ );
1275 return false;
1276 }
1277 $oldTargetId = $dbw->newSelectQueryBuilder()
1278 ->select( 'bt_id' )
1279 ->from( 'block_target' )
1280 ->where( $oldTargetConds )
1281 ->caller( __METHOD__ )->fetchField();
1282 $this->releaseTargets( $dbw, [ $oldTargetId ] );
1283
1284 $dbw->newUpdateQueryBuilder()
1285 ->update( 'block' )
1286 ->set( [ 'bl_target' => $targetId ] )
1287 ->where( [ 'bl_id' => $blockId ] )
1288 ->caller( __METHOD__ )
1289 ->execute();
1290 $affected = $dbw->affectedRows();
1291 $dbw->endAtomic( __METHOD__ );
1292 return (bool)$affected;
1293 }
1294
1301 public function deleteBlock( DatabaseBlock $block ): bool {
1302 if ( $this->readOnlyMode->isReadOnly( $this->wikiId ) ) {
1303 return false;
1304 }
1305
1306 $block->assertWiki( $this->wikiId );
1307
1308 $blockId = $block->getId( $this->wikiId );
1309
1310 if ( !$blockId ) {
1311 throw new InvalidArgumentException(
1312 __METHOD__ . ' requires that a block id be set'
1313 );
1314 }
1315 $dbw = $this->getPrimaryDB();
1316 $dbw->startAtomic( __METHOD__ );
1317 $res = $dbw->newSelectQueryBuilder()
1318 ->select( [ 'bl_id', 'bl_target' ] )
1319 ->from( 'block' )
1320 ->where(
1321 $dbw->orExpr( [
1322 'bl_parent_block_id' => $blockId,
1323 'bl_id' => $blockId,
1324 ] )
1325 )
1326 ->caller( __METHOD__ )->fetchResultSet();
1327 $this->deleteBlockRows( $res );
1328 $affected = $res->numRows();
1329 $dbw->endAtomic( __METHOD__ );
1330
1331 return $affected > 0;
1332 }
1333
1342 private function getArrayForBlockUpdate(
1343 DatabaseBlock $block,
1344 IDatabase $dbw
1345 ): array {
1346 $expiry = $dbw->encodeExpiry( $block->getExpiry() );
1347
1348 $blocker = $block->getBlocker();
1349 if ( !$blocker ) {
1350 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1351 }
1352 // DatabaseBlockStore supports inserting cross-wiki blocks by passing
1353 // non-local IDatabase and blocker.
1354 $blockerActor = $this->actorStoreFactory
1355 ->getActorStore( $dbw->getDomainID() )
1356 ->acquireActorId( $blocker, $dbw );
1357
1358 $blockArray = [
1359 'bl_by_actor' => $blockerActor,
1360 'bl_timestamp' => $dbw->timestamp( $block->getTimestamp() ),
1361 'bl_anon_only' => !$block->isHardblock(),
1362 'bl_create_account' => $block->isCreateAccountBlocked(),
1363 'bl_enable_autoblock' => $block->isAutoblocking(),
1364 'bl_expiry' => $expiry,
1365 'bl_deleted' => $this->getDeletedColumnValue( $block ),
1366 'bl_block_email' => $block->isEmailBlocked(),
1367 'bl_allow_usertalk' => $block->isUsertalkEditAllowed(),
1368 'bl_parent_block_id' => $block->getParentBlockId(),
1369 'bl_sitewide' => $block->isSitewide(),
1370 ];
1371 $commentArray = $this->commentStore->insert(
1372 $dbw,
1373 'bl_reason',
1374 $block->getReasonComment()
1375 );
1376
1377 $combinedArray = $blockArray + $commentArray;
1378 return $combinedArray;
1379 }
1380
1387 private function getArrayForAutoblockUpdate( DatabaseBlock $block ): array {
1388 $blocker = $block->getBlocker();
1389 if ( !$blocker ) {
1390 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1391 }
1392 $dbw = $this->getPrimaryDB();
1393 $blockerActor = $this->actorStoreFactory
1394 ->getActorNormalization( $this->wikiId )
1395 ->acquireActorId( $blocker, $dbw );
1396
1397 $blockArray = [
1398 'bl_by_actor' => $blockerActor,
1399 'bl_create_account' => $block->isCreateAccountBlocked(),
1400 'bl_deleted' => $this->getDeletedColumnValue( $block ),
1401 'bl_allow_usertalk' => $block->isUsertalkEditAllowed(),
1402 'bl_sitewide' => $block->isSitewide(),
1403 ];
1404
1405 // Shorten the autoblock expiry if the parent block expiry is sooner.
1406 // Don't lengthen -- that is only done when the IP address is actually
1407 // used by the blocked user.
1408 if ( $block->getExpiry() !== 'infinity' ) {
1409 $blockArray['bl_expiry'] = new RawSQLValue( $dbw->conditional(
1410 $dbw->expr( 'bl_expiry', '>', $dbw->timestamp( $block->getExpiry() ) ),
1411 $dbw->addQuotes( $dbw->timestamp( $block->getExpiry() ) ),
1412 'bl_expiry'
1413 ) );
1414 }
1415
1416 $commentArray = $this->commentStore->insert(
1417 $dbw,
1418 'bl_reason',
1419 $this->getAutoblockReason( $block )
1420 );
1421
1422 $combinedArray = $blockArray + $commentArray;
1423 return $combinedArray;
1424 }
1425
1429 private function getDeletedColumnValue( DatabaseBlock $block ): int {
1430 if ( $block->getHideName() ) {
1431 return 1;
1432 } elseif ( $block->getHideBlock() ) {
1433 return 2;
1434 }
1435 return 0;
1436 }
1437
1445 private function doRetroactiveAutoblock( DatabaseBlock $block ): array {
1446 $autoBlockIds = [];
1447 // If autoblock is enabled, autoblock the LAST IP(s) used
1448 if ( $block->isAutoblocking() && $block->getType() == AbstractBlock::TYPE_USER ) {
1449 $this->logger->debug(
1450 'Doing retroactive autoblocks for ' . $block->getTargetName()
1451 );
1452
1453 $hookAutoBlocked = [];
1454 $continue = $this->hookRunner->onPerformRetroactiveAutoblock(
1455 $block,
1456 $hookAutoBlocked
1457 );
1458
1459 if ( $continue ) {
1460 $coreAutoBlocked = $this->performRetroactiveAutoblock( $block );
1461 $autoBlockIds = array_merge( $hookAutoBlocked, $coreAutoBlocked );
1462 } else {
1463 $autoBlockIds = $hookAutoBlocked;
1464 }
1465 }
1466 return $autoBlockIds;
1467 }
1468
1476 private function performRetroactiveAutoblock( DatabaseBlock $block ): array {
1477 if ( !$this->options->get( MainConfigNames::PutIPinRC ) ) {
1478 // No IPs in the recent changes table to autoblock
1479 return [];
1480 }
1481
1482 $target = $block->getTarget();
1483 if ( !( $target instanceof UserBlockTarget ) ) {
1484 // Autoblocks only apply to users
1485 return [];
1486 }
1487
1488 $dbr = $this->getReplicaDB();
1489
1490 $actor = $this->actorStoreFactory
1491 ->getActorNormalization( $this->wikiId )
1492 ->findActorId( $target->getUserIdentity(), $dbr );
1493
1494 if ( !$actor ) {
1495 $this->logger->debug( 'No actor found to retroactively autoblock' );
1496 return [];
1497 }
1498
1499 $rcIp = $dbr->newSelectQueryBuilder()
1500 ->select( 'rc_ip' )
1501 ->from( 'recentchanges' )
1502 ->where( [ 'rc_actor' => $actor ] )
1503 ->orderBy( 'rc_timestamp', SelectQueryBuilder::SORT_DESC )
1504 ->caller( __METHOD__ )->fetchField();
1505
1506 if ( !$rcIp ) {
1507 $this->logger->debug( 'No IP found to retroactively autoblock' );
1508 return [];
1509 }
1510
1511 $id = $this->doAutoblock( $block, $rcIp );
1512 if ( !$id ) {
1513 return [];
1514 }
1515 return [ $id ];
1516 }
1517
1526 public function doAutoblock( DatabaseBlock $parentBlock, $autoblockIP ) {
1527 // If autoblocks are disabled, go away.
1528 if ( !$parentBlock->isAutoblocking() ) {
1529 return false;
1530 }
1531 $parentBlock->assertWiki( $this->wikiId );
1532
1533 $target = $this->blockTargetFactory->newFromIp( $autoblockIP );
1534 if ( !$target ) {
1535 $this->logger->debug( "Invalid autoblock IP" );
1536 return false;
1537 }
1538
1539 // Check if autoblock exempt.
1540 if ( $this->autoblockExemptionList->isExempt( $autoblockIP ) ) {
1541 return false;
1542 }
1543
1544 // Allow hooks to cancel the autoblock.
1545 if ( !$this->hookRunner->onAbortAutoblock( $autoblockIP, $parentBlock ) ) {
1546 $this->logger->debug( "Autoblock aborted by hook." );
1547 return false;
1548 }
1549
1550 // It's okay to autoblock. Go ahead and insert/update the block...
1551
1552 // Do not add a *new* block if the IP is already blocked.
1553 $blocks = $this->newLoad( $target, false );
1554 if ( $blocks ) {
1555 foreach ( $blocks as $ipblock ) {
1556 // Check if the block is an autoblock and would exceed the user block
1557 // if renewed. If so, do nothing, otherwise prolong the block time...
1558 if ( $ipblock->getType() === Block::TYPE_AUTO
1559 && $parentBlock->getExpiry() > $ipblock->getExpiry()
1560 ) {
1561 // Reset block timestamp to now and its expiry to
1562 // $wgAutoblockExpiry in the future
1563 $this->updateTimestamp( $ipblock );
1564 }
1565 }
1566 return false;
1567 }
1568 $blocker = $parentBlock->getBlocker();
1569 if ( !$blocker ) {
1570 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1571 }
1572
1573 // Acquire a lock on the primary DB for the autoblock to prevent race conditions (T260838)
1574 if ( !$this->lockManager->lockKey( 'autoblock:' . $target ) ) {
1575 return false;
1576 }
1577
1578 $timestamp = wfTimestampNow();
1579 $expiry = $this->getAutoblockExpiry( $timestamp, $parentBlock->getExpiry() );
1580 $autoblock = new DatabaseBlock( [
1581 'wiki' => $this->wikiId,
1582 'target' => $target,
1583 'by' => $blocker,
1584 'reason' => $this->getAutoblockReason( $parentBlock ),
1585 'decodedTimestamp' => $timestamp,
1586 'auto' => true,
1587 'createAccount' => $parentBlock->isCreateAccountBlocked(),
1588 // Continue suppressing the name if needed
1589 'hideName' => $parentBlock->getHideName(),
1590 'hideBlock' => $parentBlock->getHideBlock(),
1591 'allowUsertalk' => $parentBlock->isUsertalkEditAllowed(),
1592 'parentBlockId' => $parentBlock->getId( $this->wikiId ),
1593 'sitewide' => $parentBlock->isSitewide(),
1594 'restrictions' => $parentBlock->getRestrictions(),
1595 'decodedExpiry' => $expiry,
1596 ] );
1597
1598 $this->logger->debug( "Autoblocking {$parentBlock->getTargetName()}@" . $target );
1599
1600 $status = $this->insertBlock( $autoblock );
1601
1602 $this->lockManager->unlockKey( 'autoblock:' . $target );
1603
1604 return $status
1605 ? $status['id']
1606 : false;
1607 }
1608
1609 private function getAutoblockReason( DatabaseBlock $parentBlock ): string {
1611 'autoblocker',
1612 $parentBlock->getTargetName(),
1613 $parentBlock->getReasonComment()->text
1614 )->inContentLanguage()->plain();
1615 }
1616
1623 public function updateTimestamp( DatabaseBlock $block ) {
1624 $block->assertWiki( $this->wikiId );
1625 if ( $block->getType() !== Block::TYPE_AUTO ) {
1626 return;
1627 }
1628 $now = wfTimestamp();
1629 $block->setTimestamp( $now );
1630 // No need to reduce the autoblock expiry to the expiry of the parent
1631 // block, since the caller already checked for that.
1632 $block->setExpiry( $this->getAutoblockExpiry( $now ) );
1633
1634 $dbw = $this->getPrimaryDB();
1635 $dbw->newUpdateQueryBuilder()
1636 ->update( 'block' )
1637 ->set(
1638 [
1639 'bl_timestamp' => $dbw->timestamp( $block->getTimestamp() ),
1640 'bl_expiry' => $dbw->timestamp( $block->getExpiry() ),
1641 ]
1642 )
1643 ->where( [ 'bl_id' => $block->getId( $this->wikiId ) ] )
1644 ->caller( __METHOD__ )->execute();
1645 }
1646
1658 public function getAutoblockExpiry( $timestamp, ?string $parentExpiry = null ) {
1659 $maxDuration = $this->options->get( MainConfigNames::AutoblockExpiry );
1660 $expiry = wfTimestamp( TS::MW, (int)wfTimestamp( TS::UNIX, $timestamp ) + $maxDuration );
1661 if ( $parentExpiry !== null && $parentExpiry !== 'infinity' ) {
1662 $expiry = min( $parentExpiry, $expiry );
1663 }
1664 return $expiry;
1665 }
1666
1667 // endregion -- end of database write methods
1668
1669}
const LIST_OR
Definition Defines.php:33
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
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.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:71
isUsertalkEditAllowed( $x=null)
Get or set the flag indicating whether this block blocks the target from editing their own user talk ...
getTarget()
Get the target as an object.
setTarget( $target)
Set the target for this block.
getHideName()
Get whether the block hides the target's username.
getHideBlock()
Get whether the block is hidden.
setTimestamp( $timestamp)
Set the timestamp indicating when the block was created.
isCreateAccountBlocked( $x=null)
Get or set the flag indicating whether this block blocks the target from creating an account.
getTimestamp()
Get the timestamp indicating when the block was created.
isSitewide( $x=null)
Indicates that the block is a sitewide block.
getExpiry()
Get the block expiry time.
setExpiry( $expiry)
Set the block expiry time.
A block target of the form #1234 where the number is the block ID.
Provides access to the wiki's autoblock exemption list.
Factory for BlockTarget objects.
Base class for block targets.
__construct(ServiceOptions $options, LoggerInterface $logger, ActorStoreFactory $actorStoreFactory, BlockRestrictionStore $blockRestrictionStore, CommentStore $commentStore, HookContainer $hookContainer, IConnectionProvider $dbProvider, ReadOnlyMode $readOnlyMode, UserFactory $userFactory, TempUserConfig $tempUserConfig, BlockTargetFactory $blockTargetFactory, AutoblockExemptionList $autoblockExemptionList, SessionManagerInterface $sessionManager, ILockManager $lockManager, string|false $wikiId=DatabaseBlock::LOCAL)
newListFromIPs(array $addresses, $applySoftBlocks, $fromPrimary=false)
Get all blocks that match any IP from an array of IP addresses.
updateTimestamp(DatabaseBlock $block)
Update the timestamp on autoblocks.
newFromRow(IReadableDatabase $db, $row)
Create a new DatabaseBlock object from a database row.
newListFromTarget( $specificTarget, $vagueTarget=null, $fromPrimary=false, $auto=self::AUTO_ALL)
This is similar to DatabaseBlockStore::newFromTarget, but it returns all the relevant blocks.
getAutoblockExpiry( $timestamp, ?string $parentExpiry=null)
Get the expiry timestamp for an autoblock created at the given time.
deleteBlocksMatchingConds(array $conds, $limit=null)
Delete all blocks matching the given conditions.
newUnsaved(array $options)
Create a DatabaseBlock representing an unsaved block.
updateBlock(DatabaseBlock $block)
Update a block in the DB with new parameters.
newListFromConds( $conds, $fromPrimary=false, $includeExpired=false)
Construct an array of blocks from database conditions.
updateTarget(DatabaseBlock $block, $newTarget)
Update the target in the specified object and in the database.
deleteBlock(DatabaseBlock $block)
Delete a DatabaseBlock from the database.
newFromTarget( $specificTarget, $vagueTarget=null, $fromPrimary=false, $auto=self::AUTO_ALL)
Given a target and the target's type, get an existing block object if possible.
insertBlock(DatabaseBlock $block, $expectedTargetCount=0)
Insert a block into the block table.
const AUTO_SPECIFIED
Load only autoblocks specified by ID.
purgeExpiredBlocks()
Delete expired blocks from the block table.
getConditionForRanges(array $ranges)
Get a set of SQL conditions which select range blocks encompassing the given ranges.
insertBlockWithParams(array $params)
Create a block with an array of parameters and immediately insert it.
doAutoblock(DatabaseBlock $parentBlock, $autoblockIP)
Autoblocks the given IP, referring to the specified block.
const AUTO_NONE
Do not load autoblocks.
getRangeCond( $start, $end)
Get a set of SQL conditions which select range blocks encompassing a given range.
getQueryInfo()
Return the tables, fields, and join conditions to be selected to create a new block object.
newFromID( $id, $fromPrimary=false, $includeExpired=false)
Load a block from the block ID.
A DatabaseBlock (unlike a SystemBlock) is stored in the database, may give rise to autoblocks and may...
getBlocker()
Get the user who implemented this block.
getId( $wikiId=self::LOCAL)
Get the block ID.?int
getRestrictions()
Getting the restrictions will perform a database query if the restrictions are not already loaded.
getRawRestrictions()
Get restrictions without loading from database if not yet loaded.
isAutoblocking( $x=null)
Does the block cause autoblocks to be created?
getType()
Get the type of target for this particular block.int|null AbstractBlock::TYPE_ constant
Handle database storage of comments such as edit summaries and log reasons.
A class for passing options to services.
assertRequiredOptions(array $expectedKeys)
Assert that the list of options provided in this instance exactly match $expectedKeys,...
Deferrable Update for closure/callback updates that should use auto-commit mode.
Defer callable updates to run later in the PHP process.
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
A class containing constants representing the names of configuration variables.
const UpdateRowsPerQuery
Name constant for the UpdateRowsPerQuery setting, for use with Config::get()
const BlockDisablesLogin
Name constant for the BlockDisablesLogin setting, for use with Config::get()
const AutoblockExpiry
Name constant for the AutoblockExpiry setting, for use with Config::get()
const BlockCIDRLimit
Name constant for the BlockCIDRLimit setting, for use with Config::get()
const PutIPinRC
Name constant for the PutIPinRC setting, for use with Config::get()
ActorStore factory for any wiki domain.
Create User objects.
Content of like value.
Definition LikeValue.php:14
Raw SQL expression to be used in query builders.
Raw SQL value to be used in query builders.
Determine whether a site is currently in read-only mode.
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, 'EnableChunkedUploads'=> 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'=> true, '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 -l $lang -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'MaxAnimatedWebPArea'=> 12500000, 'WebPThumbnailType'=>['webp', 'image/webp',], '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, 'RestTermsOfServiceUrl'=> null, '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'=>[], 'RemoteVirtualDomainsMapping'=>[], '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, 'SplitParsoidParserCache'=> true, '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, '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, ], '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', 'editmywatchlist' => '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', 'editmywatchlist' => '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', 'managesessions' => '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, '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' => [ ], 'RestLocalModuleTestBaseUrl' => null, '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' => [ ], 'UseParsoidLinksUpdate' => null, 'UseParsoidMessages' => null, ], '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', ], 'WebPThumbnailType' => 'array', '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', ], 'RestTermsOfServiceUrl' => [ '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', 'RemoteVirtualDomainsMapping' => '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', 'SplitParsoidParserCache' => 'boolean', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => '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', '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', 'RestLocalModuleTestBaseUrl' => [ 'string', 'null', ], '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', 'UseParsoidLinksUpdate' => [ 'boolean', 'null', ], 'UseParsoidMessages' => [ 'boolean', 'null', ], ], 'mergeStrategy' => [ 'WebPThumbnailType' => 'replace', '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', ], ], ], ], ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], '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', ], 'skipRedirects' => [ 'type' => 'bool', ], ], ], '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', ], ], 'RestModuleOverrides' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'availability' => [ 'type' => 'string', ], ], 'required' => [ 'availability', ], ], ], '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.', ],]
assertWiki( $wikiId)
Throws if $wikiId is different from the return value of getWikiId().
const LOCAL
Wiki ID value to use with instances that are defined relative to the local wiki.
MediaWiki\Session entry point interface.
Interface for temporary user creation config and name matching.
Interface for objects representing user identity.
Interface representing MediaWiki's LockManager.
lockKey(string $key, int $timeout=0)
Provide a mutex of the key.
Provide primary and replica IDatabase connections.
Interface to a relational database.
Definition IDatabase.php:31
A database connection without write operations.
newSelectQueryBuilder()
Create an empty SelectQueryBuilder which can be used to run queries against this connection.
expr(string $field, string $op, $value)
See Expression::__construct()
Result wrapper for grabbing data queried from an IDatabase object.
decodeExpiry( $expiry, $format=TS::MW)
Decode an expiry time into a DBMS independent format.
timestamp( $ts=0)
Convert a timestamp in one of the formats accepted by ConvertibleTimestamp to the format used for ins...