MediaWiki master
ApiBase.php
Go to the documentation of this file.
1<?php
9namespace MediaWiki\Api;
10
11use InvalidArgumentException;
12use LogicException;
33use ReflectionClass;
34use StatusValue;
35use stdClass;
36use Throwable;
43use Wikimedia\Timestamp\TimestampException;
44
60abstract class ApiBase extends ContextSource {
61
63 private $hookContainer;
64
66 private $hookRunner;
67
76 public const PARAM_DFLT = ParamValidator::PARAM_DEFAULT;
80 public const PARAM_ISMULTI = ParamValidator::PARAM_ISMULTI;
84 public const PARAM_TYPE = ParamValidator::PARAM_TYPE;
88 public const PARAM_MAX = IntegerDef::PARAM_MAX;
92 public const PARAM_MAX2 = IntegerDef::PARAM_MAX2;
96 public const PARAM_MIN = IntegerDef::PARAM_MIN;
100 public const PARAM_ALLOW_DUPLICATES = ParamValidator::PARAM_ALLOW_DUPLICATES;
104 public const PARAM_DEPRECATED = ParamValidator::PARAM_DEPRECATED;
108 public const PARAM_REQUIRED = ParamValidator::PARAM_REQUIRED;
112 public const PARAM_SUBMODULE_MAP = SubmoduleDef::PARAM_SUBMODULE_MAP;
116 public const PARAM_SUBMODULE_PARAM_PREFIX = SubmoduleDef::PARAM_SUBMODULE_PARAM_PREFIX;
120 public const PARAM_ALL = ParamValidator::PARAM_ALL;
124 public const PARAM_EXTRA_NAMESPACES = NamespaceDef::PARAM_EXTRA_NAMESPACES;
128 public const PARAM_SENSITIVE = ParamValidator::PARAM_SENSITIVE;
132 public const PARAM_DEPRECATED_VALUES = EnumDef::PARAM_DEPRECATED_VALUES;
136 public const PARAM_ISMULTI_LIMIT1 = ParamValidator::PARAM_ISMULTI_LIMIT1;
140 public const PARAM_ISMULTI_LIMIT2 = ParamValidator::PARAM_ISMULTI_LIMIT2;
155 public const PARAM_RANGE_ENFORCE = 'api-param-range-enforce';
156
157 // region API-specific constants for ::getAllowedParams() arrays
166 public const PARAM_HELP_MSG = 'api-param-help-msg';
167
174 public const PARAM_HELP_MSG_APPEND = 'api-param-help-msg-append';
175
184 public const PARAM_HELP_MSG_INFO = 'api-param-help-msg-info';
185
191 public const PARAM_VALUE_LINKS = 'api-param-value-links';
192
206 public const PARAM_HELP_MSG_PER_VALUE = 'api-param-help-msg-per-value';
207
224 public const PARAM_TEMPLATE_VARS = 'param-template-vars';
225
226 // endregion -- end of API-specific constants for ::getAllowedParams() arrays
227
228 public const ALL_DEFAULT_STRING = '*';
229
231 public const LIMIT_BIG1 = 500;
233 public const LIMIT_BIG2 = 5000;
235 public const LIMIT_SML1 = 50;
237 public const LIMIT_SML2 = 500;
238
244 public const GET_VALUES_FOR_HELP = 1;
245
247 private static $extensionInfo = null;
248
250 private static $filterIDsCache = [];
251
253 private const MESSAGE_CODE_MAP = [
254 'actionthrottled' => [ 'apierror-ratelimited', 'ratelimited' ],
255 'actionthrottledtext' => [ 'apierror-ratelimited', 'ratelimited' ],
256 ];
257
259 private $mMainModule;
260
261 // Adding inline type hints for these two fields is non-trivial because
262 // of tests that create mocks for ApiBase subclasses and use
263 // disableOriginalConstructor(): in those cases the constructor here is never
264 // hit and thus these will be empty and any uses will raise a "Typed property
265 // must not be accessed before initialization" error.
267 private $mModuleName;
269 private $mModulePrefix;
270
272 private $mReplicaDB = null;
276 private $mParamCache = [];
278 private $mModuleSource = false;
279
286 public function __construct( ApiMain $mainModule, string $moduleName, string $modulePrefix = '' ) {
287 $this->mMainModule = $mainModule;
288 $this->mModuleName = $moduleName;
289 $this->mModulePrefix = $modulePrefix;
290
291 if ( !$this->isMain() ) {
292 $this->setContext( $mainModule->getContext() );
293 }
294 }
295
296 /***************************************************************************/
297 // region Methods to implement
316 abstract public function execute();
317
325 public function getModuleManager() {
326 return null;
327 }
328
341 public function getCustomPrinter() {
342 return null;
343 }
344
357 protected function getExamplesMessages() {
358 return [];
359 }
360
368 public function getHelpUrls() {
369 return [];
370 }
371
385 protected function getAllowedParams( /* $flags = 0 */ ) {
386 // $flags is not declared because it causes "Strict standards"
387 // warning. Most derived classes do not implement it.
388 return [];
389 }
390
397 public function shouldCheckMaxlag() {
398 return true;
399 }
400
407 public function isReadMode() {
408 return true;
409 }
410
436 public function isWriteMode() {
437 return false;
438 }
439
449 public function mustBePosted() {
450 return $this->needsToken() !== false;
451 }
452
463 public function isDeprecated() {
464 return $this->deprecationMsg() !== null;
465 }
466
475 public function deprecationMsg(): ?MessageSpecifier {
476 return null;
477 }
478
488 public function isInternal() {
489 return false;
490 }
491
511 public function needsToken() {
512 return false;
513 }
514
525 protected function getWebUITokenSalt( array $params ) {
526 return null;
527 }
528
542 public function getConditionalRequestData( $condition ) {
543 return null;
544 }
545
546 // endregion -- end of methods to implement
547
548 /***************************************************************************/
549 // region Data access methods
557 public function getModuleName() {
558 return $this->mModuleName;
559 }
560
566 public function getModulePrefix() {
567 return $this->mModulePrefix;
568 }
569
575 public function getMain() {
576 return $this->mMainModule;
577 }
578
585 public function isMain() {
586 return $this === $this->mMainModule;
587 }
588
596 public function getParent() {
597 return $this->isMain() ? null : $this->getMain();
598 }
599
607 private function dieIfMain( string $methodName ) {
608 if ( $this->isMain() ) {
609 self::dieDebug( $methodName, 'base method was called on main module.' );
610 }
611 }
612
623 public function lacksSameOriginSecurity() {
624 // The Main module has this method overridden, avoid infinite loops
625 $this->dieIfMain( __METHOD__ );
626
627 return $this->getMain()->lacksSameOriginSecurity();
628 }
629
636 public function getModulePath() {
637 if ( $this->isMain() ) {
638 return 'main';
639 }
640
641 if ( $this->getParent()->isMain() ) {
642 return $this->getModuleName();
643 }
644
645 return $this->getParent()->getModulePath() . '+' . $this->getModuleName();
646 }
647
656 public function getModuleFromPath( $path ) {
657 $module = $this->getMain();
658 if ( $path === 'main' ) {
659 return $module;
660 }
661
662 $parts = explode( '+', $path );
663 if ( count( $parts ) === 1 ) {
664 // In case the '+' was typed into URL, it resolves as a space
665 $parts = explode( ' ', $path );
666 }
667
668 foreach ( $parts as $i => $v ) {
669 $parent = $module;
670 $manager = $parent->getModuleManager();
671 if ( $manager === null ) {
672 $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
673 $this->dieWithError( [ 'apierror-badmodule-nosubmodules', $errorPath ], 'badmodule' );
674 }
675 $module = $manager->getModule( $v );
676
677 if ( $module === null ) {
678 $errorPath = $i
679 ? implode( '+', array_slice( $parts, 0, $i ) )
680 : $parent->getModuleName();
681 $this->dieWithError(
682 [ 'apierror-badmodule-badsubmodule', $errorPath, wfEscapeWikiText( $v ) ],
683 'badmodule'
684 );
685 }
686 }
687
688 return $module;
689 }
690
696 public function getResult() {
697 // The Main module has this method overridden, avoid infinite loops
698 $this->dieIfMain( __METHOD__ );
699
700 return $this->getMain()->getResult();
701 }
702
707 public function getErrorFormatter() {
708 // The Main module has this method overridden, avoid infinite loops
709 $this->dieIfMain( __METHOD__ );
710
711 return $this->getMain()->getErrorFormatter();
712 }
713
720 protected function getDB() {
721 if ( !$this->mReplicaDB ) {
722 $this->mReplicaDB = MediaWikiServices::getInstance()
723 ->getConnectionProvider()
724 ->getReplicaDatabase();
725 }
726
727 return $this->mReplicaDB;
728 }
729
733 public function getContinuationManager() {
734 // The Main module has this method overridden, avoid infinite loops
735 $this->dieIfMain( __METHOD__ );
736
737 return $this->getMain()->getContinuationManager();
738 }
739
743 public function setContinuationManager( ?ApiContinuationManager $manager = null ) {
744 // The Main module has this method overridden, avoid infinite loops
745 $this->dieIfMain( __METHOD__ );
746
747 $this->getMain()->setContinuationManager( $manager );
748 }
749
757 return MediaWikiServices::getInstance()->getPermissionManager();
758 }
759
766 protected function getHookContainer() {
767 if ( !$this->hookContainer ) {
768 $this->hookContainer = MediaWikiServices::getInstance()->getHookContainer();
769 }
770 return $this->hookContainer;
771 }
772
781 protected function getHookRunner() {
782 if ( !$this->hookRunner ) {
783 $this->hookRunner = new ApiHookRunner( $this->getHookContainer() );
784 }
785 return $this->hookRunner;
786 }
787
788 // endregion -- end of data access methods
789
790 /***************************************************************************/
791 // region Parameter handling
804 return null;
805 }
806
815 public function encodeParamName( $paramName ) {
816 if ( is_array( $paramName ) ) {
817 return array_map( function ( $name ) {
818 return $this->mModulePrefix . $name;
819 }, $paramName );
820 }
821
822 return $this->mModulePrefix . $paramName;
823 }
824
837 public function extractRequestParams( $options = [] ) {
838 if ( is_bool( $options ) ) {
839 $options = [ 'parseLimit' => $options ];
840 }
841 $options += [
842 'parseLimit' => true,
843 'safeMode' => false,
844 ];
845
846 $parseLimit = (bool)$options['parseLimit'];
847 $cacheKey = (int)$parseLimit;
848
849 // Cache parameters, for performance and to avoid T26564.
850 if ( !isset( $this->mParamCache[$cacheKey] ) ) {
851 $params = $this->getFinalParams() ?: [];
852 $results = [];
853 $warned = [];
854
855 // Process all non-templates and save templates for secondary
856 // processing.
857 $toProcess = [];
858 foreach ( $params as $paramName => $paramSettings ) {
859 if ( isset( $paramSettings[self::PARAM_TEMPLATE_VARS] ) ) {
860 $toProcess[] = [ $paramName, $paramSettings[self::PARAM_TEMPLATE_VARS], $paramSettings ];
861 } else {
862 try {
863 $results[$paramName] = $this->getParameterFromSettings(
864 $paramName, $paramSettings, $parseLimit
865 );
866 } catch ( ApiUsageException $ex ) {
867 $results[$paramName] = $ex;
868 }
869 }
870 }
871
872 // Now process all the templates by successively replacing the
873 // placeholders with all client-supplied values.
874 // This bit duplicates JavaScript logic in
875 // ApiSandbox.PageLayout.prototype.updateTemplatedParams().
876 // If you update this, see if that needs updating too.
877 while ( $toProcess ) {
878 [ $name, $targets, $settings ] = array_shift( $toProcess );
879
880 foreach ( $targets as $placeholder => $target ) {
881 if ( !array_key_exists( $target, $results ) ) {
882 // The target wasn't processed yet, try the next one.
883 // If all hit this case, the parameter has no expansions.
884 continue;
885 }
886 if ( !is_array( $results[$target] ) || !$results[$target] ) {
887 // The target was processed but has no (valid) values.
888 // That means it has no expansions.
889 break;
890 }
891
892 // Expand this target in the name and all other targets,
893 // then requeue if there are more targets left or put in
894 // $results if all are done.
895 unset( $targets[$placeholder] );
896 $placeholder = '{' . $placeholder . '}';
897 // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
898 foreach ( $results[$target] as $value ) {
899 if ( !preg_match( '/^[^{}]*$/', $value ) ) {
900 // Skip values that make invalid parameter names.
901 $encTargetName = $this->encodeParamName( $target );
902 if ( !isset( $warned[$encTargetName][$value] ) ) {
903 $warned[$encTargetName][$value] = true;
904 $this->addWarning( [
905 'apiwarn-ignoring-invalid-templated-value',
906 wfEscapeWikiText( $encTargetName ),
907 wfEscapeWikiText( $value ),
908 ] );
909 }
910 continue;
911 }
912
913 $newName = str_replace( $placeholder, $value, $name );
914 if ( !$targets ) {
915 try {
916 $results[$newName] = $this->getParameterFromSettings(
917 $newName,
918 $settings,
919 $parseLimit
920 );
921 } catch ( ApiUsageException $ex ) {
922 $results[$newName] = $ex;
923 }
924 } else {
925 $newTargets = [];
926 foreach ( $targets as $k => $v ) {
927 $newTargets[$k] = str_replace( $placeholder, $value, $v );
928 }
929 $toProcess[] = [ $newName, $newTargets, $settings ];
930 }
931 }
932 break;
933 }
934 }
935
936 $this->mParamCache[$cacheKey] = $results;
937 }
938
939 $ret = $this->mParamCache[$cacheKey];
940 if ( !$options['safeMode'] ) {
941 foreach ( $ret as $v ) {
942 if ( $v instanceof ApiUsageException ) {
943 throw $v;
944 }
945 }
946 }
947
948 return $this->mParamCache[$cacheKey];
949 }
950
958 protected function getParameter( $paramName, $parseLimit = true ) {
959 $ret = $this->extractRequestParams( [
960 'parseLimit' => $parseLimit,
961 'safeMode' => true,
962 ] )[$paramName];
963 if ( $ret instanceof ApiUsageException ) {
964 throw $ret;
965 }
966 return $ret;
967 }
968
975 public function requireOnlyOneParameter( $params, ...$required ) {
976 $intersection = array_intersect(
977 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
978 $required
979 );
980
981 if ( count( $intersection ) > 1 ) {
982 $this->dieWithError( [
983 'apierror-invalidparammix',
984 Message::listParam( array_map(
985 function ( $p ) {
986 return '<var>' . $this->encodeParamName( $p ) . '</var>';
987 },
988 array_values( $intersection )
989 ) ),
990 count( $intersection ),
991 ] );
992 } elseif ( count( $intersection ) == 0 ) {
993 $this->dieWithError( [
994 'apierror-missingparam-one-of',
995 Message::listParam( array_map(
996 function ( $p ) {
997 return '<var>' . $this->encodeParamName( $p ) . '</var>';
998 },
999 $required
1000 ) ),
1001 count( $required ),
1002 ], 'missingparam' );
1003 }
1004 }
1005
1012 public function requireMaxOneParameter( $params, ...$required ) {
1013 $intersection = array_intersect(
1014 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1015 $required
1016 );
1017
1018 if ( count( $intersection ) > 1 ) {
1019 $this->dieWithError( [
1020 'apierror-invalidparammix',
1021 Message::listParam( array_map(
1022 function ( $p ) {
1023 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1024 },
1025 array_values( $intersection )
1026 ) ),
1027 count( $intersection ),
1028 ] );
1029 }
1030 }
1031
1039 public function requireAtLeastOneParameter( $params, ...$required ) {
1040 $intersection = array_intersect(
1041 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1042 $required
1043 );
1044
1045 if ( count( $intersection ) == 0 ) {
1046 $this->dieWithError( [
1047 'apierror-missingparam-at-least-one-of',
1048 Message::listParam( array_map(
1049 function ( $p ) {
1050 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1051 },
1052 $required
1053 ) ),
1054 count( $required ),
1055 ], 'missingparam' );
1056 }
1057 }
1058
1070 public function requireNoConflictingParameters( $params, $trigger, $conflicts ) {
1071 $triggerValue = $params[$trigger] ?? null;
1072 if ( $triggerValue === null || $triggerValue === false ) {
1073 return;
1074 }
1075 $intersection = array_intersect(
1076 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1077 (array)$conflicts
1078 );
1079 if ( count( $intersection ) ) {
1080 $this->dieWithError( [
1081 'apierror-invalidparammix-cannotusewith',
1082 Message::listParam( array_map(
1083 function ( $p ) {
1084 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1085 },
1086 array_values( $intersection )
1087 ) ),
1088 $trigger,
1089 ] );
1090 }
1091 }
1092
1101 public function requirePostedParameters( $params, $prefix = 'prefix' ) {
1102 if ( !$this->mustBePosted() ) {
1103 // In order to allow client code to choose the correct method (GET or POST) depending *only*
1104 // on mustBePosted(), make sure that the module requires posting if any of its potential
1105 // parameters require posting.
1106
1107 // TODO: Uncomment this
1108 // throw new LogicException( 'mustBePosted() must be true when using requirePostedParameters()' );
1109
1110 // This seems to already be the case in all modules in practice, but deprecate it first just
1111 // in case.
1112 wfDeprecatedMsg( 'mustBePosted() must be true when using requirePostedParameters()',
1113 '1.42' );
1114 }
1115
1116 // Skip if $wgDebugAPI is set, or if we're in internal mode
1117 if ( $this->getConfig()->get( MainConfigNames::DebugAPI ) ||
1118 $this->getMain()->isInternalMode() ) {
1119 return;
1120 }
1121
1122 $queryValues = $this->getRequest()->getQueryValuesOnly();
1123 $badParams = [];
1124 foreach ( $params as $param ) {
1125 if ( $prefix !== 'noprefix' ) {
1126 $param = $this->encodeParamName( $param );
1127 }
1128 if ( array_key_exists( $param, $queryValues ) ) {
1129 $badParams[] = $param;
1130 }
1131 }
1132
1133 if ( $badParams ) {
1134 $this->dieWithError(
1135 [ 'apierror-mustpostparams', implode( ', ', $badParams ), count( $badParams ) ]
1136 );
1137 }
1138 }
1139
1146 private function parameterNotEmpty( $x ) {
1147 return $x !== null && $x !== false;
1148 }
1149
1161 public function getTitleOrPageId( $params, $load = false ) {
1162 $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1163
1164 $pageObj = null;
1165 if ( isset( $params['title'] ) ) {
1166 $titleObj = Title::newFromText( $params['title'] );
1167 if ( !$titleObj || $titleObj->isExternal() ) {
1168 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1169 }
1170 if ( !$titleObj->canExist() ) {
1171 $this->dieWithError( 'apierror-pagecannotexist' );
1172 }
1173 $pageObj = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $titleObj );
1174 if ( $load !== false ) {
1175 $pageObj->loadPageData( $load );
1176 }
1177 } elseif ( isset( $params['pageid'] ) ) {
1178 if ( $load === false ) {
1179 $load = 'fromdb';
1180 }
1181 $pageObj = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromID( $params['pageid'], $load );
1182 if ( !$pageObj ) {
1183 $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1184 }
1185 }
1186
1187 // @phan-suppress-next-line PhanTypeMismatchReturnNullable requireOnlyOneParameter guard it is always set
1188 return $pageObj;
1189 }
1190
1199 public function getTitleFromTitleOrPageId( $params ) {
1200 $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1201
1202 $titleObj = null;
1203 if ( isset( $params['title'] ) ) {
1204 $titleObj = Title::newFromText( $params['title'] );
1205 if ( !$titleObj || $titleObj->isExternal() ) {
1206 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1207 }
1208 return $titleObj;
1209 }
1210
1211 if ( isset( $params['pageid'] ) ) {
1212 $titleObj = Title::newFromID( $params['pageid'] );
1213 if ( !$titleObj ) {
1214 $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1215 }
1216 }
1217
1218 // @phan-suppress-next-line PhanTypeMismatchReturnNullable requireOnlyOneParameter guard it is always set
1219 return $titleObj;
1220 }
1221
1231 protected function getParameterFromSettings( $name, $settings, $parseLimit ) {
1232 $validator = $this->getMain()->getParamValidator();
1233 $value = $validator->getValue( $this, $name, $settings, [
1234 'parse-limit' => $parseLimit,
1235 'raw' => ( $settings[ParamValidator::PARAM_TYPE] ?? '' ) === 'raw',
1236 ] );
1237
1238 // @todo Deprecate and remove this, if possible.
1239 if ( $parseLimit && isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1240 $settings[ParamValidator::PARAM_TYPE] === 'limit' &&
1241 $this->getMain()->getVal( $this->encodeParamName( $name ) ) === 'max'
1242 ) {
1243 $this->getResult()->addParsedLimit( $this->getModuleName(), $value );
1244 }
1245
1246 return $value;
1247 }
1248
1259 public function handleParamNormalization( $paramName, $value, $rawValue ) {
1260 $this->addWarning( [ 'apiwarn-badutf8', $paramName ] );
1261 }
1262
1271 final public function validateToken( $token, array $params ) {
1272 $tokenType = $this->needsToken();
1273 $salts = ApiQueryTokens::getTokenTypeSalts();
1274 if ( !isset( $salts[$tokenType] ) ) {
1275 throw new LogicException(
1276 "Module '{$this->getModuleName()}' tried to use token type '$tokenType' " .
1277 'without registering it'
1278 );
1279 }
1280
1281 $tokenObj = ApiQueryTokens::getToken(
1282 $this->getUser(), $this->getRequest()->getSession(), $salts[$tokenType]
1283 );
1284 if ( $tokenObj->match( $token ) ) {
1285 return true;
1286 }
1287
1288 $webUiSalt = $this->getWebUITokenSalt( $params );
1289
1290 return $webUiSalt !== null && $this->getUser()->matchEditToken(
1291 $token, $webUiSalt, $this->getRequest()
1292 );
1293 }
1294
1295 // endregion -- end of parameter handling
1296
1297 /***************************************************************************/
1298 // region Utility methods
1307 public function getWatchlistUser( $params ) {
1308 if ( $params['owner'] !== null && $params['token'] !== null ) {
1309 $services = MediaWikiServices::getInstance();
1310 $user = $services->getUserFactory()->newFromName( $params['owner'], UserRigorOptions::RIGOR_NONE );
1311 if ( !$user || !$user->isRegistered() ) {
1312 $this->dieWithError(
1313 [ 'nosuchusershort', wfEscapeWikiText( $params['owner'] ) ], 'bad_wlowner'
1314 );
1315 }
1316 $token = $services->getUserOptionsLookup()->getOption( $user, 'watchlisttoken' );
1317 if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
1318 $this->dieWithError( 'apierror-bad-watchlist-token', 'bad_wltoken' );
1319 }
1320 } else {
1321 $user = $this->getUser();
1322 if ( !$user->isRegistered() ) {
1323 $this->dieWithError( 'watchlistanontext', 'notloggedin' );
1324 }
1325 $this->checkUserRightsAny( 'viewmywatchlist' );
1326 }
1327
1328 return $user;
1329 }
1330
1345 public static function makeMessage( $msg, IContextSource $context, ?array $params = null ) {
1346 wfDeprecated( __METHOD__, '1.43' );
1347 if ( is_string( $msg ) ) {
1348 $msg = wfMessage( $msg );
1349 } elseif ( is_array( $msg ) ) {
1350 $msg = wfMessage( ...$msg );
1351 }
1352 if ( !$msg instanceof Message ) {
1353 return null;
1354 }
1355
1356 $msg->setContext( $context );
1357 if ( $params ) {
1358 $msg->params( $params );
1359 }
1360
1361 return $msg;
1362 }
1363
1369 protected function useTransactionalTimeLimit() {
1370 if ( $this->getRequest()->wasPosted() ) {
1372 }
1373 }
1374
1380 public static function clearCacheForTest(): void {
1381 if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
1382 throw new LogicException( 'Not allowed outside tests' );
1383 }
1384 self::$filterIDsCache = [];
1385 }
1386
1396 protected function filterIDs( $fields, array $ids ) {
1397 $min = INF;
1398 $max = 0;
1399 foreach ( $fields as [ $table, $field ] ) {
1400 if ( isset( self::$filterIDsCache[$table][$field] ) ) {
1401 $row = self::$filterIDsCache[$table][$field];
1402 } else {
1403 $row = $this->getDB()->newSelectQueryBuilder()
1404 ->select( [ 'min_id' => "MIN($field)", 'max_id' => "MAX($field)" ] )
1405 ->from( $table )
1406 ->caller( __METHOD__ )->fetchRow();
1407 self::$filterIDsCache[$table][$field] = $row;
1408 }
1409 $min = min( $min, $row->min_id );
1410 $max = max( $max, $row->max_id );
1411 }
1412 return array_filter( $ids, static function ( $id ) use ( $min, $max ) {
1413 return ( ( is_int( $id ) && $id >= 0 ) || ctype_digit( (string)$id ) )
1414 && $id >= $min && $id <= $max;
1415 } );
1416 }
1417
1418 // endregion -- end of utility methods
1419
1420 /***************************************************************************/
1421 // region Warning and error reporting
1439 public function addWarning( $msg, $code = null, $data = null ) {
1440 $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg, $code, $data );
1441 }
1442
1454 public function addDeprecation( $msg, $feature, $data = [] ) {
1455 $data = (array)$data;
1456 if ( $feature !== null ) {
1457 $data['feature'] = $feature;
1458 $this->logFeatureUsage( $feature );
1459 }
1460 $this->addWarning( $msg, 'deprecation', $data );
1461
1462 // No real need to deduplicate here, ApiErrorFormatter does that for
1463 // us (assuming the hook is deterministic).
1464 $msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
1465 $this->getHookRunner()->onApiDeprecationHelp( $msgs );
1466 if ( count( $msgs ) > 1 ) {
1467 $key = '$' . implode( ' $', range( 1, count( $msgs ) ) );
1468 $msg = ( new RawMessage( $key ) )->params( $msgs );
1469 } else {
1470 $msg = reset( $msgs );
1471 }
1472 $this->getMain()->addWarning( $msg, 'deprecation-help' );
1473 }
1474
1487 public function addError( $msg, $code = null, $data = null ) {
1488 $this->getErrorFormatter()->addError( $this->getModulePath(), $msg, $code, $data );
1489 }
1490
1500 public function addMessagesFromStatus(
1501 StatusValue $status, $types = [ 'warning', 'error' ], array $filter = []
1502 ) {
1503 $this->getErrorFormatter()->addMessagesFromStatus(
1504 $this->getModulePath(), $status, $types, $filter
1505 );
1506 }
1507
1522 public function dieWithError( $msg, $code = null, $data = null, $httpCode = 0 ): never {
1523 throw ApiUsageException::newWithMessage( $this, $msg, $code, $data, $httpCode );
1524 }
1525
1535 public function dieWithException( Throwable $exception, array $options = [] ): never {
1536 $this->dieWithError(
1537 $this->getErrorFormatter()->getMessageFromException( $exception, $options )
1538 );
1539 }
1540
1550 public function dieBlocked( Block $block ): never {
1551 $blockErrorFormatter = MediaWikiServices::getInstance()->getFormatterFactory()
1552 ->getBlockErrorFormatter( $this->getContext() );
1553
1554 $msg = $blockErrorFormatter->getMessage(
1555 $block,
1556 $this->getUser(),
1557 null,
1558 $this->getRequest()->getIP()
1559 );
1560
1561 $this->dieWithError( $msg );
1562 }
1563
1573 public function dieStatus( StatusValue $status ): never {
1574 if ( $status->isGood() ) {
1575 throw new InvalidArgumentException( 'Successful status passed to ApiBase::dieStatus' );
1576 }
1577
1578 foreach ( self::MESSAGE_CODE_MAP as $msg => [ $apiMsg, $code ] ) {
1579 if ( $status->hasMessage( $msg ) ) {
1580 $status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code ) );
1581 }
1582 }
1583
1584 if (
1585 $status instanceof PermissionStatus
1586 && $status->isRateLimitExceeded()
1587 && !$status->hasMessage( 'apierror-ratelimited' )
1588 ) {
1589 $status->fatal( ApiMessage::create( 'apierror-ratelimited', 'ratelimited' ) );
1590 }
1591
1592 // ApiUsageException needs a fatal status, but this method has
1593 // historically accepted any non-good status. Convert it if necessary.
1594 $status->setOK( false );
1595 if ( !$status->getMessages( 'error' ) ) {
1596 $newStatus = Status::newGood();
1597 foreach ( $status->getMessages( 'warning' ) as $err ) {
1598 $newStatus->fatal( $err );
1599 }
1600 if ( !$newStatus->getMessages( 'error' ) ) {
1601 $newStatus->fatal( 'unknownerror-nocode' );
1602 }
1603 $status = $newStatus;
1604 }
1605
1606 throw new ApiUsageException( $this, $status );
1607 }
1608
1615 public function dieReadOnly(): never {
1616 $this->dieWithError(
1617 'apierror-readonly',
1618 'readonly',
1619 [ 'readonlyreason' => MediaWikiServices::getInstance()->getReadOnlyMode()->getReason() ]
1620 );
1621 }
1622
1631 public function checkUserRightsAny( $rights ) {
1632 $rights = (array)$rights;
1633 if ( !$this->getAuthority()->isAllowedAny( ...$rights ) ) {
1634 $this->dieWithError( [ 'apierror-permissiondenied', $this->msg( "action-{$rights[0]}" ) ] );
1635 }
1636 }
1637
1655 PageIdentity $pageIdentity,
1656 $actions,
1657 array $options = []
1658 ) {
1659 $authority = $options['user'] ?? $this->getAuthority();
1660 $status = new PermissionStatus();
1661 foreach ( (array)$actions as $action ) {
1662 if ( $this->isWriteMode() ) {
1663 $authority->authorizeWrite( $action, $pageIdentity, $status );
1664 } else {
1665 $authority->authorizeRead( $action, $pageIdentity, $status );
1666 }
1667 }
1668 if ( !$status->isGood() ) {
1669 if ( !empty( $options['autoblock'] ) ) {
1670 $this->getUser()->spreadAnyEditBlock();
1671 }
1672 $this->dieStatus( $status );
1673 }
1674 }
1675
1689 public function dieWithErrorOrDebug( $msg, $code = null, $data = null, $httpCode = null ) {
1690 if ( $this->getConfig()->get( MainConfigNames::DebugAPI ) !== true ) {
1691 $this->dieWithError( $msg, $code, $data, $httpCode ?? 0 );
1692 } else {
1693 $this->addWarning( $msg, $code, $data );
1694 }
1695 }
1696
1707 protected function parseContinueParamOrDie( string $continue, array $types ): array {
1708 $cont = explode( '|', $continue );
1709 $this->dieContinueUsageIf( count( $cont ) != count( $types ) );
1710
1711 foreach ( $cont as $i => &$value ) {
1712 switch ( $types[$i] ) {
1713 case 'string':
1714 // Do nothing
1715 break;
1716 case 'int':
1717 $this->dieContinueUsageIf( $value !== (string)(int)$value );
1718 $value = (int)$value;
1719 break;
1720 case 'timestamp':
1721 try {
1722 $dbTs = $this->getDB()->timestamp( $value );
1723 } catch ( TimestampException ) {
1724 $dbTs = false;
1725 }
1726 $this->dieContinueUsageIf( $value !== $dbTs );
1727 break;
1728 default:
1729 throw new InvalidArgumentException( "Unknown type '{$types[$i]}'" );
1730 }
1731 }
1732
1733 return $cont;
1734 }
1735
1746 protected function dieContinueUsageIf( $condition ) {
1747 if ( $condition ) {
1748 $this->dieWithError( 'apierror-badcontinue' );
1749 }
1750 }
1751
1759 protected static function dieDebug( $method, $message ): never {
1760 throw new LogicException( "Internal error in $method: $message" );
1761 }
1762
1770 public function logFeatureUsage( $feature ) {
1771 static $loggedFeatures = [];
1772
1773 // Only log each feature once per request. We can get multiple calls from calls to
1774 // extractRequestParams() with different values for 'parseLimit', for example.
1775 if ( isset( $loggedFeatures[$feature] ) ) {
1776 return;
1777 }
1778 $loggedFeatures[$feature] = true;
1779
1780 $request = $this->getRequest();
1781 $ctx = [
1782 'feature' => $feature,
1783 // Replace spaces with underscores in 'username' for historical reasons.
1784 'username' => str_replace( ' ', '_', $this->getUser()->getName() ),
1785 'clientip' => $request->getIP(),
1786 'referer' => (string)$request->getHeader( 'Referer' ),
1787 'agent' => $this->getMain()->getUserAgent(),
1788 ];
1789
1790 // Text string is deprecated. Remove (or replace with just $feature) in MW 1.34.
1791 $s = '"' . addslashes( $ctx['feature'] ) . '"' .
1792 ' "' . wfUrlencode( $ctx['username'] ) . '"' .
1793 ' "' . $ctx['clientip'] . '"' .
1794 ' "' . addslashes( $ctx['referer'] ) . '"' .
1795 ' "' . addslashes( $ctx['agent'] ) . '"';
1796
1797 wfDebugLog( 'api-feature-usage', $s, 'private', $ctx );
1798
1799 $this->getHookRunner()->onApiLogFeatureUsage(
1800 $feature,
1801 [
1802 'userName' => $this->getUser()->getName(),
1803 'userAgent' => $this->getMain()->getUserAgent(),
1804 'ipAddress' => $request->getIP()
1805 ]
1806 );
1807 }
1808
1809 // endregion -- end of warning and error reporting
1810
1811 /***************************************************************************/
1812 // region Help message generation
1825 protected function getSummaryMessage() {
1826 return "apihelp-{$this->getModulePath()}-summary";
1827 }
1828
1840 protected function getExtendedDescription() {
1841 return [ [
1842 "apihelp-{$this->getModulePath()}-extended-description",
1843 'api-help-no-extended-description',
1844 ] ];
1845 }
1846
1854 public function getFinalSummary() {
1855 return $this->msg(
1856 Message::newFromSpecifier( $this->getSummaryMessage() ),
1857 $this->getModulePrefix(),
1858 $this->getModuleName(),
1859 $this->getModulePath(),
1860 );
1861 }
1862
1870 public function getFinalDescription() {
1871 $summary = $this->msg(
1872 Message::newFromSpecifier( $this->getSummaryMessage() ),
1873 $this->getModulePrefix(),
1874 $this->getModuleName(),
1875 $this->getModulePath(),
1876 );
1877 $extendedDesc = $this->getExtendedDescription();
1878 if ( is_array( $extendedDesc ) && is_array( $extendedDesc[0] ) ) {
1879 // The definition in getExtendedDescription() may also specify fallback keys. This is weird,
1880 // and it was never needed for other API doc messages, so it's only supported here.
1881 $extendedDesc = Message::newFallbackSequence( $extendedDesc[0] )
1882 ->params( array_slice( $extendedDesc, 1 ) );
1883 }
1884 $extendedDesc = $this->msg(
1885 Message::newFromSpecifier( $extendedDesc ),
1886 $this->getModulePrefix(),
1887 $this->getModuleName(),
1888 $this->getModulePath(),
1889 );
1890
1891 $msgs = [ $summary, $extendedDesc ];
1892
1893 $this->getHookRunner()->onAPIGetDescriptionMessages( $this, $msgs );
1894
1895 return $msgs;
1896 }
1897
1906 public function getFinalParams( $flags = 0 ) {
1907 // @phan-suppress-next-line PhanParamTooMany
1908 $params = $this->getAllowedParams( $flags );
1909 if ( !$params ) {
1910 $params = [];
1911 }
1912
1913 if ( $this->needsToken() ) {
1914 $params['token'] = [
1915 ParamValidator::PARAM_TYPE => 'string',
1916 ParamValidator::PARAM_REQUIRED => true,
1917 ParamValidator::PARAM_SENSITIVE => true,
1918 self::PARAM_HELP_MSG => [
1919 'api-help-param-token',
1920 $this->needsToken(),
1921 ],
1922 ] + ( $params['token'] ?? [] );
1923 }
1924
1925 $this->getHookRunner()->onAPIGetAllowedParams( $this, $params, $flags );
1926
1927 return $params;
1928 }
1929
1937 public function getFinalParamDescription() {
1938 $prefix = $this->getModulePrefix();
1939 $name = $this->getModuleName();
1940 $path = $this->getModulePath();
1941
1942 $params = $this->getFinalParams( self::GET_VALUES_FOR_HELP );
1943 $msgs = [];
1944 foreach ( $params as $param => $settings ) {
1945 if ( !is_array( $settings ) ) {
1946 $settings = [];
1947 }
1948
1949 $msg = isset( $settings[self::PARAM_HELP_MSG] )
1950 ? Message::newFromSpecifier( $settings[self::PARAM_HELP_MSG] )
1951 : Message::newFallbackSequence( [ "apihelp-$path-param-$param", 'api-help-param-no-description' ] );
1952 $msg = $this->msg( $msg, $prefix, $param, $name, $path );
1953 $msgs[$param] = [ $msg ];
1954
1955 if ( isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1956 $settings[ParamValidator::PARAM_TYPE] === 'submodule'
1957 ) {
1958 if ( isset( $settings[SubmoduleDef::PARAM_SUBMODULE_MAP] ) ) {
1959 $map = $settings[SubmoduleDef::PARAM_SUBMODULE_MAP];
1960 } else {
1961 $prefix = $this->isMain() ? '' : ( $this->getModulePath() . '+' );
1962 $map = [];
1963 foreach ( $this->getModuleManager()->getNames( $param ) as $submoduleName ) {
1964 $map[$submoduleName] = $prefix . $submoduleName;
1965 }
1966 }
1967
1968 $submodules = [];
1969 $submoduleFlags = []; // for sorting: higher flags are sorted later
1970 $submoduleNames = []; // for sorting: lexicographical, ascending
1971 foreach ( $map as $v => $m ) {
1972 $isDeprecated = false;
1973 $isInternal = false;
1974 $summary = null;
1975 try {
1976 $submod = $this->getModuleFromPath( $m );
1977 if ( $submod ) {
1978 $summary = $submod->getFinalSummary();
1979 $isDeprecated = $submod->isDeprecated();
1980 $isInternal = $submod->isInternal();
1981 if ( $isDeprecated ) {
1982 // Provide a deprecation message if available
1983 $isDeprecated = $submod->deprecationMsg() ??
1984 $isDeprecated;
1985 }
1986 }
1987 } catch ( ApiUsageException ) {
1988 // Ignore
1989 }
1990 if ( $summary ) {
1991 $key = $summary->getKey();
1992 $params = $summary->getParams();
1993 } else {
1994 $key = 'api-help-undocumented-module';
1995 $params = [ $m ];
1996 }
1997 $m = new ApiHelpParamValueMessage(
1998 "[[Special:ApiHelp/$m|$v]]",
1999 $key,
2000 $params,
2001 $isDeprecated,
2002 $isInternal
2003 );
2004 $submodules[] = $m->setContext( $this->getContext() );
2005 $submoduleFlags[] = ( $isDeprecated ? 1 : 0 ) | ( $isInternal ? 2 : 0 );
2006 $submoduleNames[] = $v;
2007 }
2008 // sort $submodules by $submoduleFlags and $submoduleNames
2009 array_multisort( $submoduleFlags, $submoduleNames, $submodules );
2010 $msgs[$param] = array_merge( $msgs[$param], $submodules );
2011 } elseif ( isset( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
2012 // ! keep these checks in sync with \MediaWiki\Api\Validator\ApiParamValidator::checkSettings
2013 if ( !is_array( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
2014 self::dieDebug( __METHOD__,
2015 'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
2016 }
2017 $isArrayOfStrings = is_array( $settings[ParamValidator::PARAM_TYPE] )
2018 || (
2019 $settings[ParamValidator::PARAM_TYPE] === 'string'
2020 && ( $settings[ParamValidator::PARAM_ISMULTI] ?? false )
2021 );
2022 if ( !$isArrayOfStrings ) {
2023 self::dieDebug( __METHOD__,
2024 'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
2025 'ParamValidator::PARAM_TYPE is an array or it is \'string\' and ' .
2026 'ParamValidator::PARAM_ISMULTI is true' );
2027 }
2028
2029 $values = is_array( $settings[ParamValidator::PARAM_TYPE] ) ?
2030 $settings[ParamValidator::PARAM_TYPE] :
2031 array_keys( $settings[self::PARAM_HELP_MSG_PER_VALUE] );
2032 $valueMsgs = $settings[self::PARAM_HELP_MSG_PER_VALUE];
2033 $deprecatedValues = $settings[EnumDef::PARAM_DEPRECATED_VALUES] ?? [];
2034 $internalValues = $settings[EnumDef::PARAM_INTERNAL_VALUES] ?? [];
2035
2036 foreach ( $values as $value ) {
2037 $msg = Message::newFromSpecifier( $valueMsgs[$value] ?? "apihelp-$path-paramvalue-$param-$value" );
2038 $m = $this->msg( $msg, [ $prefix, $param, $name, $path, $value ] );
2039 $deprecationMsg = $deprecatedValues[$value] ?? false;
2040 $deprecationMsg = (
2041 is_bool( $deprecationMsg ) || $deprecationMsg instanceof MessageSpecifier
2042 ) ? $deprecationMsg : ApiMessage::create( $deprecationMsg );
2043
2044 $m = new ApiHelpParamValueMessage(
2045 $value,
2046 // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal
2047 [ $m->getKey(), 'api-help-param-no-description' ],
2048 $m->getParams(),
2049 deprecated: $deprecationMsg,
2050 internal: $internalValues[$value] ?? false,
2051 );
2052 $msgs[$param][] = $m->setContext( $this->getContext() );
2053 }
2054 }
2055
2056 if ( isset( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
2057 if ( !is_array( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
2058 self::dieDebug( __METHOD__,
2059 'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
2060 }
2061 foreach ( $settings[self::PARAM_HELP_MSG_APPEND] as $m ) {
2062 $m = $this->msg( Message::newFromSpecifier( $m ), [ $prefix, $param, $name, $path ] );
2063 $msgs[$param][] = $m;
2064 }
2065 }
2066 }
2067
2068 $this->getHookRunner()->onAPIGetParamDescriptionMessages( $this, $msgs );
2069
2070 return $msgs;
2071 }
2072
2082 protected function getHelpFlags() {
2083 $flags = [];
2084
2085 if ( $this->isDeprecated() ) {
2086 $flags[] = 'deprecated';
2087 }
2088 if ( $this->isInternal() ) {
2089 $flags[] = 'internal';
2090 }
2091 if ( $this->isReadMode() ) {
2092 $flags[] = 'readrights';
2093 }
2094 if ( $this->isWriteMode() ) {
2095 $flags[] = 'writerights';
2096 }
2097 if ( $this->mustBePosted() ) {
2098 $flags[] = 'mustbeposted';
2099 }
2100
2101 return $flags;
2102 }
2103
2115 protected function getModuleSourceInfo() {
2116 if ( $this->mModuleSource !== false ) {
2117 return $this->mModuleSource;
2118 }
2119
2120 // First, try to find where the module comes from...
2121 $rClass = new ReflectionClass( $this );
2122 $path = $rClass->getFileName();
2123 if ( !$path ) {
2124 // No path known?
2125 $this->mModuleSource = null;
2126 return null;
2127 }
2128 $path = realpath( $path ) ?: $path;
2129
2130 // Build a map of extension directories to extension info
2131 if ( self::$extensionInfo === null ) {
2132 $extDir = $this->getConfig()->get( MainConfigNames::ExtensionDirectory );
2133 $baseDir = MW_INSTALL_PATH;
2134 self::$extensionInfo = [
2135 realpath( __DIR__ ) ?: __DIR__ => [
2136 'path' => $baseDir,
2137 'name' => 'MediaWiki',
2138 'license-name' => 'GPL-2.0-or-later',
2139 ],
2140 realpath( "$baseDir/extensions" ) ?: "$baseDir/extensions" => null,
2141 realpath( $extDir ) ?: $extDir => null,
2142 ];
2143 $keep = [
2144 'path' => null,
2145 'name' => null,
2146 'namemsg' => null,
2147 'license-name' => null,
2148 ];
2149 $credits = SpecialVersion::getCredits( ExtensionRegistry::getInstance(), $this->getConfig() );
2150 foreach ( $credits as $group ) {
2151 foreach ( $group as $ext ) {
2152 if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
2153 // This shouldn't happen, but does anyway.
2154 continue;
2155 }
2156
2157 $extpath = $ext['path'];
2158 if ( !is_dir( $extpath ) ) {
2159 $extpath = dirname( $extpath );
2160 }
2161 self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
2162 array_intersect_key( $ext, $keep );
2163 }
2164 }
2165 }
2166
2167 // Now traverse parent directories until we find a match or run out of parents.
2168 do {
2169 if ( array_key_exists( $path, self::$extensionInfo ) ) {
2170 // Found it!
2171 $this->mModuleSource = self::$extensionInfo[$path];
2172 return $this->mModuleSource;
2173 }
2174
2175 $oldpath = $path;
2176 $path = dirname( $path );
2177 } while ( $path !== $oldpath );
2178
2179 // No idea what extension this might be.
2180 $this->mModuleSource = null;
2181 return null;
2182 }
2183
2198 public function modifyHelp( array &$help, array $options, array &$tocData ) {
2199 wfDeprecated( __METHOD__, '1.47' );
2200 }
2201
2202 // endregion -- end of help message generation
2203
2204 /***************************************************************************/
2205 // region Data Unified metrics
2213 protected function recordUnifiedMetrics( $detailLabels = [] ) {
2214 // The concept of "module" is different in Action API and REST API
2215 // in REST API, it represents the "collection" of endpoints
2216 // in Action API, it represents the "module" of the API (or an endpoint)
2217 // In order to make the metrics consistent, we want the module to also reflect
2218 // the "collection" of endpoints. The closest we can get is to use the namespace
2219 // of the API module, and get the area of the code or extension it belongs to.
2220 // If module exists, we'll take the namespace for it, otherwise fall back on
2221 // the current namespace. In both cases we'll remove the class name to only keep
2222 // the namespace.
2223 // Since this method can also be called from module classes (ApiQuery, etc)
2224 // we need to allow for accepting the submodule's class name, too, if it's given.
2225 $fullClass = get_class( $this );
2226 $moduleNamespace = substr( $fullClass, 0, strrpos( $fullClass, '\\' ) );
2227
2228 // Get the endpoint representation, which for the moment is the module name.
2229 $endpoint = $this->getModuleName();
2230
2231 // The "path" should give us useful and consistent information about the endpoint.
2232 // The ->getModulePath() method should give us a string wih the module parent and
2233 // its own name, which should be enough to identify the endpoint and work with
2234 // RegEx patterns to extract information from the path.
2235 $path = $this->getModulePath();
2236
2237 // Unified metrics
2238 $metricsLabels = array_merge( [
2239 // This should represent the "collection" of endpoints
2240 'api_module' => $moduleNamespace,
2241 // This is the endpoint that is being executed
2242 'api_endpoint' => $endpoint,
2243 'path' => $path,
2244 'method' => $this->getRequest()->getMethod(),
2245 'status' => "200", // Success
2246 ], $detailLabels );
2247
2248 $approvedLabels = [
2249 'api_module',
2250 'api_endpoint',
2251 'path',
2252 'method',
2253 'status',
2254 ];
2255
2256 // Hit metrics
2257 $metricHitStats = $this->getMain()->getStatsFactory()->getCounter( 'action_api_modules_hit_total' )
2258 ->setLabel( 'api_type', 'ACTION_API' );
2259 foreach ( $approvedLabels as $label ) {
2260 // Set a fallback value for empty strings
2261 $value = (
2262 array_key_exists( $label, $metricsLabels ) &&
2263 is_string( $metricsLabels[$label] ) &&
2264 trim( $metricsLabels[$label] ) !== ''
2265 ) ? $metricsLabels[$label] : 'EMPTY_VALUE';
2266 $metricHitStats->setLabel( $label, $value );
2267 }
2268 $metricHitStats->increment();
2269 }
2270
2271 // endregion -- end of Unified metrics methods
2272}
2273
2274/*
2275 * This file uses VisualStudio style region/endregion fold markers which are
2276 * recognised by PHPStorm. If modelines are enabled, the following editor
2277 * configuration will also enable folding in vim, if it is in the last 5 lines
2278 * of the file. We also use "@name" which creates sections in Doxygen.
2279 *
2280 * vim: foldmarker=//\ region,//\ endregion foldmethod=marker
2281 */
2282
2284class_alias( ApiBase::class, 'ApiBase' );
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
wfTransactionalTimeLimit()
Raise the request time limit to $wgTransactionalTimeLimit.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
if(!defined('MW_SETUP_CALLBACK'))
Definition WebStart.php:71
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:60
const LIMIT_SML1
Slow query, standard limit.
Definition ApiBase.php:235
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1522
checkUserRightsAny( $rights)
Helper function for permission-denied errors.
Definition ApiBase.php:1631
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition ApiBase.php:2082
requirePostedParameters( $params, $prefix='prefix')
Die if any of the specified parameters were found in the query part of the URL rather than the HTTP p...
Definition ApiBase.php:1101
static clearCacheForTest()
Reset static caches of database state.
Definition ApiBase.php:1380
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition ApiBase.php:566
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
Definition ApiBase.php:397
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:557
getSummaryMessage()
Return the summary message.
Definition ApiBase.php:1825
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition ApiBase.php:781
const PARAM_VALUE_LINKS
Deprecated and unused.
Definition ApiBase.php:191
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
Definition ApiBase.php:184
requireAtLeastOneParameter( $params,... $required)
Die if 0 of a certain set of parameters is set and not false.
Definition ApiBase.php:1039
getMain()
Get the main module.
Definition ApiBase.php:575
getModulePath()
Get the path to this module.
Definition ApiBase.php:636
getParameterFromSettings( $name, $settings, $parseLimit)
Using the settings, determine the value for the given parameter.
Definition ApiBase.php:1231
const ALL_DEFAULT_STRING
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:228
requireNoConflictingParameters( $params, $trigger, $conflicts)
Die with an "invalid param mix" error if the parameters contain the trigger parameter and any of the ...
Definition ApiBase.php:1070
getWebUITokenSalt(array $params)
Fetch the salt used in the Web UI corresponding to this module.
Definition ApiBase.php:525
static makeMessage( $msg, IContextSource $context, ?array $params=null)
Create a Message from a string or array.
Definition ApiBase.php:1345
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition ApiBase.php:1746
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition ApiBase.php:1369
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
Definition ApiBase.php:1707
getHelpUrls()
Return links to more detailed help pages about the module.
Definition ApiBase.php:368
getModuleManager()
Get the module manager, or null if this module has no submodules.
Definition ApiBase.php:325
addMessagesFromStatus(StatusValue $status, $types=[ 'warning', 'error'], array $filter=[])
Add warnings and/or errors from a Status.
Definition ApiBase.php:1500
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition ApiBase.php:1307
getResult()
Get the result object.
Definition ApiBase.php:696
isReadMode()
Indicates whether this module requires read rights.
Definition ApiBase.php:407
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:206
getCustomPrinter()
If the module may only be used with a certain format module, it should override this method to return...
Definition ApiBase.php:341
logFeatureUsage( $feature)
Write logging information for API features to a debug log, for usage analysis.
Definition ApiBase.php:1770
getExtendedDescription()
Return the extended help text message.
Definition ApiBase.php:1840
isDeprecated()
Indicates whether this module is deprecated.
Definition ApiBase.php:463
requireMaxOneParameter( $params,... $required)
Dies if more than one parameter from a certain set of parameters are set and not false.
Definition ApiBase.php:1012
isInternal()
Indicates whether this module is considered to be "internal".
Definition ApiBase.php:488
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition ApiBase.php:1439
const PARAM_RANGE_ENFORCE
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition ApiBase.php:155
getFinalDescription()
Get the final module description, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1870
getParent()
Get the parent of this module.
Definition ApiBase.php:596
getDB()
Gets a default replica DB connection object.
Definition ApiBase.php:720
filterIDs( $fields, array $ids)
Filter out-of-range values from a list of positive integer IDs.
Definition ApiBase.php:1396
const LIMIT_SML2
Slow query, apihighlimits limit.
Definition ApiBase.php:237
__construct(ApiMain $mainModule, string $moduleName, string $modulePrefix='')
Definition ApiBase.php:286
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition ApiBase.php:174
recordUnifiedMetrics( $detailLabels=[])
Record unified metrics for the API.
Definition ApiBase.php:2213
setContinuationManager(?ApiContinuationManager $manager=null)
Definition ApiBase.php:743
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition ApiBase.php:623
dieWithException(Throwable $exception, array $options=[])
Abort execution with an error derived from a throwable.
Definition ApiBase.php:1535
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition ApiBase.php:1759
dieBlocked(Block $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
Definition ApiBase.php:1550
const PARAM_SUBMODULE_PARAM_PREFIX
Definition ApiBase.php:116
getTitleFromTitleOrPageId( $params)
Get a Title object from a title or pageid param, if it is possible.
Definition ApiBase.php:1199
const PARAM_TEMPLATE_VARS
(array) Indicate that this is a templated parameter, and specify replacements.
Definition ApiBase.php:224
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:166
addError( $msg, $code=null, $data=null)
Add an error for this module without aborting.
Definition ApiBase.php:1487
deprecationMsg()
Returns a MessageSpecifier describing the deprecation if this module is deprecated,...
Definition ApiBase.php:475
modifyHelp(array &$help, array $options, array &$tocData)
Called from ApiHelp before the pieces are joined together and returned.
Definition ApiBase.php:2198
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:233
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition ApiBase.php:815
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition ApiBase.php:385
getExamplesMessages()
Returns usage examples for this module.
Definition ApiBase.php:357
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition ApiBase.php:1454
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition ApiBase.php:1573
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition ApiBase.php:1259
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:837
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition ApiBase.php:756
getConditionalRequestData( $condition)
Returns data for HTTP conditional request mechanisms.
Definition ApiBase.php:542
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1937
getFinalParams( $flags=0)
Get the final list of parameters, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1906
dieWithErrorOrDebug( $msg, $code=null, $data=null, $httpCode=null)
Will only set a warning instead of failing if the global $wgDebugAPI is set to true.
Definition ApiBase.php:1689
getFinalSummary()
Get the final module summary.
Definition ApiBase.php:1854
const PARAM_DEPRECATED_VALUES
Definition ApiBase.php:132
dieReadOnly()
Helper function for readonly errors.
Definition ApiBase.php:1615
checkTitleUserPermissions(PageIdentity $pageIdentity, $actions, array $options=[])
Helper function for permission-denied errors.
Definition ApiBase.php:1654
needsToken()
Returns the token type this module requires in order to execute.
Definition ApiBase.php:511
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition ApiBase.php:803
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition ApiBase.php:2115
isWriteMode()
Indicates whether this module requires write access to the wiki.
Definition ApiBase.php:436
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition ApiBase.php:449
getTitleOrPageId( $params, $load=false)
Attempts to load a WikiPage object from a title or pageid parameter, if possible.
Definition ApiBase.php:1161
validateToken( $token, array $params)
Validate the supplied token.
Definition ApiBase.php:1271
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition ApiBase.php:585
getModuleFromPath( $path)
Get a module from its module path.
Definition ApiBase.php:656
requireOnlyOneParameter( $params,... $required)
Die if 0 or more than one of a certain set of parameters is set and not false.
Definition ApiBase.php:975
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition ApiBase.php:958
getHookContainer()
Get a HookContainer, for running extension hooks or for hook metadata.
Definition ApiBase.php:766
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When this is set, the result could take longer to generate,...
Definition ApiBase.php:244
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:231
Message subclass that prepends wikitext for API help.
This class provides an implementation of the hook interfaces used by the core Action API,...
This is the main API class, used for both external and internal processing.
Definition ApiMain.php:66
Exception used to abort API execution with an error.
Type definition for submodule types.
The simplest way of implementing IContextSource is to hold a RequestContext as a member variable and ...
setContext(IContextSource $context)
getContext()
Get the base IContextSource object.
Variant of the Message class.
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:144
setContext(IContextSource $context)
Set the language and the title from a context object.
Definition Message.php:870
Base representation for an editable wiki page.
Definition WikiPage.php:83
Type definition for namespace types.
A service class for checking permissions To obtain an instance, use MediaWikiServices::getInstance()-...
A StatusValue for permission errors.
Load JSON files, and uses a Processor to extract information.
Version information about MediaWiki (core, extensions, libs), PHP, and the database.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Definition Status.php:44
Represents a title within MediaWiki.
Definition Title.php:69
User class for the MediaWiki software.
Definition User.php:130
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Service for formatting and validating API parameters.
Type definition for enumeration types.
Definition EnumDef.php:32
Type definition for integer types.
Type definition for string types.
Definition StringDef.php:24
const PARAM_MAX_BYTES
(integer) Maximum length of a string in bytes.
Definition StringDef.php:39
const PARAM_MAX_CHARS
(integer) Maximum length of a string in characters (Unicode codepoints).
Definition StringDef.php:51
return[ 'config-schema-inverse'=>['default'=>['ConfigRegistry'=>['main'=> 'MediaWiki\\Config\\GlobalVarConfig::newInstance',], 'Sitename'=> 'MediaWiki', 'Server'=> false, 'CanonicalServer'=> false, 'ServerName'=> false, 'AssumeProxiesUseDefaultProtocolPorts'=> true, 'HttpsPort'=> 443, 'ForceHTTPS'=> false, 'ScriptPath'=> '/wiki', 'UsePathInfo'=> null, 'Script'=> false, 'LoadScript'=> false, 'RestPath'=> false, 'StylePath'=> false, 'LocalStylePath'=> false, 'ExtensionAssetsPath'=> false, 'ExtensionDirectory'=> null, 'StyleDirectory'=> null, 'ArticlePath'=> false, 'UploadPath'=> false, 'ImgAuthPath'=> false, 'ThumbPath'=> false, 'UploadDirectory'=> false, 'FileCacheDirectory'=> false, 'Logo'=> false, 'Logos'=> false, 'Favicon'=> '/favicon.ico', 'AppleTouchIcon'=> false, 'ReferrerPolicy'=> false, 'TmpDirectory'=> false, 'UploadBaseUrl'=> '', 'UploadStashScalerBaseUrl'=> false, 'ActionPaths'=>[], 'MainPageIsDomainRoot'=> false, 'EnableUploads'=> false, 'UploadStashMaxAge'=> 21600, 'EnableAsyncUploads'=> false, 'EnableAsyncUploadsByURL'=> false, 'UploadMaintenance'=> false, 'IllegalFileChars'=> ':\\/\\\\', 'DeletedDirectory'=> false, 'ImgAuthDetails'=> false, 'ImgAuthUrlPathMap'=>[], 'LocalFileRepo'=>['class'=> 'MediaWiki\\FileRepo\\LocalRepo', 'name'=> 'local', 'directory'=> null, 'scriptDirUrl'=> null, 'favicon'=> null, 'url'=> null, 'hashLevels'=> null, 'thumbScriptUrl'=> null, 'transformVia404'=> null, 'deletedDir'=> null, 'deletedHashLevels'=> null, 'updateCompatibleMetadata'=> null, 'reserializeMetadata'=> null,], 'ForeignFileRepos'=>[], 'UseInstantCommons'=> false, 'UseSharedUploads'=> false, 'SharedUploadDirectory'=> null, 'SharedUploadPath'=> null, 'HashedSharedUploadDirectory'=> true, 'RepositoryBaseUrl'=> 'https:'FetchCommonsDescriptions'=> false, 'SharedUploadDBname'=> false, 'SharedUploadDBprefix'=> '', 'CacheSharedUploads'=> true, 'ForeignUploadTargets'=>['local',], 'UploadDialog'=>['fields'=>['description'=> true, 'date'=> false, 'categories'=> false,], 'licensemessages'=>['local'=> 'generic-local', 'foreign'=> 'generic-foreign',], 'comment'=>['local'=> '', 'foreign'=> '',], 'format'=>['filepage'=> ' $DESCRIPTION', 'description'=> ' $TEXT', 'ownwork'=> '', 'license'=> '', 'uncategorized'=> '',],], 'FileBackends'=>[], 'LockManagers'=>[], 'DefaultLockManager'=> null, 'ShowEXIF'=> null, 'UpdateCompatibleMetadata'=> false, 'AllowCopyUploads'=> false, 'CopyUploadsDomains'=>[], 'CopyUploadsFromSpecialUpload'=> false, 'CopyUploadProxy'=> false, 'CopyUploadTimeout'=> false, 'CopyUploadAllowOnWikiDomainConfig'=> false, 'MaxUploadSize'=> 104857600, 'MinUploadChunkSize'=> 1024, 'UploadNavigationUrl'=> false, 'UploadMissingFileUrl'=> false, 'ThumbnailScriptPath'=> false, 'SharedThumbnailScriptPath'=> false, 'HashedUploadDirectory'=> true, 'CSPUploadEntryPoint'=> true, 'FileExtensions'=>['png', 'gif', 'jpg', 'jpeg', 'webp',], 'ProhibitedFileExtensions'=>['html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht', 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar', 'shtml', 'jhtml', 'pl', 'py', 'cgi', 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl', 'xml',], 'MimeTypeExclusions'=>['text/html', 'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile', 'application/java', 'application/xml', 'text/xml',], 'CheckFileExtensions'=> true, 'StrictFileExtensions'=> true, 'DisableUploadScriptChecks'=> false, 'UploadSizeWarning'=> false, 'TrustedMediaFormats'=>['BITMAP', 'AUDIO', 'VIDEO', 'image/svg+xml', 'application/pdf',], 'MediaHandlers'=>[], 'NativeImageLazyLoading'=> false, 'ParserTestMediaHandlers'=>['image/jpeg'=> 'MockBitmapHandler', 'image/png'=> 'MockBitmapHandler', 'image/gif'=> 'MockBitmapHandler', 'image/tiff'=> 'MockBitmapHandler', 'image/webp'=> 'MockBitmapHandler', 'image/x-ms-bmp'=> 'MockBitmapHandler', 'image/x-bmp'=> 'MockBitmapHandler', 'image/x-xcf'=> 'MockBitmapHandler', 'image/svg+xml'=> 'MockSvgHandler', 'image/vnd.djvu'=> 'MockDjVuHandler',], 'UseImageResize'=> true, 'UseImageMagick'=> false, 'ImageMagickConvertCommand'=> '/usr/bin/convert', 'MaxInterlacingAreas'=>[], 'SharpenParameter'=> '0x0.4', 'SharpenReductionThreshold'=> 0.85, 'ImageMagickTempDir'=> false, 'CustomConvertCommand'=> false, 'JpegTran'=> '/usr/bin/jpegtran', 'JpegPixelFormat'=> 'yuv420', 'JpegQuality'=> 80, 'Exiv2Command'=> '/usr/bin/exiv2', 'Exiftool'=> '/usr/bin/exiftool', 'SVGConverters'=>['ImageMagick'=> ' $path/convert -background "#ffffff00" -thumbnail $widthx$height\\! $input PNG:$output', 'inkscape'=> ' $path/inkscape -w $width -o $output $input', 'batik'=> 'java -Djava.awt.headless=true -jar $path/batik-rasterizer.jar -w $width -d $output $input', 'rsvg'=> ' $path/rsvg-convert -w $width -h $height -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 220, 250, 300, 400,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'TrackMediaRequestProvenance'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EmailConfirmationBanner'=> false, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'CodeHighlighter',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'EnableSectionShare'=> false, 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'NamespacesWithoutAutoSummaries' => [ ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider', 'services' => [ 'ConnectionProvider', 'UserFactory', ], 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'autocreateaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, 'createwithcontentmodel' => true, 'logout' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'createpreviouslyrenamedaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'RestrictUserPageEditing' => false, 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], 'managesessions' => [ 'logout' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', 'managesessions' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'ReauthenticateForActions' => [ 'edituserjs' => 'edituserjscss', 'editusercss' => 'edituserjscss', 'editsitejs' => 'editsitejscss', 'editsitecss' => 'editsitejscss', ], 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPUseReportURIDirective' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'ApiClientErrorSampleRate' => 1.0, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: 'https: 'git@github\\.com:(.*?)(\\.git)?' => 'https: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, 'mw-edited-other-users-js' => true, 'mw-edited-other-users-css' => true, ], 'RestrictedTagViewRights' => [ ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchstarPopover' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\RecentChanges\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Promise-Non-Write-API-Action', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'RestModuleOverrides' => [ ], 'RestExternalModules' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, 'ReturnExperimentalPFragmentTypes' => [ ], ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'DefaultLockManager' => [ 'string', 'null', ], 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EmailConfirmationBanner' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'NamespacesWithoutAutoSummaries' => 'array', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'RestrictUserPageEditing' => 'boolean', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'ReauthenticateForActions' => 'object', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPUseReportURIDirective' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RestrictedTagViewRights' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchstarPopover' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'RestModuleOverrides' => 'object', 'RestExternalModules' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', 'ReturnExperimentalPFragmentTypes' => 'array', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'RestModuleOverrides' => 'array_replace_recursive', 'RestExternalModules' => 'array_replace_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'UseCopyrightUpload' => [ 'deprecated' => 'since 1.47 This feature is being removed.', ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'file' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], ], ], 'RestModuleOverrides' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'mode' => [ 'type' => 'string', ], ], 'required' => [ 'mode', ], ], ], 'RestExternalModules' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'info' => [ 'type' => 'object', 'properties' => [ 'version' => [ 'type' => 'string', ], 'title' => [ 'type' => 'string', ], 'x-i18n-title' => [ 'type' => 'string', ], 'description' => [ 'type' => 'string', ], 'x-i18n-description' => [ 'type' => 'string', ], ], 'required' => [ 'version', ], ], 'base' => [ 'type' => 'string', 'format' => 'uri', ], 'spec' => [ 'type' => 'string', 'format' => 'uri', ], ], 'required' => [ 'info', 'base', 'spec', ], ], ], 'ShellboxUrls' => [ 'additionalProperties' => [ 'type' => [ 'string', 'boolean', 'null', ], ], ], ], 'obsolete-config' => [ 'MangleFlashPolicy' => 'Since 1.39; no longer has any effect.', 'EnableOpenSearchSuggest' => 'Since 1.35, no longer used', 'AutoloadAttemptLowercase' => 'Since 1.40; no longer has any effect.', ],]
Represents a block that may prevent users from performing specific operations.
Definition Block.php:31
Interface for objects which can provide a MediaWiki context on request.
Interface for objects (potentially) representing an editable wiki page.
Shared interface for rigor levels when dealing with User methods.
A database connection without write operations.