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;
38use Wikimedia\Timestamp\TimestampFormat as TS;
39use function array_key_exists;
40
48 public const AUTO_ALL = 'all';
50 public const AUTO_SPECIFIED = 'specified';
52 public const AUTO_NONE = 'none';
53
57 public const CONSTRUCTOR_OPTIONS = [
63 ];
64
65 private string|false $wikiId;
66
67 private ServiceOptions $options;
68 private LoggerInterface $logger;
69 private ActorStoreFactory $actorStoreFactory;
70 private BlockRestrictionStore $blockRestrictionStore;
71 private CommentStore $commentStore;
72 private HookRunner $hookRunner;
73 private IConnectionProvider $dbProvider;
74 private ReadOnlyMode $readOnlyMode;
75 private UserFactory $userFactory;
76 private TempUserConfig $tempUserConfig;
77 private BlockTargetFactory $blockTargetFactory;
78 private AutoblockExemptionList $autoblockExemptionList;
79 private SessionManagerInterface $sessionManager;
80
81 public function __construct(
82 ServiceOptions $options,
83 LoggerInterface $logger,
84 ActorStoreFactory $actorStoreFactory,
85 BlockRestrictionStore $blockRestrictionStore,
86 CommentStore $commentStore,
87 HookContainer $hookContainer,
88 IConnectionProvider $dbProvider,
89 ReadOnlyMode $readOnlyMode,
90 UserFactory $userFactory,
91 TempUserConfig $tempUserConfig,
92 BlockTargetFactory $blockTargetFactory,
93 AutoblockExemptionList $autoblockExemptionList,
94 SessionManagerInterface $sessionManager,
95 string|false $wikiId = DatabaseBlock::LOCAL
96 ) {
97 $options->assertRequiredOptions( self::CONSTRUCTOR_OPTIONS );
98
99 $this->wikiId = $wikiId;
100
101 $this->options = $options;
102 $this->logger = $logger;
103 $this->actorStoreFactory = $actorStoreFactory;
104 $this->blockRestrictionStore = $blockRestrictionStore;
105 $this->commentStore = $commentStore;
106 $this->hookRunner = new HookRunner( $hookContainer );
107 $this->dbProvider = $dbProvider;
108 $this->readOnlyMode = $readOnlyMode;
109 $this->userFactory = $userFactory;
110 $this->tempUserConfig = $tempUserConfig;
111 $this->blockTargetFactory = $blockTargetFactory;
112 $this->autoblockExemptionList = $autoblockExemptionList;
113 $this->sessionManager = $sessionManager;
114 }
115
116 /***************************************************************************/
117 // region Database read methods
129 public function newFromID( $id, $fromPrimary = false, $includeExpired = false ) {
130 $blocks = $this->newListFromConds( [ 'bl_id' => $id ], $fromPrimary, $includeExpired );
131 return $blocks ? $blocks[0] : null;
132 }
133
150 public function getQueryInfo() {
151 $commentQuery = $this->commentStore->getJoin( 'bl_reason' );
152 return [
153 'tables' => [
154 'block',
155 'block_target',
156 'block_by_actor' => 'actor',
157 ] + $commentQuery['tables'],
158 'fields' => [
159 'bl_id',
160 'bt_address',
161 'bt_user',
162 'bt_user_text',
163 'bl_timestamp',
164 'bt_auto',
165 'bl_anon_only',
166 'bl_create_account',
167 'bl_enable_autoblock',
168 'bl_expiry',
169 'bl_deleted',
170 'bl_block_email',
171 'bl_allow_usertalk',
172 'bl_parent_block_id',
173 'bl_sitewide',
174 'bl_by_actor',
175 'bl_by' => 'block_by_actor.actor_user',
176 'bl_by_text' => 'block_by_actor.actor_name',
177 ] + $commentQuery['fields'],
178 'joins' => [
179 'block_target' => [ 'JOIN', 'bt_id=bl_target' ],
180 'block_by_actor' => [ 'JOIN', 'actor_id=bl_by_actor' ],
181 ] + $commentQuery['joins'],
182 ];
183 }
184
197 private function newLoad(
198 $specificTarget,
199 $fromPrimary,
200 $vagueTarget = null,
201 $auto = self::AUTO_ALL
202 ) {
203 if ( $fromPrimary ) {
204 $db = $this->getPrimaryDB();
205 } else {
206 $db = $this->getReplicaDB();
207 }
208
209 $userIds = [];
210 $userNames = [];
211 $addresses = [];
212 $ranges = [];
213 if ( $specificTarget instanceof UserBlockTarget ) {
214 $userId = $specificTarget->getUserIdentity()->getId( $this->wikiId );
215 if ( $userId ) {
216 $userIds[] = $userId;
217 } else {
218 // A nonexistent user can have no blocks.
219 // This case is hit in testing, possibly production too.
220 // Ignoring the user is optimal for production performance.
221 }
222 } elseif ( $specificTarget instanceof AnonIpBlockTarget
223 || $specificTarget instanceof RangeBlockTarget
224 ) {
225 $addresses[] = (string)$specificTarget;
226 }
227
228 // Be aware that the != '' check is explicit, since empty values will be
229 // passed by some callers (T31116)
230 if ( $vagueTarget !== null ) {
231 if ( $vagueTarget instanceof UserBlockTarget ) {
232 // Slightly weird, but who are we to argue?
233 $vagueUser = $vagueTarget->getUserIdentity();
234 $userId = $vagueUser->getId( $this->wikiId );
235 if ( $userId ) {
236 $userIds[] = $userId;
237 } else {
238 $userNames[] = $vagueUser->getName();
239 }
240 } elseif ( $vagueTarget instanceof BlockTargetWithIp ) {
241 $ranges[] = $vagueTarget->toHexRange();
242 } else {
243 $this->logger->debug( "Ignoring invalid vague target" );
244 }
245 }
246
247 $orConds = [];
248 if ( $userIds ) {
249 $orConds[] = $db->expr( 'bt_user', '=', array_values( array_unique( $userIds ) ) );
250 }
251 if ( $userNames ) {
252 // Add bt_ip_hex to the condition since it is in the index
253 $orConds[] = $db->expr( 'bt_ip_hex', '=', null )
254 ->and( 'bt_user_text', '=', array_values( array_unique( $userNames ) ) );
255 }
256 if ( $addresses ) {
257 $orConds[] = $db->expr( 'bt_address', '=', array_values( array_unique( $addresses ) ) );
258 }
259 foreach ( $this->getConditionForRanges( $ranges ) as $cond ) {
260 $orConds[] = new RawSQLExpression( $cond );
261 }
262 if ( !$orConds ) {
263 return [];
264 }
265
266 // Exclude autoblocks unless AUTO_ALL was requested.
267 $autoConds = $auto === self::AUTO_ALL ? [] : [ 'bt_auto' => 0 ];
268
269 $blockQuery = $this->getQueryInfo();
270 $res = $db->newSelectQueryBuilder()
271 ->queryInfo( $blockQuery )
272 ->where( $db->orExpr( $orConds ) )
273 ->andWhere( $autoConds )
274 ->caller( __METHOD__ )
275 ->fetchResultSet();
276
277 $blocks = [];
278 $blockIds = [];
279 $autoBlocks = [];
280 foreach ( $res as $row ) {
281 $block = $this->newFromRow( $db, $row );
282
283 // Don't use expired blocks
284 if ( $block->isExpired() ) {
285 continue;
286 }
287
288 // Don't use anon only blocks on users
289 if (
290 $specificTarget instanceof UserBlockTarget &&
291 !$block->isHardblock() &&
292 !$this->tempUserConfig->isTempName( $specificTarget->toString() )
293 ) {
294 continue;
295 }
296
297 // Check for duplicate autoblocks
298 if ( $block->getType() === Block::TYPE_AUTO ) {
299 $autoBlocks[] = $block;
300 } else {
301 $blocks[] = $block;
302 $blockIds[] = $block->getId( $this->wikiId );
303 }
304 }
305
306 // Only add autoblocks that aren't duplicates
307 foreach ( $autoBlocks as $block ) {
308 if ( !in_array( $block->getParentBlockId(), $blockIds ) ) {
309 $blocks[] = $block;
310 }
311 }
312
313 return $blocks;
314 }
315
324 private function chooseMostSpecificBlock( array $blocks ) {
325 if ( count( $blocks ) === 1 ) {
326 return $blocks[0];
327 }
328
329 // This result could contain a block on the user, a block on the IP, and a russian-doll
330 // set of range blocks. We want to choose the most specific one, so keep a leader board.
331 $bestBlock = null;
332
333 // Lower will be better
334 $bestBlockScore = 100;
335 foreach ( $blocks as $block ) {
336 $score = $block->getTarget()->getSpecificity();
337 if ( $score < $bestBlockScore ) {
338 $bestBlockScore = $score;
339 $bestBlock = $block;
340 }
341 }
342
343 return $bestBlock;
344 }
345
357 public function getConditionForRanges( array $ranges ): array {
358 $dbr = $this->getReplicaDB();
359
360 $conds = [];
361 $individualIPs = [];
362 foreach ( $ranges as [ $start, $end ] ) {
363 // Per T16634, we want to include relevant active range blocks; for
364 // range blocks, we want to include larger ranges which enclose the given
365 // range. We know that all blocks must be smaller than $wgBlockCIDRLimit,
366 // so we can improve performance by filtering on a LIKE clause
367 $chunk = $this->getIpFragment( $start );
368 $end ??= $start;
369
370 $expr = $dbr->expr(
371 'bt_range_start',
372 IExpression::LIKE,
373 new LikeValue( $chunk, $dbr->anyString() )
374 )
375 ->and( 'bt_range_start', '<=', $start )
376 ->and( 'bt_range_end', '>=', $end );
377 if ( $start === $end ) {
378 $individualIPs[] = $start;
379 }
380 $conds[] = $expr->toSql( $dbr );
381 }
382 if ( $individualIPs ) {
383 // Also select single IP blocks for these targets
384 $conds[] = $dbr->expr( 'bt_ip_hex', '=', $individualIPs )
385 ->and( 'bt_range_start', '=', null )
386 ->toSql( $dbr );
387 }
388 return $conds;
389 }
390
401 public function getRangeCond( $start, $end ) {
402 $dbr = $this->getReplicaDB();
403 $conds = $this->getConditionForRanges( [ [ $start, $end ] ] );
404 return $dbr->makeList( $conds, IDatabase::LIST_OR );
405 }
406
414 private function getIpFragment( $hex ) {
415 $blockCIDRLimit = $this->options->get( MainConfigNames::BlockCIDRLimit );
416 if ( str_starts_with( $hex, 'v6-' ) ) {
417 return 'v6-' . substr( substr( $hex, 3 ), 0, (int)floor( $blockCIDRLimit['IPv6'] / 4 ) );
418 } else {
419 return substr( $hex, 0, (int)floor( $blockCIDRLimit['IPv4'] / 4 ) );
420 }
421 }
422
431 public function newFromRow( IReadableDatabase $db, $row ) {
432 return new DatabaseBlock( [
433 'target' => $this->blockTargetFactory->newFromRowRaw( $row ),
434 'wiki' => $this->wikiId,
435 'timestamp' => $row->bl_timestamp,
436 'auto' => (bool)$row->bt_auto,
437 'hideName' => (bool)$row->bl_deleted,
438 'id' => (int)$row->bl_id,
439 // Blocks with no parent ID should have bl_parent_block_id as null,
440 // don't save that as 0 though, see T282890
441 'parentBlockId' => $row->bl_parent_block_id
442 ? (int)$row->bl_parent_block_id : null,
443 'by' => $this->actorStoreFactory
444 ->getActorStore( $this->wikiId )
445 ->newActorFromRowFields( $row->bl_by, $row->bl_by_text, $row->bl_by_actor ),
446 'decodedExpiry' => $db->decodeExpiry( $row->bl_expiry ),
447 'reason' => $this->commentStore->getComment( 'bl_reason', $row ),
448 'anonOnly' => $row->bl_anon_only,
449 'enableAutoblock' => (bool)$row->bl_enable_autoblock,
450 'sitewide' => (bool)$row->bl_sitewide,
451 'createAccount' => (bool)$row->bl_create_account,
452 'blockEmail' => (bool)$row->bl_block_email,
453 'allowUsertalk' => (bool)$row->bl_allow_usertalk
454 ] );
455 }
456
486 public function newFromTarget(
487 $specificTarget,
488 $vagueTarget = null,
489 $fromPrimary = false,
490 $auto = self::AUTO_ALL
491 ) {
492 $blocks = $this->newListFromTarget( $specificTarget, $vagueTarget, $fromPrimary, $auto );
493 return $this->chooseMostSpecificBlock( $blocks );
494 }
495
509 public function newListFromTarget(
510 $specificTarget,
511 $vagueTarget = null,
512 $fromPrimary = false,
513 $auto = self::AUTO_ALL
514 ) {
515 if ( !( $specificTarget instanceof BlockTarget ) ) {
516 $specificTarget = $this->blockTargetFactory->newFromLegacyUnion( $specificTarget );
517 }
518 if ( $vagueTarget !== null && !( $vagueTarget instanceof BlockTarget ) ) {
519 $vagueTarget = $this->blockTargetFactory->newFromLegacyUnion( $vagueTarget );
520 }
521 if ( $specificTarget instanceof AutoBlockTarget ) {
522 if ( $auto === self::AUTO_NONE ) {
523 return [];
524 }
525 $block = $this->newFromID( $specificTarget->getId() );
526 return $block ? [ $block ] : [];
527 } elseif ( $specificTarget === null && $vagueTarget === null ) {
528 // We're not going to find anything useful here
529 return [];
530 } else {
531 return $this->newLoad( $specificTarget, $fromPrimary, $vagueTarget, $auto );
532 }
533 }
534
545 public function newListFromIPs( array $addresses, $applySoftBlocks, $fromPrimary = false ) {
546 $addresses = array_unique( $addresses );
547 if ( $addresses === [] ) {
548 return [];
549 }
550
551 $ranges = [];
552 foreach ( $addresses as $ipaddr ) {
553 $ranges[] = [ IPUtils::toHex( $ipaddr ), null ];
554 }
555 $rangeConds = $this->getConditionForRanges( $ranges );
556
557 if ( $fromPrimary ) {
558 $db = $this->getPrimaryDB();
559 } else {
560 $db = $this->getReplicaDB();
561 }
562 $conds = $db->makeList( $rangeConds, LIST_OR );
563 if ( !$applySoftBlocks ) {
564 $conds = [ $conds, 'bl_anon_only' => 0 ];
565 }
566 $blockQuery = $this->getQueryInfo();
567 $rows = $db->newSelectQueryBuilder()
568 ->queryInfo( $blockQuery )
569 ->fields( [ 'bt_range_start', 'bt_range_end' ] )
570 ->where( $conds )
571 ->caller( __METHOD__ )
572 ->fetchResultSet();
573
574 $blocks = [];
575 foreach ( $rows as $row ) {
576 $block = $this->newFromRow( $db, $row );
577 if ( !$block->isExpired() ) {
578 $blocks[] = $block;
579 }
580 }
581
582 return $blocks;
583 }
584
595 public function newListFromConds( $conds, $fromPrimary = false, $includeExpired = false ) {
596 $db = $fromPrimary ? $this->getPrimaryDB() : $this->getReplicaDB();
597 $conds = self::mapActorAlias( $conds );
598 if ( !$includeExpired ) {
599 $conds[] = $db->expr( 'bl_expiry', '>=', $db->timestamp() );
600 }
601 $res = $db->newSelectQueryBuilder()
602 ->queryInfo( $this->getQueryInfo() )
603 ->conds( $conds )
604 ->caller( __METHOD__ )
605 ->fetchResultSet();
606 $blocks = [];
607 foreach ( $res as $row ) {
608 $blocks[] = $this->newFromRow( $db, $row );
609 }
610 return $blocks;
611 }
612
613 // endregion -- end of database read methods
614
615 /***************************************************************************/
616 // region Database write methods
632 public function newUnsaved( array $options ): DatabaseBlock {
633 if ( isset( $options['targetUser'] ) ) {
634 $options['target'] = $this->blockTargetFactory
635 ->newFromUser( $options['targetUser'] );
636 unset( $options['targetUser'] );
637 }
638 if ( isset( $options['address'] ) ) {
639 $target = $this->blockTargetFactory
640 ->newFromString( $options['address'] );
641 if ( !$target ) {
642 throw new InvalidArgumentException( 'Invalid target address' );
643 }
644 $options['target'] = $target;
645 unset( $options['address'] );
646 }
647 return new DatabaseBlock( $options );
648 }
649
655 public function purgeExpiredBlocks() {
656 if ( $this->readOnlyMode->isReadOnly( $this->wikiId ) ) {
657 return;
658 }
659
660 $dbw = $this->getPrimaryDB();
661
662 DeferredUpdates::addUpdate( new AutoCommitUpdate(
663 $dbw,
664 __METHOD__,
665 function ( IDatabase $dbw, $fname ) {
666 $limit = $this->options->get( MainConfigNames::UpdateRowsPerQuery );
667 $res = $dbw->newSelectQueryBuilder()
668 ->select( [ 'bl_id', 'bl_target' ] )
669 ->from( 'block' )
670 ->where( $dbw->expr( 'bl_expiry', '<', $dbw->timestamp() ) )
671 // Set a limit to avoid causing replication lag (T301742)
672 ->limit( $limit )
673 ->caller( $fname )->fetchResultSet();
674 $this->deleteBlockRows( $res );
675 }
676 ) );
677 }
678
688 public function deleteBlocksMatchingConds( array $conds, $limit = null ) {
689 $dbw = $this->getPrimaryDB();
690 $conds = self::mapActorAlias( $conds );
691 $qb = $dbw->newSelectQueryBuilder()
692 ->select( [ 'bl_id', 'bl_target' ] )
693 ->from( 'block' )
694 // Typical input conds need block_target
695 ->join( 'block_target', null, 'bt_id=bl_target' )
696 ->where( $conds )
697 ->caller( __METHOD__ );
698 if ( self::hasActorAlias( $conds ) ) {
699 $qb->join( 'actor', 'ipblocks_actor', 'actor_id=bl_by_actor' );
700 }
701 if ( $limit !== null ) {
702 $qb->limit( $limit );
703 }
704 $res = $qb->fetchResultSet();
705 return $this->deleteBlockRows( $res );
706 }
707
714 private static function mapActorAlias( $conds ) {
715 return self::mapConds(
716 [
717 'bl_by' => 'ipblocks_actor.actor_user',
718 ],
719 $conds
720 );
721 }
722
727 private static function hasActorAlias( $conds ) {
728 return array_key_exists( 'ipblocks_actor.actor_user', $conds )
729 || array_key_exists( 'ipblocks_actor.actor_name', $conds );
730 }
731
739 private static function mapConds( $map, $conds ) {
740 $newConds = [];
741 foreach ( $conds as $field => $value ) {
742 if ( isset( $map[$field] ) ) {
743 $newConds[$map[$field]] = $value;
744 } else {
745 $newConds[$field] = $value;
746 }
747 }
748 return $newConds;
749 }
750
758 private function deleteBlockRows( $rows ) {
759 $ids = [];
760 $deltasByTarget = [];
761 foreach ( $rows as $row ) {
762 $ids[] = (int)$row->bl_id;
763 $target = (int)$row->bl_target;
764 if ( !isset( $deltasByTarget[$target] ) ) {
765 $deltasByTarget[$target] = 0;
766 }
767 $deltasByTarget[$target]++;
768 }
769 if ( !$ids ) {
770 return 0;
771 }
772 $dbw = $this->getPrimaryDB();
773 $dbw->startAtomic( __METHOD__ );
774
775 $maxTargetCount = max( $deltasByTarget );
776 for ( $delta = 1; $delta <= $maxTargetCount; $delta++ ) {
777 $targetsWithThisDelta = array_keys( $deltasByTarget, $delta, true );
778 if ( $targetsWithThisDelta ) {
779 $this->releaseTargets( $dbw, $targetsWithThisDelta, $delta );
780 }
781 }
782
783 $dbw->newDeleteQueryBuilder()
784 ->deleteFrom( 'block' )
785 ->where( [ 'bl_id' => $ids ] )
786 ->caller( __METHOD__ )->execute();
787 $numDeleted = $dbw->affectedRows();
788 $dbw->endAtomic( __METHOD__ );
789 $this->blockRestrictionStore->deleteByBlockId( $ids );
790 return $numDeleted;
791 }
792
801 private function releaseTargets( IDatabase $dbw, $targetIds, int $delta = 1 ) {
802 if ( !$targetIds ) {
803 return;
804 }
805 $dbw->newUpdateQueryBuilder()
806 ->update( 'block_target' )
807 ->set( [ 'bt_count' => new RawSQLValue( "bt_count-$delta" ) ] )
808 ->where( [ 'bt_id' => $targetIds ] )
809 ->caller( __METHOD__ )
810 ->execute();
811 $dbw->newDeleteQueryBuilder()
812 ->deleteFrom( 'block_target' )
813 ->where( [
814 'bt_count<1',
815 'bt_id' => $targetIds
816 ] )
817 ->caller( __METHOD__ )
818 ->execute();
819 }
820
821 private function getReplicaDB(): IReadableDatabase {
822 return $this->dbProvider->getReplicaDatabase( $this->wikiId );
823 }
824
825 private function getPrimaryDB(): IDatabase {
826 return $this->dbProvider->getPrimaryDatabase( $this->wikiId );
827 }
828
842 public function insertBlock(
843 DatabaseBlock $block,
844 $expectedTargetCount = 0
845 ) {
846 $block->assertWiki( $this->wikiId );
847
848 $blocker = $block->getBlocker();
849 if ( !$blocker || $blocker->getName() === '' ) {
850 throw new InvalidArgumentException( 'Cannot insert a block without a blocker set' );
851 }
852
853 if ( $expectedTargetCount instanceof IDatabase ) {
854 throw new InvalidArgumentException(
855 'Old method signature: Passing a custom database connection to '
856 . 'DatabaseBlockStore::insertBlock is no longer supported'
857 );
858 }
859
860 $this->logger->debug( 'Inserting block; timestamp ' . $block->getTimestamp() );
861
862 // Purge expired blocks. This now just queues a deferred update, so it
863 // is possible for expired blocks to conflict with inserted blocks below.
864 $this->purgeExpiredBlocks();
865
866 $dbw = $this->getPrimaryDB();
867 $dbw->startAtomic( __METHOD__ );
868 $finalTargetCount = $this->attemptInsert( $block, $dbw, $expectedTargetCount );
869 $purgeDone = false;
870
871 // Don't collide with expired blocks.
872 // Do this after trying to insert to avoid locking.
873 if ( !$finalTargetCount ) {
874 if ( $this->purgeExpiredConflicts( $block, $dbw ) ) {
875 $finalTargetCount = $this->attemptInsert( $block, $dbw, $expectedTargetCount );
876 $purgeDone = true;
877 }
878 }
879 $dbw->endAtomic( __METHOD__ );
880
881 if ( $finalTargetCount > 1 && !$purgeDone ) {
882 // Subtract expired blocks from the target count
883 $expiredBlockCount = $this->getExpiredConflictingBlockRows( $block, $dbw )->count();
884 if ( $expiredBlockCount >= $finalTargetCount ) {
885 $finalTargetCount = 1;
886 } else {
887 $finalTargetCount -= $expiredBlockCount;
888 }
889 }
890
891 if ( $finalTargetCount ) {
892 $autoBlockIds = $this->doRetroactiveAutoblock( $block );
893
894 if ( $this->options->get( MainConfigNames::BlockDisablesLogin ) ) {
895 $targetUserIdentity = $block->getTargetUserIdentity();
896 if ( $targetUserIdentity ) {
897 $targetUser = $this->userFactory->newFromUserIdentity( $targetUserIdentity );
898 $this->sessionManager->invalidateSessionsForUser( $targetUser );
899 }
900 }
901
902 return [
903 'id' => $block->getId( $this->wikiId ),
904 'autoIds' => $autoBlockIds,
905 'finalTargetCount' => $finalTargetCount
906 ];
907 }
908
909 return false;
910 }
911
923 public function insertBlockWithParams( array $params ): DatabaseBlock {
924 $block = $this->newUnsaved( $params );
925 $status = $this->insertBlock( $block, $params['expectedTargetCount'] ?? null );
926 if ( !$status ) {
927 throw new RuntimeException( 'Failed to insert block' );
928 }
929 return $block;
930 }
931
941 private function attemptInsert(
942 DatabaseBlock $block,
943 IDatabase $dbw,
944 $expectedTargetCount
945 ) {
946 [ $targetId, $finalCount ] = $this->acquireTarget( $block, $dbw, $expectedTargetCount );
947 if ( !$targetId ) {
948 return false;
949 }
950 $row = $this->getArrayForBlockUpdate( $block, $dbw );
951 $row['bl_target'] = $targetId;
952 $dbw->newInsertQueryBuilder()
953 ->insertInto( 'block' )
954 ->row( $row )
955 ->caller( __METHOD__ )->execute();
956 if ( !$dbw->affectedRows() ) {
957 return false;
958 }
959 $id = $dbw->insertId();
960
961 if ( !$id ) {
962 throw new RuntimeException( 'block insert ID is falsey' );
963 }
964 $block->setId( $id );
965 $restrictions = $block->getRawRestrictions();
966 if ( $restrictions ) {
967 $this->blockRestrictionStore->insert( $restrictions );
968 }
969
970 return $finalCount;
971 }
972
980 private function purgeExpiredConflicts(
981 DatabaseBlock $block,
982 IDatabase $dbw
983 ) {
984 return (bool)$this->deleteBlockRows(
985 $this->getExpiredConflictingBlockRows( $block, $dbw )
986 );
987 }
988
997 private function getExpiredConflictingBlockRows(
998 DatabaseBlock $block,
999 IDatabase $dbw
1000 ) {
1001 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1002 $targetConds = $this->getTargetConds( $block->getTarget() );
1003 return $dbw->newSelectQueryBuilder()
1004 ->select( [ 'bl_id', 'bl_target' ] )
1005 ->from( 'block' )
1006 ->join( 'block_target', null, [ 'bt_id=bl_target' ] )
1007 ->where( $targetConds )
1008 ->andWhere( $dbw->expr( 'bl_expiry', '<', $dbw->timestamp() ) )
1009 ->caller( __METHOD__ )->fetchResultSet();
1010 }
1011
1018 private function getTargetConds( BlockTarget $target ) {
1019 if ( $target instanceof UserBlockTarget ) {
1020 return [
1021 'bt_user' => $target->getUserIdentity()->getId( $this->wikiId )
1022 ];
1023 } elseif ( $target instanceof AnonIpBlockTarget || $target instanceof RangeBlockTarget ) {
1024 return [ 'bt_address' => $target->toString() ];
1025 } else {
1026 throw new \InvalidArgumentException( 'Invalid target type' );
1027 }
1028 }
1029
1044 private function acquireTarget(
1045 DatabaseBlock $block,
1046 IDatabase $dbw,
1047 $expectedTargetCount
1048 ) {
1049 $target = $block->getTarget();
1050 // Note: for new autoblocks, the target is an IpBlockTarget
1051 $isAuto = $block->getType() === Block::TYPE_AUTO;
1052 if ( $target instanceof UserBlockTarget ) {
1053 $targetAddress = null;
1054 $targetUserName = (string)$target;
1055 $targetUserId = $target->getUserIdentity()->getId( $this->wikiId );
1056 $targetConds = [ 'bt_user' => $targetUserId ];
1057 $targetLockKey = $dbw->getDomainID() . ':block:u:' . $targetUserId;
1058 } else {
1059 $targetAddress = (string)$target;
1060 $targetUserName = null;
1061 $targetUserId = null;
1062 $targetConds = [
1063 'bt_address' => $targetAddress,
1064 'bt_auto' => $isAuto,
1065 ];
1066 $targetLockKey = $dbw->getDomainID() . ':block:' .
1067 ( $isAuto ? 'a' : 'i' ) . ':' . $targetAddress;
1068 }
1069
1070 $condsWithCount = $targetConds;
1071 if ( $expectedTargetCount !== null ) {
1072 $condsWithCount['bt_count'] = $expectedTargetCount;
1073 }
1074
1075 $dbw->lock( $targetLockKey, __METHOD__ );
1076 $func = __METHOD__;
1077 $dbw->onTransactionCommitOrIdle(
1078 static function () use ( $dbw, $targetLockKey, $func ) {
1079 $dbw->unlock( $targetLockKey, "$func.closure" );
1080 },
1081 __METHOD__
1082 );
1083
1084 // This query locks the index gap when the target doesn't exist yet,
1085 // so there is a risk of throttling adjacent block insertions,
1086 // especially on small wikis which have larger gaps. If this proves to
1087 // be a problem, we could have getPrimaryDB() return an autocommit
1088 // connection.
1089 $dbw->newUpdateQueryBuilder()
1090 ->update( 'block_target' )
1091 ->set( [ 'bt_count' => new RawSQLValue( 'bt_count+1' ) ] )
1092 ->where( $condsWithCount )
1093 ->caller( __METHOD__ )->execute();
1094 $numUpdatedRows = $dbw->affectedRows();
1095
1096 // Now that the row is locked, find the target ID
1097 $res = $dbw->newSelectQueryBuilder()
1098 ->select( [ 'bt_id', 'bt_count' ] )
1099 ->from( 'block_target' )
1100 ->where( $targetConds )
1101 ->forUpdate()
1102 ->caller( __METHOD__ )
1103 ->fetchResultSet();
1104 if ( $res->numRows() > 1 ) {
1105 $ids = [];
1106 foreach ( $res as $row ) {
1107 $ids[] = $row->bt_id;
1108 }
1109 throw new RuntimeException( "Duplicate block_target rows detected: " .
1110 implode( ',', $ids ) );
1111 }
1112 $row = $res->fetchObject();
1113
1114 if ( $row ) {
1115 $count = (int)$row->bt_count;
1116 if ( !$numUpdatedRows ) {
1117 // ID found but count update failed -- must be a conflict due to bt_count mismatch
1118 return [ null, $count ];
1119 }
1120 $id = (int)$row->bt_id;
1121 } else {
1122 if ( $numUpdatedRows ) {
1123 throw new RuntimeException(
1124 'block_target row unexpectedly missing after we locked it' );
1125 }
1126 if ( $expectedTargetCount !== 0 && $expectedTargetCount !== null ) {
1127 // Conflict (expectation failure)
1128 return [ null, 0 ];
1129 }
1130
1131 // Insert new row
1132 $targetRow = [
1133 'bt_address' => $targetAddress,
1134 'bt_user' => $targetUserId,
1135 'bt_user_text' => $targetUserName,
1136 'bt_auto' => $isAuto,
1137 'bt_range_start' => $block->getRangeStart(),
1138 'bt_range_end' => $block->getRangeEnd(),
1139 'bt_ip_hex' => $block->getIpHex(),
1140 'bt_count' => 1
1141 ];
1142 $dbw->newInsertQueryBuilder()
1143 ->insertInto( 'block_target' )
1144 ->row( $targetRow )
1145 ->caller( __METHOD__ )->execute();
1146 $id = $dbw->insertId();
1147 if ( !$id ) {
1148 throw new RuntimeException(
1149 'block_target insert ID is falsey despite unconditional insert' );
1150 }
1151 $count = 1;
1152 }
1153
1154 return [ $id, $count ];
1155 }
1156
1168 public function updateBlock( DatabaseBlock $block ) {
1169 $this->logger->debug( 'Updating block; timestamp ' . $block->getTimestamp() );
1170
1171 $block->assertWiki( $this->wikiId );
1172
1173 $blockId = $block->getId( $this->wikiId );
1174 if ( !$blockId ) {
1175 throw new InvalidArgumentException(
1176 __METHOD__ . ' requires that a block id be set'
1177 );
1178 }
1179
1180 // Update bl_timestamp to current when making any updates to a block (T389275)
1181 $block->setTimestamp( wfTimestamp() );
1182
1183 $dbw = $this->getPrimaryDB();
1184
1185 $dbw->startAtomic( __METHOD__ );
1186
1187 $row = $this->getArrayForBlockUpdate( $block, $dbw );
1188 $dbw->newUpdateQueryBuilder()
1189 ->update( 'block' )
1190 ->set( $row )
1191 ->where( [ 'bl_id' => $blockId ] )
1192 ->caller( __METHOD__ )->execute();
1193
1194 // Only update the restrictions if they have been modified.
1195 $result = true;
1196 $restrictions = $block->getRawRestrictions();
1197 if ( $restrictions !== null ) {
1198 // An empty array should remove all of the restrictions.
1199 if ( $restrictions === [] ) {
1200 $result = $this->blockRestrictionStore->deleteByBlockId( $blockId );
1201 } else {
1202 $result = $this->blockRestrictionStore->update( $restrictions );
1203 }
1204 }
1205
1206 if ( $block->isAutoblocking() ) {
1207 // Update corresponding autoblock(s) (T50813)
1208 $dbw->newUpdateQueryBuilder()
1209 ->update( 'block' )
1210 ->set( $this->getArrayForAutoblockUpdate( $block ) )
1211 ->where( [ 'bl_parent_block_id' => $blockId ] )
1212 ->caller( __METHOD__ )->execute();
1213
1214 // Only update the restrictions if they have been modified.
1215 if ( $restrictions !== null ) {
1216 $this->blockRestrictionStore->updateByParentBlockId(
1217 $blockId,
1218 $restrictions
1219 );
1220 }
1221 } else {
1222 // Autoblock no longer required, delete corresponding autoblock(s)
1223 $this->deleteBlocksMatchingConds( [ 'bl_parent_block_id' => $blockId ] );
1224 }
1225
1226 $dbw->endAtomic( __METHOD__ );
1227
1228 if ( $result ) {
1229 $autoBlockIds = $this->doRetroactiveAutoblock( $block );
1230 return [ 'id' => $blockId, 'autoIds' => $autoBlockIds ];
1231 }
1232
1233 return false;
1234 }
1235
1249 public function updateTarget( DatabaseBlock $block, $newTarget ) {
1250 $dbw = $this->getPrimaryDB();
1251 $blockId = $block->getId( $this->wikiId );
1252 if ( !$blockId ) {
1253 throw new InvalidArgumentException(
1254 __METHOD__ . " requires that a block id be set\n"
1255 );
1256 }
1257 if ( !( $newTarget instanceof BlockTarget ) ) {
1258 $newTarget = $this->blockTargetFactory->newFromLegacyUnion( $newTarget );
1259 }
1260
1261 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1262 $oldTargetConds = $this->getTargetConds( $block->getTarget() );
1263 $block->setTarget( $newTarget );
1264
1265 $dbw->startAtomic( __METHOD__ );
1266 [ $targetId, $count ] = $this->acquireTarget( $block, $dbw, null );
1267 if ( !$targetId ) {
1268 // This is an exotic and unlikely error -- perhaps an exception should be thrown
1269 $dbw->endAtomic( __METHOD__ );
1270 return false;
1271 }
1272 $oldTargetId = $dbw->newSelectQueryBuilder()
1273 ->select( 'bt_id' )
1274 ->from( 'block_target' )
1275 ->where( $oldTargetConds )
1276 ->caller( __METHOD__ )->fetchField();
1277 $this->releaseTargets( $dbw, [ $oldTargetId ] );
1278
1279 $dbw->newUpdateQueryBuilder()
1280 ->update( 'block' )
1281 ->set( [ 'bl_target' => $targetId ] )
1282 ->where( [ 'bl_id' => $blockId ] )
1283 ->caller( __METHOD__ )
1284 ->execute();
1285 $affected = $dbw->affectedRows();
1286 $dbw->endAtomic( __METHOD__ );
1287 return (bool)$affected;
1288 }
1289
1296 public function deleteBlock( DatabaseBlock $block ): bool {
1297 if ( $this->readOnlyMode->isReadOnly( $this->wikiId ) ) {
1298 return false;
1299 }
1300
1301 $block->assertWiki( $this->wikiId );
1302
1303 $blockId = $block->getId( $this->wikiId );
1304
1305 if ( !$blockId ) {
1306 throw new InvalidArgumentException(
1307 __METHOD__ . ' requires that a block id be set'
1308 );
1309 }
1310 $dbw = $this->getPrimaryDB();
1311 $dbw->startAtomic( __METHOD__ );
1312 $res = $dbw->newSelectQueryBuilder()
1313 ->select( [ 'bl_id', 'bl_target' ] )
1314 ->from( 'block' )
1315 ->where(
1316 $dbw->orExpr( [
1317 'bl_parent_block_id' => $blockId,
1318 'bl_id' => $blockId,
1319 ] )
1320 )
1321 ->caller( __METHOD__ )->fetchResultSet();
1322 $this->deleteBlockRows( $res );
1323 $affected = $res->numRows();
1324 $dbw->endAtomic( __METHOD__ );
1325
1326 return $affected > 0;
1327 }
1328
1337 private function getArrayForBlockUpdate(
1338 DatabaseBlock $block,
1339 IDatabase $dbw
1340 ): array {
1341 $expiry = $dbw->encodeExpiry( $block->getExpiry() );
1342
1343 $blocker = $block->getBlocker();
1344 if ( !$blocker ) {
1345 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1346 }
1347 // DatabaseBlockStore supports inserting cross-wiki blocks by passing
1348 // non-local IDatabase and blocker.
1349 $blockerActor = $this->actorStoreFactory
1350 ->getActorStore( $dbw->getDomainID() )
1351 ->acquireActorId( $blocker, $dbw );
1352
1353 $blockArray = [
1354 'bl_by_actor' => $blockerActor,
1355 'bl_timestamp' => $dbw->timestamp( $block->getTimestamp() ),
1356 'bl_anon_only' => !$block->isHardblock(),
1357 'bl_create_account' => $block->isCreateAccountBlocked(),
1358 'bl_enable_autoblock' => $block->isAutoblocking(),
1359 'bl_expiry' => $expiry,
1360 'bl_deleted' => intval( $block->getHideName() ), // typecast required for SQLite
1361 'bl_block_email' => $block->isEmailBlocked(),
1362 'bl_allow_usertalk' => $block->isUsertalkEditAllowed(),
1363 'bl_parent_block_id' => $block->getParentBlockId(),
1364 'bl_sitewide' => $block->isSitewide(),
1365 ];
1366 $commentArray = $this->commentStore->insert(
1367 $dbw,
1368 'bl_reason',
1369 $block->getReasonComment()
1370 );
1371
1372 $combinedArray = $blockArray + $commentArray;
1373 return $combinedArray;
1374 }
1375
1382 private function getArrayForAutoblockUpdate( DatabaseBlock $block ): array {
1383 $blocker = $block->getBlocker();
1384 if ( !$blocker ) {
1385 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1386 }
1387 $dbw = $this->getPrimaryDB();
1388 $blockerActor = $this->actorStoreFactory
1389 ->getActorNormalization( $this->wikiId )
1390 ->acquireActorId( $blocker, $dbw );
1391
1392 $blockArray = [
1393 'bl_by_actor' => $blockerActor,
1394 'bl_create_account' => $block->isCreateAccountBlocked(),
1395 'bl_deleted' => (int)$block->getHideName(), // typecast required for SQLite
1396 'bl_allow_usertalk' => $block->isUsertalkEditAllowed(),
1397 'bl_sitewide' => $block->isSitewide(),
1398 ];
1399
1400 // Shorten the autoblock expiry if the parent block expiry is sooner.
1401 // Don't lengthen -- that is only done when the IP address is actually
1402 // used by the blocked user.
1403 if ( $block->getExpiry() !== 'infinity' ) {
1404 $blockArray['bl_expiry'] = new RawSQLValue( $dbw->conditional(
1405 $dbw->expr( 'bl_expiry', '>', $dbw->timestamp( $block->getExpiry() ) ),
1406 $dbw->addQuotes( $dbw->timestamp( $block->getExpiry() ) ),
1407 'bl_expiry'
1408 ) );
1409 }
1410
1411 $commentArray = $this->commentStore->insert(
1412 $dbw,
1413 'bl_reason',
1414 $this->getAutoblockReason( $block )
1415 );
1416
1417 $combinedArray = $blockArray + $commentArray;
1418 return $combinedArray;
1419 }
1420
1428 private function doRetroactiveAutoblock( DatabaseBlock $block ): array {
1429 $autoBlockIds = [];
1430 // If autoblock is enabled, autoblock the LAST IP(s) used
1431 if ( $block->isAutoblocking() && $block->getType() == AbstractBlock::TYPE_USER ) {
1432 $this->logger->debug(
1433 'Doing retroactive autoblocks for ' . $block->getTargetName()
1434 );
1435
1436 $hookAutoBlocked = [];
1437 $continue = $this->hookRunner->onPerformRetroactiveAutoblock(
1438 $block,
1439 $hookAutoBlocked
1440 );
1441
1442 if ( $continue ) {
1443 $coreAutoBlocked = $this->performRetroactiveAutoblock( $block );
1444 $autoBlockIds = array_merge( $hookAutoBlocked, $coreAutoBlocked );
1445 } else {
1446 $autoBlockIds = $hookAutoBlocked;
1447 }
1448 }
1449 return $autoBlockIds;
1450 }
1451
1459 private function performRetroactiveAutoblock( DatabaseBlock $block ): array {
1460 if ( !$this->options->get( MainConfigNames::PutIPinRC ) ) {
1461 // No IPs in the recent changes table to autoblock
1462 return [];
1463 }
1464
1465 $target = $block->getTarget();
1466 if ( !( $target instanceof UserBlockTarget ) ) {
1467 // Autoblocks only apply to users
1468 return [];
1469 }
1470
1471 $dbr = $this->getReplicaDB();
1472
1473 $actor = $this->actorStoreFactory
1474 ->getActorNormalization( $this->wikiId )
1475 ->findActorId( $target->getUserIdentity(), $dbr );
1476
1477 if ( !$actor ) {
1478 $this->logger->debug( 'No actor found to retroactively autoblock' );
1479 return [];
1480 }
1481
1482 $rcIp = $dbr->newSelectQueryBuilder()
1483 ->select( 'rc_ip' )
1484 ->from( 'recentchanges' )
1485 ->where( [ 'rc_actor' => $actor ] )
1486 ->orderBy( 'rc_timestamp', SelectQueryBuilder::SORT_DESC )
1487 ->caller( __METHOD__ )->fetchField();
1488
1489 if ( !$rcIp ) {
1490 $this->logger->debug( 'No IP found to retroactively autoblock' );
1491 return [];
1492 }
1493
1494 $id = $this->doAutoblock( $block, $rcIp );
1495 if ( !$id ) {
1496 return [];
1497 }
1498 return [ $id ];
1499 }
1500
1509 public function doAutoblock( DatabaseBlock $parentBlock, $autoblockIP ) {
1510 // If autoblocks are disabled, go away.
1511 if ( !$parentBlock->isAutoblocking() ) {
1512 return false;
1513 }
1514 $parentBlock->assertWiki( $this->wikiId );
1515
1516 $target = $this->blockTargetFactory->newFromIp( $autoblockIP );
1517 if ( !$target ) {
1518 $this->logger->debug( "Invalid autoblock IP" );
1519 return false;
1520 }
1521
1522 // Check if autoblock exempt.
1523 if ( $this->autoblockExemptionList->isExempt( $autoblockIP ) ) {
1524 return false;
1525 }
1526
1527 // Allow hooks to cancel the autoblock.
1528 if ( !$this->hookRunner->onAbortAutoblock( $autoblockIP, $parentBlock ) ) {
1529 $this->logger->debug( "Autoblock aborted by hook." );
1530 return false;
1531 }
1532
1533 // It's okay to autoblock. Go ahead and insert/update the block...
1534
1535 // Do not add a *new* block if the IP is already blocked.
1536 $blocks = $this->newLoad( $target, false );
1537 if ( $blocks ) {
1538 foreach ( $blocks as $ipblock ) {
1539 // Check if the block is an autoblock and would exceed the user block
1540 // if renewed. If so, do nothing, otherwise prolong the block time...
1541 if ( $ipblock->getType() === Block::TYPE_AUTO
1542 && $parentBlock->getExpiry() > $ipblock->getExpiry()
1543 ) {
1544 // Reset block timestamp to now and its expiry to
1545 // $wgAutoblockExpiry in the future
1546 $this->updateTimestamp( $ipblock );
1547 }
1548 }
1549 return false;
1550 }
1551 $blocker = $parentBlock->getBlocker();
1552 if ( !$blocker ) {
1553 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1554 }
1555
1556 // Acquire a lock on the primary DB for the autoblock to prevent race conditions (T260838)
1557 $dbw = $this->getPrimaryDB();
1558 $autoblockTargetLockKey = $dbw->getDomainID() . ':autoblock:' . $target;
1559 if ( !$dbw->lock( $autoblockTargetLockKey, __METHOD__, 0 ) ) {
1560 return false;
1561 }
1562
1563 $timestamp = wfTimestampNow();
1564 $expiry = $this->getAutoblockExpiry( $timestamp, $parentBlock->getExpiry() );
1565 $autoblock = new DatabaseBlock( [
1566 'wiki' => $this->wikiId,
1567 'target' => $target,
1568 'by' => $blocker,
1569 'reason' => $this->getAutoblockReason( $parentBlock ),
1570 'decodedTimestamp' => $timestamp,
1571 'auto' => true,
1572 'createAccount' => $parentBlock->isCreateAccountBlocked(),
1573 // Continue suppressing the name if needed
1574 'hideName' => $parentBlock->getHideName(),
1575 'allowUsertalk' => $parentBlock->isUsertalkEditAllowed(),
1576 'parentBlockId' => $parentBlock->getId( $this->wikiId ),
1577 'sitewide' => $parentBlock->isSitewide(),
1578 'restrictions' => $parentBlock->getRestrictions(),
1579 'decodedExpiry' => $expiry,
1580 ] );
1581
1582 $this->logger->debug( "Autoblocking {$parentBlock->getTargetName()}@" . $target );
1583
1584 $status = $this->insertBlock( $autoblock );
1585
1586 $dbw->unlock( $autoblockTargetLockKey, __METHOD__ );
1587
1588 return $status
1589 ? $status['id']
1590 : false;
1591 }
1592
1593 private function getAutoblockReason( DatabaseBlock $parentBlock ): string {
1595 'autoblocker',
1596 $parentBlock->getTargetName(),
1597 $parentBlock->getReasonComment()->text
1598 )->inContentLanguage()->plain();
1599 }
1600
1607 public function updateTimestamp( DatabaseBlock $block ) {
1608 $block->assertWiki( $this->wikiId );
1609 if ( $block->getType() !== Block::TYPE_AUTO ) {
1610 return;
1611 }
1612 $now = wfTimestamp();
1613 $block->setTimestamp( $now );
1614 // No need to reduce the autoblock expiry to the expiry of the parent
1615 // block, since the caller already checked for that.
1616 $block->setExpiry( $this->getAutoblockExpiry( $now ) );
1617
1618 $dbw = $this->getPrimaryDB();
1619 $dbw->newUpdateQueryBuilder()
1620 ->update( 'block' )
1621 ->set(
1622 [
1623 'bl_timestamp' => $dbw->timestamp( $block->getTimestamp() ),
1624 'bl_expiry' => $dbw->timestamp( $block->getExpiry() ),
1625 ]
1626 )
1627 ->where( [ 'bl_id' => $block->getId( $this->wikiId ) ] )
1628 ->caller( __METHOD__ )->execute();
1629 }
1630
1642 public function getAutoblockExpiry( $timestamp, ?string $parentExpiry = null ) {
1643 $maxDuration = $this->options->get( MainConfigNames::AutoblockExpiry );
1644 $expiry = wfTimestamp( TS::MW, (int)wfTimestamp( TS::UNIX, $timestamp ) + $maxDuration );
1645 if ( $parentExpiry !== null && $parentExpiry !== 'infinity' ) {
1646 $expiry = min( $parentExpiry, $expiry );
1647 }
1648 return $expiry;
1649 }
1650
1651 // endregion -- end of database write methods
1652
1653}
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:68
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.
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.
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.
__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, string|false $wikiId=DatabaseBlock::LOCAL)
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, 'UploadMaintenance'=> false, 'IllegalFileChars'=> ':\\/\\\\', 'DeletedDirectory'=> false, 'ImgAuthDetails'=> false, 'ImgAuthUrlPathMap'=>[], 'LocalFileRepo'=>['class'=> 'MediaWiki\\FileRepo\\LocalRepo', 'name'=> 'local', 'directory'=> null, 'scriptDirUrl'=> null, 'favicon'=> null, 'url'=> null, 'hashLevels'=> null, 'thumbScriptUrl'=> null, 'transformVia404'=> null, 'deletedDir'=> null, 'deletedHashLevels'=> null, 'updateCompatibleMetadata'=> null, 'reserializeMetadata'=> null,], 'ForeignFileRepos'=>[], 'UseInstantCommons'=> false, 'UseSharedUploads'=> false, 'SharedUploadDirectory'=> null, 'SharedUploadPath'=> null, 'HashedSharedUploadDirectory'=> true, 'RepositoryBaseUrl'=> 'https:'FetchCommonsDescriptions'=> false, 'SharedUploadDBname'=> false, 'SharedUploadDBprefix'=> '', 'CacheSharedUploads'=> true, 'ForeignUploadTargets'=>['local',], 'UploadDialog'=>['fields'=>['description'=> true, 'date'=> false, 'categories'=> false,], 'licensemessages'=>['local'=> 'generic-local', 'foreign'=> 'generic-foreign',], 'comment'=>['local'=> '', 'foreign'=> '',], 'format'=>['filepage'=> ' $DESCRIPTION', 'description'=> ' $TEXT', 'ownwork'=> '', 'license'=> '', 'uncategorized'=> '',],], 'FileBackends'=>[], 'LockManagers'=>[], 'ShowEXIF'=> null, 'UpdateCompatibleMetadata'=> false, 'AllowCopyUploads'=> false, 'CopyUploadsDomains'=>[], 'CopyUploadsFromSpecialUpload'=> false, 'CopyUploadProxy'=> false, 'CopyUploadTimeout'=> false, 'CopyUploadAllowOnWikiDomainConfig'=> false, 'MaxUploadSize'=> 104857600, 'MinUploadChunkSize'=> 1024, 'UploadNavigationUrl'=> false, 'UploadMissingFileUrl'=> false, 'ThumbnailScriptPath'=> false, 'SharedThumbnailScriptPath'=> false, 'HashedUploadDirectory'=> true, 'CSPUploadEntryPoint'=> true, 'FileExtensions'=>['png', 'gif', 'jpg', 'jpeg', 'webp',], 'ProhibitedFileExtensions'=>['html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht', 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar', 'shtml', 'jhtml', 'pl', 'py', 'cgi', 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl', 'xml',], 'MimeTypeExclusions'=>['text/html', 'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile', 'application/java', 'application/xml', 'text/xml',], 'CheckFileExtensions'=> true, 'StrictFileExtensions'=> true, 'DisableUploadScriptChecks'=> false, 'UploadSizeWarning'=> false, 'TrustedMediaFormats'=>['BITMAP', 'AUDIO', 'VIDEO', 'image/svg+xml', 'application/pdf',], 'MediaHandlers'=>[], 'NativeImageLazyLoading'=> false, 'ParserTestMediaHandlers'=>['image/jpeg'=> 'MockBitmapHandler', 'image/png'=> 'MockBitmapHandler', 'image/gif'=> 'MockBitmapHandler', 'image/tiff'=> 'MockBitmapHandler', 'image/webp'=> 'MockBitmapHandler', 'image/x-ms-bmp'=> 'MockBitmapHandler', 'image/x-bmp'=> 'MockBitmapHandler', 'image/x-xcf'=> 'MockBitmapHandler', 'image/svg+xml'=> 'MockSvgHandler', 'image/vnd.djvu'=> 'MockDjVuHandler',], 'UseImageResize'=> true, 'UseImageMagick'=> false, 'ImageMagickConvertCommand'=> '/usr/bin/convert', 'MaxInterlacingAreas'=>[], 'SharpenParameter'=> '0x0.4', 'SharpenReductionThreshold'=> 0.85, 'ImageMagickTempDir'=> false, 'CustomConvertCommand'=> false, 'JpegTran'=> '/usr/bin/jpegtran', 'JpegPixelFormat'=> 'yuv420', 'JpegQuality'=> 80, 'Exiv2Command'=> '/usr/bin/exiv2', 'Exiftool'=> '/usr/bin/exiftool', 'SVGConverters'=>['ImageMagick'=> ' $path/convert -background "#ffffff00" -thumbnail $widthx$height\\! $input PNG:$output', 'inkscape'=> ' $path/inkscape -w $width -o $output $input', 'batik'=> 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg'=> ' $path/rsvg-convert -w $width -h $height -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> false, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 250, 300,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailStepsRatio'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'EnableSpecialMute'=> false, 'EnableUserEmailMuteList'=> false, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'UserEmailConfirmationUseHTML'=> false, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ImageLinksSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'UseLegacyMediaStyles' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCEngines' => [ 'redis' => 'MediaWiki\\RCFeed\\RedisPubSubFeedEngine', 'udp' => 'MediaWiki\\RCFeed\\UDPRCFeedEngine', ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCache' => false, 'ParserOptionsLogUnsafeSampleRate' => 0, ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailStepsRatio' => [ 'number', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'UserEmailConfirmationUseHTML' => 'boolean', 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ImageLinksSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'RCEngines' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCache' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], 'required' => [ 'url', ], ], ], '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.
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...