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' => (int)$row->bl_deleted === 1,
438 'hideBlock' => (bool)$row->bl_deleted,
439 'id' => (int)$row->bl_id,
440 // Blocks with no parent ID should have bl_parent_block_id as null,
441 // don't save that as 0 though, see T282890
442 'parentBlockId' => $row->bl_parent_block_id
443 ? (int)$row->bl_parent_block_id : null,
444 'by' => $this->actorStoreFactory
445 ->getActorStore( $this->wikiId )
446 ->newActorFromRowFields( $row->bl_by, $row->bl_by_text, $row->bl_by_actor ),
447 'decodedExpiry' => $db->decodeExpiry( $row->bl_expiry ),
448 'reason' => $this->commentStore->getComment( 'bl_reason', $row ),
449 'anonOnly' => $row->bl_anon_only,
450 'enableAutoblock' => (bool)$row->bl_enable_autoblock,
451 'sitewide' => (bool)$row->bl_sitewide,
452 'createAccount' => (bool)$row->bl_create_account,
453 'blockEmail' => (bool)$row->bl_block_email,
454 'allowUsertalk' => (bool)$row->bl_allow_usertalk
455 ] );
456 }
457
487 public function newFromTarget(
488 $specificTarget,
489 $vagueTarget = null,
490 $fromPrimary = false,
491 $auto = self::AUTO_ALL
492 ) {
493 $blocks = $this->newListFromTarget( $specificTarget, $vagueTarget, $fromPrimary, $auto );
494 return $this->chooseMostSpecificBlock( $blocks );
495 }
496
510 public function newListFromTarget(
511 $specificTarget,
512 $vagueTarget = null,
513 $fromPrimary = false,
514 $auto = self::AUTO_ALL
515 ) {
516 if ( !( $specificTarget instanceof BlockTarget ) ) {
517 $specificTarget = $this->blockTargetFactory->newFromLegacyUnion( $specificTarget );
518 }
519 if ( $vagueTarget !== null && !( $vagueTarget instanceof BlockTarget ) ) {
520 $vagueTarget = $this->blockTargetFactory->newFromLegacyUnion( $vagueTarget );
521 }
522 if ( $specificTarget instanceof AutoBlockTarget ) {
523 if ( $auto === self::AUTO_NONE ) {
524 return [];
525 }
526 $block = $this->newFromID( $specificTarget->getId() );
527 return $block ? [ $block ] : [];
528 } elseif ( $specificTarget === null && $vagueTarget === null ) {
529 // We're not going to find anything useful here
530 return [];
531 } else {
532 return $this->newLoad( $specificTarget, $fromPrimary, $vagueTarget, $auto );
533 }
534 }
535
546 public function newListFromIPs( array $addresses, $applySoftBlocks, $fromPrimary = false ) {
547 $addresses = array_unique( $addresses );
548 if ( $addresses === [] ) {
549 return [];
550 }
551
552 $ranges = [];
553 foreach ( $addresses as $ipaddr ) {
554 $ranges[] = [ IPUtils::toHex( $ipaddr ), null ];
555 }
556 $rangeConds = $this->getConditionForRanges( $ranges );
557
558 if ( $fromPrimary ) {
559 $db = $this->getPrimaryDB();
560 } else {
561 $db = $this->getReplicaDB();
562 }
563 $conds = $db->makeList( $rangeConds, LIST_OR );
564 if ( !$applySoftBlocks ) {
565 $conds = [ $conds, 'bl_anon_only' => 0 ];
566 }
567 $blockQuery = $this->getQueryInfo();
568 $rows = $db->newSelectQueryBuilder()
569 ->queryInfo( $blockQuery )
570 ->fields( [ 'bt_range_start', 'bt_range_end' ] )
571 ->where( $conds )
572 ->caller( __METHOD__ )
573 ->fetchResultSet();
574
575 $blocks = [];
576 foreach ( $rows as $row ) {
577 $block = $this->newFromRow( $db, $row );
578 if ( !$block->isExpired() ) {
579 $blocks[] = $block;
580 }
581 }
582
583 return $blocks;
584 }
585
596 public function newListFromConds( $conds, $fromPrimary = false, $includeExpired = false ) {
597 $db = $fromPrimary ? $this->getPrimaryDB() : $this->getReplicaDB();
598 $conds = self::mapActorAlias( $conds );
599 if ( !$includeExpired ) {
600 $conds[] = $db->expr( 'bl_expiry', '>=', $db->timestamp() );
601 }
602 $res = $db->newSelectQueryBuilder()
603 ->queryInfo( $this->getQueryInfo() )
604 ->conds( $conds )
605 ->caller( __METHOD__ )
606 ->fetchResultSet();
607 $blocks = [];
608 foreach ( $res as $row ) {
609 $blocks[] = $this->newFromRow( $db, $row );
610 }
611 return $blocks;
612 }
613
614 // endregion -- end of database read methods
615
616 /***************************************************************************/
617 // region Database write methods
633 public function newUnsaved( array $options ): DatabaseBlock {
634 if ( isset( $options['targetUser'] ) ) {
635 $options['target'] = $this->blockTargetFactory
636 ->newFromUser( $options['targetUser'] );
637 unset( $options['targetUser'] );
638 }
639 if ( isset( $options['address'] ) ) {
640 $target = $this->blockTargetFactory
641 ->newFromString( $options['address'] );
642 if ( !$target ) {
643 throw new InvalidArgumentException( 'Invalid target address' );
644 }
645 $options['target'] = $target;
646 unset( $options['address'] );
647 }
648 return new DatabaseBlock( $options );
649 }
650
656 public function purgeExpiredBlocks() {
657 if ( $this->readOnlyMode->isReadOnly( $this->wikiId ) ) {
658 return;
659 }
660
661 $dbw = $this->getPrimaryDB();
662
663 DeferredUpdates::addUpdate( new AutoCommitUpdate(
664 $dbw,
665 __METHOD__,
666 function ( IDatabase $dbw, $fname ) {
667 $limit = $this->options->get( MainConfigNames::UpdateRowsPerQuery );
668 $res = $dbw->newSelectQueryBuilder()
669 ->select( [ 'bl_id', 'bl_target' ] )
670 ->from( 'block' )
671 ->where( $dbw->expr( 'bl_expiry', '<', $dbw->timestamp() ) )
672 // Set a limit to avoid causing replication lag (T301742)
673 ->limit( $limit )
674 ->caller( $fname )->fetchResultSet();
675 $this->deleteBlockRows( $res );
676 }
677 ) );
678 }
679
689 public function deleteBlocksMatchingConds( array $conds, $limit = null ) {
690 $dbw = $this->getPrimaryDB();
691 $conds = self::mapActorAlias( $conds );
692 $qb = $dbw->newSelectQueryBuilder()
693 ->select( [ 'bl_id', 'bl_target' ] )
694 ->from( 'block' )
695 // Typical input conds need block_target
696 ->join( 'block_target', null, 'bt_id=bl_target' )
697 ->where( $conds )
698 ->caller( __METHOD__ );
699 if ( self::hasActorAlias( $conds ) ) {
700 $qb->join( 'actor', 'ipblocks_actor', 'actor_id=bl_by_actor' );
701 }
702 if ( $limit !== null ) {
703 $qb->limit( $limit );
704 }
705 $res = $qb->fetchResultSet();
706 return $this->deleteBlockRows( $res );
707 }
708
715 private static function mapActorAlias( $conds ) {
716 return self::mapConds(
717 [
718 'bl_by' => 'ipblocks_actor.actor_user',
719 ],
720 $conds
721 );
722 }
723
728 private static function hasActorAlias( $conds ) {
729 return array_key_exists( 'ipblocks_actor.actor_user', $conds )
730 || array_key_exists( 'ipblocks_actor.actor_name', $conds );
731 }
732
740 private static function mapConds( $map, $conds ) {
741 $newConds = [];
742 foreach ( $conds as $field => $value ) {
743 if ( isset( $map[$field] ) ) {
744 $newConds[$map[$field]] = $value;
745 } else {
746 $newConds[$field] = $value;
747 }
748 }
749 return $newConds;
750 }
751
759 private function deleteBlockRows( $rows ) {
760 $ids = [];
761 $deltasByTarget = [];
762 foreach ( $rows as $row ) {
763 $ids[] = (int)$row->bl_id;
764 $target = (int)$row->bl_target;
765 if ( !isset( $deltasByTarget[$target] ) ) {
766 $deltasByTarget[$target] = 0;
767 }
768 $deltasByTarget[$target]++;
769 }
770 if ( !$ids ) {
771 return 0;
772 }
773 $dbw = $this->getPrimaryDB();
774 $dbw->startAtomic( __METHOD__ );
775
776 $maxTargetCount = max( $deltasByTarget );
777 for ( $delta = 1; $delta <= $maxTargetCount; $delta++ ) {
778 $targetsWithThisDelta = array_keys( $deltasByTarget, $delta, true );
779 if ( $targetsWithThisDelta ) {
780 $this->releaseTargets( $dbw, $targetsWithThisDelta, $delta );
781 }
782 }
783
784 $dbw->newDeleteQueryBuilder()
785 ->deleteFrom( 'block' )
786 ->where( [ 'bl_id' => $ids ] )
787 ->caller( __METHOD__ )->execute();
788 $numDeleted = $dbw->affectedRows();
789 $dbw->endAtomic( __METHOD__ );
790 $this->blockRestrictionStore->deleteByBlockId( $ids );
791 return $numDeleted;
792 }
793
802 private function releaseTargets( IDatabase $dbw, $targetIds, int $delta = 1 ) {
803 if ( !$targetIds ) {
804 return;
805 }
806 $dbw->newUpdateQueryBuilder()
807 ->update( 'block_target' )
808 ->set( [ 'bt_count' => new RawSQLValue( "bt_count-$delta" ) ] )
809 ->where( [ 'bt_id' => $targetIds ] )
810 ->caller( __METHOD__ )
811 ->execute();
812 $dbw->newDeleteQueryBuilder()
813 ->deleteFrom( 'block_target' )
814 ->where( [
815 'bt_count<1',
816 'bt_id' => $targetIds
817 ] )
818 ->caller( __METHOD__ )
819 ->execute();
820 }
821
822 private function getReplicaDB(): IReadableDatabase {
823 return $this->dbProvider->getReplicaDatabase( $this->wikiId );
824 }
825
826 private function getPrimaryDB(): IDatabase {
827 return $this->dbProvider->getPrimaryDatabase( $this->wikiId );
828 }
829
843 public function insertBlock(
844 DatabaseBlock $block,
845 $expectedTargetCount = 0
846 ) {
847 $block->assertWiki( $this->wikiId );
848
849 $blocker = $block->getBlocker();
850 if ( !$blocker || $blocker->getName() === '' ) {
851 throw new InvalidArgumentException( 'Cannot insert a block without a blocker set' );
852 }
853
854 if ( $expectedTargetCount instanceof IDatabase ) {
855 throw new InvalidArgumentException(
856 'Old method signature: Passing a custom database connection to '
857 . 'DatabaseBlockStore::insertBlock is no longer supported'
858 );
859 }
860
861 $this->logger->debug( 'Inserting block; timestamp ' . $block->getTimestamp() );
862
863 // Purge expired blocks. This now just queues a deferred update, so it
864 // is possible for expired blocks to conflict with inserted blocks below.
865 $this->purgeExpiredBlocks();
866
867 $dbw = $this->getPrimaryDB();
868 $dbw->startAtomic( __METHOD__ );
869 $finalTargetCount = $this->attemptInsert( $block, $dbw, $expectedTargetCount );
870 $purgeDone = false;
871
872 // Don't collide with expired blocks.
873 // Do this after trying to insert to avoid locking.
874 if ( !$finalTargetCount ) {
875 if ( $this->purgeExpiredConflicts( $block, $dbw ) ) {
876 $finalTargetCount = $this->attemptInsert( $block, $dbw, $expectedTargetCount );
877 $purgeDone = true;
878 }
879 }
880 $dbw->endAtomic( __METHOD__ );
881
882 if ( $finalTargetCount > 1 && !$purgeDone ) {
883 // Subtract expired blocks from the target count
884 $expiredBlockCount = $this->getExpiredConflictingBlockRows( $block, $dbw )->count();
885 if ( $expiredBlockCount >= $finalTargetCount ) {
886 $finalTargetCount = 1;
887 } else {
888 $finalTargetCount -= $expiredBlockCount;
889 }
890 }
891
892 if ( $finalTargetCount ) {
893 $autoBlockIds = $this->doRetroactiveAutoblock( $block );
894
895 if ( $this->options->get( MainConfigNames::BlockDisablesLogin ) ) {
896 $targetUserIdentity = $block->getTargetUserIdentity();
897 if ( $targetUserIdentity ) {
898 $targetUser = $this->userFactory->newFromUserIdentity( $targetUserIdentity );
899 $this->sessionManager->invalidateSessionsForUser( $targetUser );
900 }
901 }
902
903 return [
904 'id' => $block->getId( $this->wikiId ),
905 'autoIds' => $autoBlockIds,
906 'finalTargetCount' => $finalTargetCount
907 ];
908 }
909
910 return false;
911 }
912
924 public function insertBlockWithParams( array $params ): DatabaseBlock {
925 $block = $this->newUnsaved( $params );
926 $status = $this->insertBlock( $block, $params['expectedTargetCount'] ?? null );
927 if ( !$status ) {
928 throw new RuntimeException( 'Failed to insert block' );
929 }
930 return $block;
931 }
932
942 private function attemptInsert(
943 DatabaseBlock $block,
944 IDatabase $dbw,
945 $expectedTargetCount
946 ) {
947 [ $targetId, $finalCount ] = $this->acquireTarget( $block, $dbw, $expectedTargetCount );
948 if ( !$targetId ) {
949 return false;
950 }
951 $row = $this->getArrayForBlockUpdate( $block, $dbw );
952 $row['bl_target'] = $targetId;
953 $dbw->newInsertQueryBuilder()
954 ->insertInto( 'block' )
955 ->row( $row )
956 ->caller( __METHOD__ )->execute();
957 if ( !$dbw->affectedRows() ) {
958 return false;
959 }
960 $id = $dbw->insertId();
961
962 if ( !$id ) {
963 throw new RuntimeException( 'block insert ID is falsey' );
964 }
965 $block->setId( $id );
966 $restrictions = $block->getRawRestrictions();
967 if ( $restrictions ) {
968 $this->blockRestrictionStore->insert( $restrictions );
969 }
970
971 return $finalCount;
972 }
973
981 private function purgeExpiredConflicts(
982 DatabaseBlock $block,
983 IDatabase $dbw
984 ) {
985 return (bool)$this->deleteBlockRows(
986 $this->getExpiredConflictingBlockRows( $block, $dbw )
987 );
988 }
989
998 private function getExpiredConflictingBlockRows(
999 DatabaseBlock $block,
1000 IDatabase $dbw
1001 ) {
1002 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1003 $targetConds = $this->getTargetConds( $block->getTarget() );
1004 return $dbw->newSelectQueryBuilder()
1005 ->select( [ 'bl_id', 'bl_target' ] )
1006 ->from( 'block' )
1007 ->join( 'block_target', null, [ 'bt_id=bl_target' ] )
1008 ->where( $targetConds )
1009 ->andWhere( $dbw->expr( 'bl_expiry', '<', $dbw->timestamp() ) )
1010 ->caller( __METHOD__ )->fetchResultSet();
1011 }
1012
1019 private function getTargetConds( BlockTarget $target ) {
1020 if ( $target instanceof UserBlockTarget ) {
1021 return [
1022 'bt_user' => $target->getUserIdentity()->getId( $this->wikiId )
1023 ];
1024 } elseif ( $target instanceof AnonIpBlockTarget || $target instanceof RangeBlockTarget ) {
1025 return [ 'bt_address' => $target->toString() ];
1026 } else {
1027 throw new \InvalidArgumentException( 'Invalid target type' );
1028 }
1029 }
1030
1045 private function acquireTarget(
1046 DatabaseBlock $block,
1047 IDatabase $dbw,
1048 $expectedTargetCount
1049 ) {
1050 $target = $block->getTarget();
1051 // Note: for new autoblocks, the target is an IpBlockTarget
1052 $isAuto = $block->getType() === Block::TYPE_AUTO;
1053 if ( $target instanceof UserBlockTarget ) {
1054 $targetAddress = null;
1055 $targetUserName = (string)$target;
1056 $targetUserId = $target->getUserIdentity()->getId( $this->wikiId );
1057 $targetConds = [ 'bt_user' => $targetUserId ];
1058 $targetLockKey = $dbw->getDomainID() . ':block:u:' . $targetUserId;
1059 } else {
1060 $targetAddress = (string)$target;
1061 $targetUserName = null;
1062 $targetUserId = null;
1063 $targetConds = [
1064 'bt_address' => $targetAddress,
1065 'bt_auto' => $isAuto,
1066 ];
1067 $targetLockKey = $dbw->getDomainID() . ':block:' .
1068 ( $isAuto ? 'a' : 'i' ) . ':' . $targetAddress;
1069 }
1070
1071 $condsWithCount = $targetConds;
1072 if ( $expectedTargetCount !== null ) {
1073 $condsWithCount['bt_count'] = $expectedTargetCount;
1074 }
1075
1076 $dbw->lock( $targetLockKey, __METHOD__ );
1077 $func = __METHOD__;
1078 $dbw->onTransactionCommitOrIdle(
1079 static function () use ( $dbw, $targetLockKey, $func ) {
1080 $dbw->unlock( $targetLockKey, "$func.closure" );
1081 },
1082 __METHOD__
1083 );
1084
1085 // This query locks the index gap when the target doesn't exist yet,
1086 // so there is a risk of throttling adjacent block insertions,
1087 // especially on small wikis which have larger gaps. If this proves to
1088 // be a problem, we could have getPrimaryDB() return an autocommit
1089 // connection.
1090 $dbw->newUpdateQueryBuilder()
1091 ->update( 'block_target' )
1092 ->set( [ 'bt_count' => new RawSQLValue( 'bt_count+1' ) ] )
1093 ->where( $condsWithCount )
1094 ->caller( __METHOD__ )->execute();
1095 $numUpdatedRows = $dbw->affectedRows();
1096
1097 // Now that the row is locked, find the target ID
1098 $res = $dbw->newSelectQueryBuilder()
1099 ->select( [ 'bt_id', 'bt_count' ] )
1100 ->from( 'block_target' )
1101 ->where( $targetConds )
1102 ->forUpdate()
1103 ->caller( __METHOD__ )
1104 ->fetchResultSet();
1105 if ( $res->numRows() > 1 ) {
1106 $ids = [];
1107 foreach ( $res as $row ) {
1108 $ids[] = $row->bt_id;
1109 }
1110 throw new RuntimeException( "Duplicate block_target rows detected: " .
1111 implode( ',', $ids ) );
1112 }
1113 $row = $res->fetchObject();
1114
1115 if ( $row ) {
1116 $count = (int)$row->bt_count;
1117 if ( !$numUpdatedRows ) {
1118 // ID found but count update failed -- must be a conflict due to bt_count mismatch
1119 return [ null, $count ];
1120 }
1121 $id = (int)$row->bt_id;
1122 } else {
1123 if ( $numUpdatedRows ) {
1124 throw new RuntimeException(
1125 'block_target row unexpectedly missing after we locked it' );
1126 }
1127 if ( $expectedTargetCount !== 0 && $expectedTargetCount !== null ) {
1128 // Conflict (expectation failure)
1129 return [ null, 0 ];
1130 }
1131
1132 // Insert new row
1133 $targetRow = [
1134 'bt_address' => $targetAddress,
1135 'bt_user' => $targetUserId,
1136 'bt_user_text' => $targetUserName,
1137 'bt_auto' => $isAuto,
1138 'bt_range_start' => $block->getRangeStart(),
1139 'bt_range_end' => $block->getRangeEnd(),
1140 'bt_ip_hex' => $block->getIpHex(),
1141 'bt_count' => 1
1142 ];
1143 $dbw->newInsertQueryBuilder()
1144 ->insertInto( 'block_target' )
1145 ->row( $targetRow )
1146 ->caller( __METHOD__ )->execute();
1147 $id = $dbw->insertId();
1148 if ( !$id ) {
1149 throw new RuntimeException(
1150 'block_target insert ID is falsey despite unconditional insert' );
1151 }
1152 $count = 1;
1153 }
1154
1155 return [ $id, $count ];
1156 }
1157
1169 public function updateBlock( DatabaseBlock $block ) {
1170 $this->logger->debug( 'Updating block; timestamp ' . $block->getTimestamp() );
1171
1172 $block->assertWiki( $this->wikiId );
1173
1174 $blockId = $block->getId( $this->wikiId );
1175 if ( !$blockId ) {
1176 throw new InvalidArgumentException(
1177 __METHOD__ . ' requires that a block id be set'
1178 );
1179 }
1180
1181 // Update bl_timestamp to current when making any updates to a block (T389275)
1182 $block->setTimestamp( wfTimestamp() );
1183
1184 $dbw = $this->getPrimaryDB();
1185
1186 $dbw->startAtomic( __METHOD__ );
1187
1188 $row = $this->getArrayForBlockUpdate( $block, $dbw );
1189 $dbw->newUpdateQueryBuilder()
1190 ->update( 'block' )
1191 ->set( $row )
1192 ->where( [ 'bl_id' => $blockId ] )
1193 ->caller( __METHOD__ )->execute();
1194
1195 // Only update the restrictions if they have been modified.
1196 $result = true;
1197 $restrictions = $block->getRawRestrictions();
1198 if ( $restrictions !== null ) {
1199 // An empty array should remove all of the restrictions.
1200 if ( $restrictions === [] ) {
1201 $result = $this->blockRestrictionStore->deleteByBlockId( $blockId );
1202 } else {
1203 $result = $this->blockRestrictionStore->update( $restrictions );
1204 }
1205 }
1206
1207 if ( $block->isAutoblocking() ) {
1208 // Update corresponding autoblock(s) (T50813)
1209 $dbw->newUpdateQueryBuilder()
1210 ->update( 'block' )
1211 ->set( $this->getArrayForAutoblockUpdate( $block ) )
1212 ->where( [ 'bl_parent_block_id' => $blockId ] )
1213 ->caller( __METHOD__ )->execute();
1214
1215 // Only update the restrictions if they have been modified.
1216 if ( $restrictions !== null ) {
1217 $this->blockRestrictionStore->updateByParentBlockId(
1218 $blockId,
1219 $restrictions
1220 );
1221 }
1222 } else {
1223 // Autoblock no longer required, delete corresponding autoblock(s)
1224 $this->deleteBlocksMatchingConds( [ 'bl_parent_block_id' => $blockId ] );
1225 }
1226
1227 $dbw->endAtomic( __METHOD__ );
1228
1229 if ( $result ) {
1230 $autoBlockIds = $this->doRetroactiveAutoblock( $block );
1231 return [ 'id' => $blockId, 'autoIds' => $autoBlockIds ];
1232 }
1233
1234 return false;
1235 }
1236
1250 public function updateTarget( DatabaseBlock $block, $newTarget ) {
1251 $dbw = $this->getPrimaryDB();
1252 $blockId = $block->getId( $this->wikiId );
1253 if ( !$blockId ) {
1254 throw new InvalidArgumentException(
1255 __METHOD__ . " requires that a block id be set\n"
1256 );
1257 }
1258 if ( !( $newTarget instanceof BlockTarget ) ) {
1259 $newTarget = $this->blockTargetFactory->newFromLegacyUnion( $newTarget );
1260 }
1261
1262 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable
1263 $oldTargetConds = $this->getTargetConds( $block->getTarget() );
1264 $block->setTarget( $newTarget );
1265
1266 $dbw->startAtomic( __METHOD__ );
1267 [ $targetId, $count ] = $this->acquireTarget( $block, $dbw, null );
1268 if ( !$targetId ) {
1269 // This is an exotic and unlikely error -- perhaps an exception should be thrown
1270 $dbw->endAtomic( __METHOD__ );
1271 return false;
1272 }
1273 $oldTargetId = $dbw->newSelectQueryBuilder()
1274 ->select( 'bt_id' )
1275 ->from( 'block_target' )
1276 ->where( $oldTargetConds )
1277 ->caller( __METHOD__ )->fetchField();
1278 $this->releaseTargets( $dbw, [ $oldTargetId ] );
1279
1280 $dbw->newUpdateQueryBuilder()
1281 ->update( 'block' )
1282 ->set( [ 'bl_target' => $targetId ] )
1283 ->where( [ 'bl_id' => $blockId ] )
1284 ->caller( __METHOD__ )
1285 ->execute();
1286 $affected = $dbw->affectedRows();
1287 $dbw->endAtomic( __METHOD__ );
1288 return (bool)$affected;
1289 }
1290
1297 public function deleteBlock( DatabaseBlock $block ): bool {
1298 if ( $this->readOnlyMode->isReadOnly( $this->wikiId ) ) {
1299 return false;
1300 }
1301
1302 $block->assertWiki( $this->wikiId );
1303
1304 $blockId = $block->getId( $this->wikiId );
1305
1306 if ( !$blockId ) {
1307 throw new InvalidArgumentException(
1308 __METHOD__ . ' requires that a block id be set'
1309 );
1310 }
1311 $dbw = $this->getPrimaryDB();
1312 $dbw->startAtomic( __METHOD__ );
1313 $res = $dbw->newSelectQueryBuilder()
1314 ->select( [ 'bl_id', 'bl_target' ] )
1315 ->from( 'block' )
1316 ->where(
1317 $dbw->orExpr( [
1318 'bl_parent_block_id' => $blockId,
1319 'bl_id' => $blockId,
1320 ] )
1321 )
1322 ->caller( __METHOD__ )->fetchResultSet();
1323 $this->deleteBlockRows( $res );
1324 $affected = $res->numRows();
1325 $dbw->endAtomic( __METHOD__ );
1326
1327 return $affected > 0;
1328 }
1329
1338 private function getArrayForBlockUpdate(
1339 DatabaseBlock $block,
1340 IDatabase $dbw
1341 ): array {
1342 $expiry = $dbw->encodeExpiry( $block->getExpiry() );
1343
1344 $blocker = $block->getBlocker();
1345 if ( !$blocker ) {
1346 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1347 }
1348 // DatabaseBlockStore supports inserting cross-wiki blocks by passing
1349 // non-local IDatabase and blocker.
1350 $blockerActor = $this->actorStoreFactory
1351 ->getActorStore( $dbw->getDomainID() )
1352 ->acquireActorId( $blocker, $dbw );
1353
1354 $blockArray = [
1355 'bl_by_actor' => $blockerActor,
1356 'bl_timestamp' => $dbw->timestamp( $block->getTimestamp() ),
1357 'bl_anon_only' => !$block->isHardblock(),
1358 'bl_create_account' => $block->isCreateAccountBlocked(),
1359 'bl_enable_autoblock' => $block->isAutoblocking(),
1360 'bl_expiry' => $expiry,
1361 'bl_deleted' => $this->getDeletedColumnValue( $block ),
1362 'bl_block_email' => $block->isEmailBlocked(),
1363 'bl_allow_usertalk' => $block->isUsertalkEditAllowed(),
1364 'bl_parent_block_id' => $block->getParentBlockId(),
1365 'bl_sitewide' => $block->isSitewide(),
1366 ];
1367 $commentArray = $this->commentStore->insert(
1368 $dbw,
1369 'bl_reason',
1370 $block->getReasonComment()
1371 );
1372
1373 $combinedArray = $blockArray + $commentArray;
1374 return $combinedArray;
1375 }
1376
1383 private function getArrayForAutoblockUpdate( DatabaseBlock $block ): array {
1384 $blocker = $block->getBlocker();
1385 if ( !$blocker ) {
1386 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1387 }
1388 $dbw = $this->getPrimaryDB();
1389 $blockerActor = $this->actorStoreFactory
1390 ->getActorNormalization( $this->wikiId )
1391 ->acquireActorId( $blocker, $dbw );
1392
1393 $blockArray = [
1394 'bl_by_actor' => $blockerActor,
1395 'bl_create_account' => $block->isCreateAccountBlocked(),
1396 'bl_deleted' => $this->getDeletedColumnValue( $block ),
1397 'bl_allow_usertalk' => $block->isUsertalkEditAllowed(),
1398 'bl_sitewide' => $block->isSitewide(),
1399 ];
1400
1401 // Shorten the autoblock expiry if the parent block expiry is sooner.
1402 // Don't lengthen -- that is only done when the IP address is actually
1403 // used by the blocked user.
1404 if ( $block->getExpiry() !== 'infinity' ) {
1405 $blockArray['bl_expiry'] = new RawSQLValue( $dbw->conditional(
1406 $dbw->expr( 'bl_expiry', '>', $dbw->timestamp( $block->getExpiry() ) ),
1407 $dbw->addQuotes( $dbw->timestamp( $block->getExpiry() ) ),
1408 'bl_expiry'
1409 ) );
1410 }
1411
1412 $commentArray = $this->commentStore->insert(
1413 $dbw,
1414 'bl_reason',
1415 $this->getAutoblockReason( $block )
1416 );
1417
1418 $combinedArray = $blockArray + $commentArray;
1419 return $combinedArray;
1420 }
1421
1425 private function getDeletedColumnValue( DatabaseBlock $block ): int {
1426 if ( $block->getHideName() ) {
1427 return 1;
1428 } elseif ( $block->getHideBlock() ) {
1429 return 2;
1430 }
1431 return 0;
1432 }
1433
1441 private function doRetroactiveAutoblock( DatabaseBlock $block ): array {
1442 $autoBlockIds = [];
1443 // If autoblock is enabled, autoblock the LAST IP(s) used
1444 if ( $block->isAutoblocking() && $block->getType() == AbstractBlock::TYPE_USER ) {
1445 $this->logger->debug(
1446 'Doing retroactive autoblocks for ' . $block->getTargetName()
1447 );
1448
1449 $hookAutoBlocked = [];
1450 $continue = $this->hookRunner->onPerformRetroactiveAutoblock(
1451 $block,
1452 $hookAutoBlocked
1453 );
1454
1455 if ( $continue ) {
1456 $coreAutoBlocked = $this->performRetroactiveAutoblock( $block );
1457 $autoBlockIds = array_merge( $hookAutoBlocked, $coreAutoBlocked );
1458 } else {
1459 $autoBlockIds = $hookAutoBlocked;
1460 }
1461 }
1462 return $autoBlockIds;
1463 }
1464
1472 private function performRetroactiveAutoblock( DatabaseBlock $block ): array {
1473 if ( !$this->options->get( MainConfigNames::PutIPinRC ) ) {
1474 // No IPs in the recent changes table to autoblock
1475 return [];
1476 }
1477
1478 $target = $block->getTarget();
1479 if ( !( $target instanceof UserBlockTarget ) ) {
1480 // Autoblocks only apply to users
1481 return [];
1482 }
1483
1484 $dbr = $this->getReplicaDB();
1485
1486 $actor = $this->actorStoreFactory
1487 ->getActorNormalization( $this->wikiId )
1488 ->findActorId( $target->getUserIdentity(), $dbr );
1489
1490 if ( !$actor ) {
1491 $this->logger->debug( 'No actor found to retroactively autoblock' );
1492 return [];
1493 }
1494
1495 $rcIp = $dbr->newSelectQueryBuilder()
1496 ->select( 'rc_ip' )
1497 ->from( 'recentchanges' )
1498 ->where( [ 'rc_actor' => $actor ] )
1499 ->orderBy( 'rc_timestamp', SelectQueryBuilder::SORT_DESC )
1500 ->caller( __METHOD__ )->fetchField();
1501
1502 if ( !$rcIp ) {
1503 $this->logger->debug( 'No IP found to retroactively autoblock' );
1504 return [];
1505 }
1506
1507 $id = $this->doAutoblock( $block, $rcIp );
1508 if ( !$id ) {
1509 return [];
1510 }
1511 return [ $id ];
1512 }
1513
1522 public function doAutoblock( DatabaseBlock $parentBlock, $autoblockIP ) {
1523 // If autoblocks are disabled, go away.
1524 if ( !$parentBlock->isAutoblocking() ) {
1525 return false;
1526 }
1527 $parentBlock->assertWiki( $this->wikiId );
1528
1529 $target = $this->blockTargetFactory->newFromIp( $autoblockIP );
1530 if ( !$target ) {
1531 $this->logger->debug( "Invalid autoblock IP" );
1532 return false;
1533 }
1534
1535 // Check if autoblock exempt.
1536 if ( $this->autoblockExemptionList->isExempt( $autoblockIP ) ) {
1537 return false;
1538 }
1539
1540 // Allow hooks to cancel the autoblock.
1541 if ( !$this->hookRunner->onAbortAutoblock( $autoblockIP, $parentBlock ) ) {
1542 $this->logger->debug( "Autoblock aborted by hook." );
1543 return false;
1544 }
1545
1546 // It's okay to autoblock. Go ahead and insert/update the block...
1547
1548 // Do not add a *new* block if the IP is already blocked.
1549 $blocks = $this->newLoad( $target, false );
1550 if ( $blocks ) {
1551 foreach ( $blocks as $ipblock ) {
1552 // Check if the block is an autoblock and would exceed the user block
1553 // if renewed. If so, do nothing, otherwise prolong the block time...
1554 if ( $ipblock->getType() === Block::TYPE_AUTO
1555 && $parentBlock->getExpiry() > $ipblock->getExpiry()
1556 ) {
1557 // Reset block timestamp to now and its expiry to
1558 // $wgAutoblockExpiry in the future
1559 $this->updateTimestamp( $ipblock );
1560 }
1561 }
1562 return false;
1563 }
1564 $blocker = $parentBlock->getBlocker();
1565 if ( !$blocker ) {
1566 throw new RuntimeException( __METHOD__ . ': this block does not have a blocker' );
1567 }
1568
1569 // Acquire a lock on the primary DB for the autoblock to prevent race conditions (T260838)
1570 $dbw = $this->getPrimaryDB();
1571 $autoblockTargetLockKey = $dbw->getDomainID() . ':autoblock:' . $target;
1572 if ( !$dbw->lock( $autoblockTargetLockKey, __METHOD__, 0 ) ) {
1573 return false;
1574 }
1575
1576 $timestamp = wfTimestampNow();
1577 $expiry = $this->getAutoblockExpiry( $timestamp, $parentBlock->getExpiry() );
1578 $autoblock = new DatabaseBlock( [
1579 'wiki' => $this->wikiId,
1580 'target' => $target,
1581 'by' => $blocker,
1582 'reason' => $this->getAutoblockReason( $parentBlock ),
1583 'decodedTimestamp' => $timestamp,
1584 'auto' => true,
1585 'createAccount' => $parentBlock->isCreateAccountBlocked(),
1586 // Continue suppressing the name if needed
1587 'hideName' => $parentBlock->getHideName(),
1588 'hideBlock' => $parentBlock->getHideBlock(),
1589 'allowUsertalk' => $parentBlock->isUsertalkEditAllowed(),
1590 'parentBlockId' => $parentBlock->getId( $this->wikiId ),
1591 'sitewide' => $parentBlock->isSitewide(),
1592 'restrictions' => $parentBlock->getRestrictions(),
1593 'decodedExpiry' => $expiry,
1594 ] );
1595
1596 $this->logger->debug( "Autoblocking {$parentBlock->getTargetName()}@" . $target );
1597
1598 $status = $this->insertBlock( $autoblock );
1599
1600 $dbw->unlock( $autoblockTargetLockKey, __METHOD__ );
1601
1602 return $status
1603 ? $status['id']
1604 : false;
1605 }
1606
1607 private function getAutoblockReason( DatabaseBlock $parentBlock ): string {
1609 'autoblocker',
1610 $parentBlock->getTargetName(),
1611 $parentBlock->getReasonComment()->text
1612 )->inContentLanguage()->plain();
1613 }
1614
1621 public function updateTimestamp( DatabaseBlock $block ) {
1622 $block->assertWiki( $this->wikiId );
1623 if ( $block->getType() !== Block::TYPE_AUTO ) {
1624 return;
1625 }
1626 $now = wfTimestamp();
1627 $block->setTimestamp( $now );
1628 // No need to reduce the autoblock expiry to the expiry of the parent
1629 // block, since the caller already checked for that.
1630 $block->setExpiry( $this->getAutoblockExpiry( $now ) );
1631
1632 $dbw = $this->getPrimaryDB();
1633 $dbw->newUpdateQueryBuilder()
1634 ->update( 'block' )
1635 ->set(
1636 [
1637 'bl_timestamp' => $dbw->timestamp( $block->getTimestamp() ),
1638 'bl_expiry' => $dbw->timestamp( $block->getExpiry() ),
1639 ]
1640 )
1641 ->where( [ 'bl_id' => $block->getId( $this->wikiId ) ] )
1642 ->caller( __METHOD__ )->execute();
1643 }
1644
1656 public function getAutoblockExpiry( $timestamp, ?string $parentExpiry = null ) {
1657 $maxDuration = $this->options->get( MainConfigNames::AutoblockExpiry );
1658 $expiry = wfTimestamp( TS::MW, (int)wfTimestamp( TS::UNIX, $timestamp ) + $maxDuration );
1659 if ( $parentExpiry !== null && $parentExpiry !== 'infinity' ) {
1660 $expiry = min( $parentExpiry, $expiry );
1661 }
1662 return $expiry;
1663 }
1664
1665 // endregion -- end of database write methods
1666
1667}
const LIST_OR
Definition Defines.php:33
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:71
isUsertalkEditAllowed( $x=null)
Get or set the flag indicating whether this block blocks the target from editing their own user talk ...
getTarget()
Get the target as an object.
setTarget( $target)
Set the target for this block.
getHideName()
Get whether the block hides the target's username.
getHideBlock()
Get whether the block is hidden.
setTimestamp( $timestamp)
Set the timestamp indicating when the block was created.
isCreateAccountBlocked( $x=null)
Get or set the flag indicating whether this block blocks the target from creating an account.
getTimestamp()
Get the timestamp indicating when the block was created.
isSitewide( $x=null)
Indicates that the block is a sitewide block.
getExpiry()
Get the block expiry time.
setExpiry( $expiry)
Set the block expiry time.
A block target of the form #1234 where the number is the block ID.
Provides access to the wiki's autoblock exemption list.
Factory for BlockTarget objects.
Base class for block targets.
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'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 220, 250, 300, 400,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'TrackMediaRequestProvenance'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EmailConfirmationBanner'=> false, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'CodeHighlighter',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'NamespacesWithoutAutoSummaries' => [ ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider', 'services' => [ 'ConnectionProvider', 'UserFactory', ], 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'autocreateaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, 'createwithcontentmodel' => true, 'logout' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'createpreviouslyrenamedaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], 'managesessions' => [ 'logout' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', 'managesessions' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPUseReportURIDirective' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'ApiClientErrorSampleRate' => 1.0, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: 'https: 'git@github\\.com:(.*?)(\\.git)?' => 'https: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, 'mw-edited-other-users-js' => true, 'mw-edited-other-users-css' => true, ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchstarPopover' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\RecentChanges\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Promise-Non-Write-API-Action', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'RestModuleOverrides' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, ], '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', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EmailConfirmationBanner' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'NamespacesWithoutAutoSummaries' => 'array', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPUseReportURIDirective' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchstarPopover' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'RestModuleOverrides' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'RestModuleOverrides' => 'array_replace_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'file' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], ], ], 'RestModuleOverrides' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'mode' => [ 'type' => 'string', ], ], 'required' => [ 'mode', ], ], ], '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...