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
460 public function isDeprecated() {
461 return false;
462 }
463
473 public function isInternal() {
474 return false;
475 }
476
496 public function needsToken() {
497 return false;
498 }
499
510 protected function getWebUITokenSalt( array $params ) {
511 return null;
512 }
513
527 public function getConditionalRequestData( $condition ) {
528 return null;
529 }
530
531 // endregion -- end of methods to implement
532
533 /***************************************************************************/
534 // region Data access methods
542 public function getModuleName() {
543 return $this->mModuleName;
544 }
545
551 public function getModulePrefix() {
552 return $this->mModulePrefix;
553 }
554
560 public function getMain() {
561 return $this->mMainModule;
562 }
563
570 public function isMain() {
571 return $this === $this->mMainModule;
572 }
573
581 public function getParent() {
582 return $this->isMain() ? null : $this->getMain();
583 }
584
592 private function dieIfMain( string $methodName ) {
593 if ( $this->isMain() ) {
594 self::dieDebug( $methodName, 'base method was called on main module.' );
595 }
596 }
597
608 public function lacksSameOriginSecurity() {
609 // The Main module has this method overridden, avoid infinite loops
610 $this->dieIfMain( __METHOD__ );
611
612 return $this->getMain()->lacksSameOriginSecurity();
613 }
614
621 public function getModulePath() {
622 if ( $this->isMain() ) {
623 return 'main';
624 }
625
626 if ( $this->getParent()->isMain() ) {
627 return $this->getModuleName();
628 }
629
630 return $this->getParent()->getModulePath() . '+' . $this->getModuleName();
631 }
632
641 public function getModuleFromPath( $path ) {
642 $module = $this->getMain();
643 if ( $path === 'main' ) {
644 return $module;
645 }
646
647 $parts = explode( '+', $path );
648 if ( count( $parts ) === 1 ) {
649 // In case the '+' was typed into URL, it resolves as a space
650 $parts = explode( ' ', $path );
651 }
652
653 foreach ( $parts as $i => $v ) {
654 $parent = $module;
655 $manager = $parent->getModuleManager();
656 if ( $manager === null ) {
657 $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
658 $this->dieWithError( [ 'apierror-badmodule-nosubmodules', $errorPath ], 'badmodule' );
659 }
660 $module = $manager->getModule( $v );
661
662 if ( $module === null ) {
663 $errorPath = $i
664 ? implode( '+', array_slice( $parts, 0, $i ) )
665 : $parent->getModuleName();
666 $this->dieWithError(
667 [ 'apierror-badmodule-badsubmodule', $errorPath, wfEscapeWikiText( $v ) ],
668 'badmodule'
669 );
670 }
671 }
672
673 return $module;
674 }
675
681 public function getResult() {
682 // The Main module has this method overridden, avoid infinite loops
683 $this->dieIfMain( __METHOD__ );
684
685 return $this->getMain()->getResult();
686 }
687
692 public function getErrorFormatter() {
693 // The Main module has this method overridden, avoid infinite loops
694 $this->dieIfMain( __METHOD__ );
695
696 return $this->getMain()->getErrorFormatter();
697 }
698
705 protected function getDB() {
706 if ( !$this->mReplicaDB ) {
707 $this->mReplicaDB = MediaWikiServices::getInstance()
708 ->getConnectionProvider()
709 ->getReplicaDatabase();
710 }
711
712 return $this->mReplicaDB;
713 }
714
718 public function getContinuationManager() {
719 // The Main module has this method overridden, avoid infinite loops
720 $this->dieIfMain( __METHOD__ );
721
722 return $this->getMain()->getContinuationManager();
723 }
724
728 public function setContinuationManager( ?ApiContinuationManager $manager = null ) {
729 // The Main module has this method overridden, avoid infinite loops
730 $this->dieIfMain( __METHOD__ );
731
732 $this->getMain()->setContinuationManager( $manager );
733 }
734
743 }
744
751 protected function getHookContainer() {
752 if ( !$this->hookContainer ) {
753 $this->hookContainer = MediaWikiServices::getInstance()->getHookContainer();
754 }
755 return $this->hookContainer;
756 }
757
766 protected function getHookRunner() {
767 if ( !$this->hookRunner ) {
768 $this->hookRunner = new ApiHookRunner( $this->getHookContainer() );
769 }
770 return $this->hookRunner;
771 }
772
773 // endregion -- end of data access methods
774
775 /***************************************************************************/
776 // region Parameter handling
789 return null;
790 }
791
800 public function encodeParamName( $paramName ) {
801 if ( is_array( $paramName ) ) {
802 return array_map( function ( $name ) {
803 return $this->mModulePrefix . $name;
804 }, $paramName );
805 }
806
807 return $this->mModulePrefix . $paramName;
808 }
809
822 public function extractRequestParams( $options = [] ) {
823 if ( is_bool( $options ) ) {
824 $options = [ 'parseLimit' => $options ];
825 }
826 $options += [
827 'parseLimit' => true,
828 'safeMode' => false,
829 ];
830
831 $parseLimit = (bool)$options['parseLimit'];
832 $cacheKey = (int)$parseLimit;
833
834 // Cache parameters, for performance and to avoid T26564.
835 if ( !isset( $this->mParamCache[$cacheKey] ) ) {
836 $params = $this->getFinalParams() ?: [];
837 $results = [];
838 $warned = [];
839
840 // Process all non-templates and save templates for secondary
841 // processing.
842 $toProcess = [];
843 foreach ( $params as $paramName => $paramSettings ) {
844 if ( isset( $paramSettings[self::PARAM_TEMPLATE_VARS] ) ) {
845 $toProcess[] = [ $paramName, $paramSettings[self::PARAM_TEMPLATE_VARS], $paramSettings ];
846 } else {
847 try {
848 $results[$paramName] = $this->getParameterFromSettings(
849 $paramName, $paramSettings, $parseLimit
850 );
851 } catch ( ApiUsageException $ex ) {
852 $results[$paramName] = $ex;
853 }
854 }
855 }
856
857 // Now process all the templates by successively replacing the
858 // placeholders with all client-supplied values.
859 // This bit duplicates JavaScript logic in
860 // ApiSandbox.PageLayout.prototype.updateTemplatedParams().
861 // If you update this, see if that needs updating too.
862 while ( $toProcess ) {
863 [ $name, $targets, $settings ] = array_shift( $toProcess );
864
865 foreach ( $targets as $placeholder => $target ) {
866 if ( !array_key_exists( $target, $results ) ) {
867 // The target wasn't processed yet, try the next one.
868 // If all hit this case, the parameter has no expansions.
869 continue;
870 }
871 if ( !is_array( $results[$target] ) || !$results[$target] ) {
872 // The target was processed but has no (valid) values.
873 // That means it has no expansions.
874 break;
875 }
876
877 // Expand this target in the name and all other targets,
878 // then requeue if there are more targets left or put in
879 // $results if all are done.
880 unset( $targets[$placeholder] );
881 $placeholder = '{' . $placeholder . '}';
882 // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
883 foreach ( $results[$target] as $value ) {
884 if ( !preg_match( '/^[^{}]*$/', $value ) ) {
885 // Skip values that make invalid parameter names.
886 $encTargetName = $this->encodeParamName( $target );
887 if ( !isset( $warned[$encTargetName][$value] ) ) {
888 $warned[$encTargetName][$value] = true;
889 $this->addWarning( [
890 'apiwarn-ignoring-invalid-templated-value',
891 wfEscapeWikiText( $encTargetName ),
892 wfEscapeWikiText( $value ),
893 ] );
894 }
895 continue;
896 }
897
898 $newName = str_replace( $placeholder, $value, $name );
899 if ( !$targets ) {
900 try {
901 $results[$newName] = $this->getParameterFromSettings(
902 $newName,
903 $settings,
904 $parseLimit
905 );
906 } catch ( ApiUsageException $ex ) {
907 $results[$newName] = $ex;
908 }
909 } else {
910 $newTargets = [];
911 foreach ( $targets as $k => $v ) {
912 $newTargets[$k] = str_replace( $placeholder, $value, $v );
913 }
914 $toProcess[] = [ $newName, $newTargets, $settings ];
915 }
916 }
917 break;
918 }
919 }
920
921 $this->mParamCache[$cacheKey] = $results;
922 }
923
924 $ret = $this->mParamCache[$cacheKey];
925 if ( !$options['safeMode'] ) {
926 foreach ( $ret as $v ) {
927 if ( $v instanceof ApiUsageException ) {
928 throw $v;
929 }
930 }
931 }
932
933 return $this->mParamCache[$cacheKey];
934 }
935
943 protected function getParameter( $paramName, $parseLimit = true ) {
944 $ret = $this->extractRequestParams( [
945 'parseLimit' => $parseLimit,
946 'safeMode' => true,
947 ] )[$paramName];
948 if ( $ret instanceof ApiUsageException ) {
949 throw $ret;
950 }
951 return $ret;
952 }
953
960 public function requireOnlyOneParameter( $params, ...$required ) {
961 $intersection = array_intersect(
962 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
963 $required
964 );
965
966 if ( count( $intersection ) > 1 ) {
967 $this->dieWithError( [
968 'apierror-invalidparammix',
969 Message::listParam( array_map(
970 function ( $p ) {
971 return '<var>' . $this->encodeParamName( $p ) . '</var>';
972 },
973 array_values( $intersection )
974 ) ),
975 count( $intersection ),
976 ] );
977 } elseif ( count( $intersection ) == 0 ) {
978 $this->dieWithError( [
979 'apierror-missingparam-one-of',
980 Message::listParam( array_map(
981 function ( $p ) {
982 return '<var>' . $this->encodeParamName( $p ) . '</var>';
983 },
984 $required
985 ) ),
986 count( $required ),
987 ], 'missingparam' );
988 }
989 }
990
997 public function requireMaxOneParameter( $params, ...$required ) {
998 $intersection = array_intersect(
999 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1000 $required
1001 );
1002
1003 if ( count( $intersection ) > 1 ) {
1004 $this->dieWithError( [
1005 'apierror-invalidparammix',
1006 Message::listParam( array_map(
1007 function ( $p ) {
1008 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1009 },
1010 array_values( $intersection )
1011 ) ),
1012 count( $intersection ),
1013 ] );
1014 }
1015 }
1016
1024 public function requireAtLeastOneParameter( $params, ...$required ) {
1025 $intersection = array_intersect(
1026 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1027 $required
1028 );
1029
1030 if ( count( $intersection ) == 0 ) {
1031 $this->dieWithError( [
1032 'apierror-missingparam-at-least-one-of',
1033 Message::listParam( array_map(
1034 function ( $p ) {
1035 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1036 },
1037 $required
1038 ) ),
1039 count( $required ),
1040 ], 'missingparam' );
1041 }
1042 }
1043
1055 public function requireNoConflictingParameters( $params, $trigger, $conflicts ) {
1056 $triggerValue = $params[$trigger] ?? null;
1057 if ( $triggerValue === null || $triggerValue === false ) {
1058 return;
1059 }
1060 $intersection = array_intersect(
1061 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1062 (array)$conflicts
1063 );
1064 if ( count( $intersection ) ) {
1065 $this->dieWithError( [
1066 'apierror-invalidparammix-cannotusewith',
1067 Message::listParam( array_map(
1068 function ( $p ) {
1069 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1070 },
1071 array_values( $intersection )
1072 ) ),
1073 $trigger,
1074 ] );
1075 }
1076 }
1077
1086 public function requirePostedParameters( $params, $prefix = 'prefix' ) {
1087 if ( !$this->mustBePosted() ) {
1088 // In order to allow client code to choose the correct method (GET or POST) depending *only*
1089 // on mustBePosted(), make sure that the module requires posting if any of its potential
1090 // parameters require posting.
1091
1092 // TODO: Uncomment this
1093 // throw new LogicException( 'mustBePosted() must be true when using requirePostedParameters()' );
1094
1095 // This seems to already be the case in all modules in practice, but deprecate it first just
1096 // in case.
1097 wfDeprecatedMsg( 'mustBePosted() must be true when using requirePostedParameters()',
1098 '1.42' );
1099 }
1100
1101 // Skip if $wgDebugAPI is set, or if we're in internal mode
1102 if ( $this->getConfig()->get( MainConfigNames::DebugAPI ) ||
1103 $this->getMain()->isInternalMode() ) {
1104 return;
1105 }
1106
1107 $queryValues = $this->getRequest()->getQueryValuesOnly();
1108 $badParams = [];
1109 foreach ( $params as $param ) {
1110 if ( $prefix !== 'noprefix' ) {
1111 $param = $this->encodeParamName( $param );
1112 }
1113 if ( array_key_exists( $param, $queryValues ) ) {
1114 $badParams[] = $param;
1115 }
1116 }
1117
1118 if ( $badParams ) {
1119 $this->dieWithError(
1120 [ 'apierror-mustpostparams', implode( ', ', $badParams ), count( $badParams ) ]
1121 );
1122 }
1123 }
1124
1131 private function parameterNotEmpty( $x ) {
1132 return $x !== null && $x !== false;
1133 }
1134
1146 public function getTitleOrPageId( $params, $load = false ) {
1147 $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1148
1149 $pageObj = null;
1150 if ( isset( $params['title'] ) ) {
1151 $titleObj = Title::newFromText( $params['title'] );
1152 if ( !$titleObj || $titleObj->isExternal() ) {
1153 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1154 }
1155 if ( !$titleObj->canExist() ) {
1156 $this->dieWithError( 'apierror-pagecannotexist' );
1157 }
1158 $pageObj = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $titleObj );
1159 if ( $load !== false ) {
1160 $pageObj->loadPageData( $load );
1161 }
1162 } elseif ( isset( $params['pageid'] ) ) {
1163 if ( $load === false ) {
1164 $load = 'fromdb';
1165 }
1166 $pageObj = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromID( $params['pageid'], $load );
1167 if ( !$pageObj ) {
1168 $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1169 }
1170 }
1171
1172 // @phan-suppress-next-line PhanTypeMismatchReturnNullable requireOnlyOneParameter guard it is always set
1173 return $pageObj;
1174 }
1175
1184 public function getTitleFromTitleOrPageId( $params ) {
1185 $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1186
1187 $titleObj = null;
1188 if ( isset( $params['title'] ) ) {
1189 $titleObj = Title::newFromText( $params['title'] );
1190 if ( !$titleObj || $titleObj->isExternal() ) {
1191 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1192 }
1193 return $titleObj;
1194 }
1195
1196 if ( isset( $params['pageid'] ) ) {
1197 $titleObj = Title::newFromID( $params['pageid'] );
1198 if ( !$titleObj ) {
1199 $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1200 }
1201 }
1202
1203 // @phan-suppress-next-line PhanTypeMismatchReturnNullable requireOnlyOneParameter guard it is always set
1204 return $titleObj;
1205 }
1206
1216 protected function getParameterFromSettings( $name, $settings, $parseLimit ) {
1217 $validator = $this->getMain()->getParamValidator();
1218 $value = $validator->getValue( $this, $name, $settings, [
1219 'parse-limit' => $parseLimit,
1220 'raw' => ( $settings[ParamValidator::PARAM_TYPE] ?? '' ) === 'raw',
1221 ] );
1222
1223 // @todo Deprecate and remove this, if possible.
1224 if ( $parseLimit && isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1225 $settings[ParamValidator::PARAM_TYPE] === 'limit' &&
1226 $this->getMain()->getVal( $this->encodeParamName( $name ) ) === 'max'
1227 ) {
1228 $this->getResult()->addParsedLimit( $this->getModuleName(), $value );
1229 }
1230
1231 return $value;
1232 }
1233
1244 public function handleParamNormalization( $paramName, $value, $rawValue ) {
1245 $this->addWarning( [ 'apiwarn-badutf8', $paramName ] );
1246 }
1247
1256 final public function validateToken( $token, array $params ) {
1257 $tokenType = $this->needsToken();
1259 if ( !isset( $salts[$tokenType] ) ) {
1260 throw new LogicException(
1261 "Module '{$this->getModuleName()}' tried to use token type '$tokenType' " .
1262 'without registering it'
1263 );
1264 }
1265
1266 $tokenObj = ApiQueryTokens::getToken(
1267 $this->getUser(), $this->getRequest()->getSession(), $salts[$tokenType]
1268 );
1269 if ( $tokenObj->match( $token ) ) {
1270 return true;
1271 }
1272
1273 $webUiSalt = $this->getWebUITokenSalt( $params );
1274
1275 return $webUiSalt !== null && $this->getUser()->matchEditToken(
1276 $token, $webUiSalt, $this->getRequest()
1277 );
1278 }
1279
1280 // endregion -- end of parameter handling
1281
1282 /***************************************************************************/
1283 // region Utility methods
1292 public function getWatchlistUser( $params ) {
1293 if ( $params['owner'] !== null && $params['token'] !== null ) {
1294 $services = MediaWikiServices::getInstance();
1295 $user = $services->getUserFactory()->newFromName( $params['owner'], UserRigorOptions::RIGOR_NONE );
1296 if ( !$user || !$user->isRegistered() ) {
1297 $this->dieWithError(
1298 [ 'nosuchusershort', wfEscapeWikiText( $params['owner'] ) ], 'bad_wlowner'
1299 );
1300 }
1301 $token = $services->getUserOptionsLookup()->getOption( $user, 'watchlisttoken' );
1302 if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
1303 $this->dieWithError( 'apierror-bad-watchlist-token', 'bad_wltoken' );
1304 }
1305 } else {
1306 $user = $this->getUser();
1307 if ( !$user->isRegistered() ) {
1308 $this->dieWithError( 'watchlistanontext', 'notloggedin' );
1309 }
1310 $this->checkUserRightsAny( 'viewmywatchlist' );
1311 }
1312
1313 return $user;
1314 }
1315
1330 public static function makeMessage( $msg, IContextSource $context, ?array $params = null ) {
1331 wfDeprecated( __METHOD__, '1.43' );
1332 if ( is_string( $msg ) ) {
1333 $msg = wfMessage( $msg );
1334 } elseif ( is_array( $msg ) ) {
1335 $msg = wfMessage( ...$msg );
1336 }
1337 if ( !$msg instanceof Message ) {
1338 return null;
1339 }
1340
1341 $msg->setContext( $context );
1342 if ( $params ) {
1343 $msg->params( $params );
1344 }
1345
1346 return $msg;
1347 }
1348
1354 protected function useTransactionalTimeLimit() {
1355 if ( $this->getRequest()->wasPosted() ) {
1357 }
1358 }
1359
1365 public static function clearCacheForTest(): void {
1366 if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
1367 throw new LogicException( 'Not allowed outside tests' );
1368 }
1369 self::$filterIDsCache = [];
1370 }
1371
1381 protected function filterIDs( $fields, array $ids ) {
1382 $min = INF;
1383 $max = 0;
1384 foreach ( $fields as [ $table, $field ] ) {
1385 if ( isset( self::$filterIDsCache[$table][$field] ) ) {
1386 $row = self::$filterIDsCache[$table][$field];
1387 } else {
1388 $row = $this->getDB()->newSelectQueryBuilder()
1389 ->select( [ 'min_id' => "MIN($field)", 'max_id' => "MAX($field)" ] )
1390 ->from( $table )
1391 ->caller( __METHOD__ )->fetchRow();
1392 self::$filterIDsCache[$table][$field] = $row;
1393 }
1394 $min = min( $min, $row->min_id );
1395 $max = max( $max, $row->max_id );
1396 }
1397 return array_filter( $ids, static function ( $id ) use ( $min, $max ) {
1398 return ( ( is_int( $id ) && $id >= 0 ) || ctype_digit( (string)$id ) )
1399 && $id >= $min && $id <= $max;
1400 } );
1401 }
1402
1403 // endregion -- end of utility methods
1404
1405 /***************************************************************************/
1406 // region Warning and error reporting
1424 public function addWarning( $msg, $code = null, $data = null ) {
1425 $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg, $code, $data );
1426 }
1427
1438 public function addDeprecation( $msg, $feature, $data = [] ) {
1439 $data = (array)$data;
1440 if ( $feature !== null ) {
1441 $data['feature'] = $feature;
1442 $this->logFeatureUsage( $feature );
1443 }
1444 $this->addWarning( $msg, 'deprecation', $data );
1445
1446 // No real need to deduplicate here, ApiErrorFormatter does that for
1447 // us (assuming the hook is deterministic).
1448 $msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
1449 $this->getHookRunner()->onApiDeprecationHelp( $msgs );
1450 if ( count( $msgs ) > 1 ) {
1451 $key = '$' . implode( ' $', range( 1, count( $msgs ) ) );
1452 $msg = ( new RawMessage( $key ) )->params( $msgs );
1453 } else {
1454 $msg = reset( $msgs );
1455 }
1456 $this->getMain()->addWarning( $msg, 'deprecation-help' );
1457 }
1458
1471 public function addError( $msg, $code = null, $data = null ) {
1472 $this->getErrorFormatter()->addError( $this->getModulePath(), $msg, $code, $data );
1473 }
1474
1484 public function addMessagesFromStatus(
1485 StatusValue $status, $types = [ 'warning', 'error' ], array $filter = []
1486 ) {
1487 $this->getErrorFormatter()->addMessagesFromStatus(
1488 $this->getModulePath(), $status, $types, $filter
1489 );
1490 }
1491
1506 public function dieWithError( $msg, $code = null, $data = null, $httpCode = 0 ): never {
1507 throw ApiUsageException::newWithMessage( $this, $msg, $code, $data, $httpCode );
1508 }
1509
1519 public function dieWithException( Throwable $exception, array $options = [] ): never {
1520 $this->dieWithError(
1521 $this->getErrorFormatter()->getMessageFromException( $exception, $options )
1522 );
1523 }
1524
1534 public function dieBlocked( Block $block ): never {
1535 $blockErrorFormatter = MediaWikiServices::getInstance()->getFormatterFactory()
1536 ->getBlockErrorFormatter( $this->getContext() );
1537
1538 $msg = $blockErrorFormatter->getMessage(
1539 $block,
1540 $this->getUser(),
1541 null,
1542 $this->getRequest()->getIP()
1543 );
1544
1545 $this->dieWithError( $msg );
1546 }
1547
1557 public function dieStatus( StatusValue $status ): never {
1558 if ( $status->isGood() ) {
1559 throw new InvalidArgumentException( 'Successful status passed to ApiBase::dieStatus' );
1560 }
1561
1562 foreach ( self::MESSAGE_CODE_MAP as $msg => [ $apiMsg, $code ] ) {
1563 if ( $status->hasMessage( $msg ) ) {
1564 $status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code ) );
1565 }
1566 }
1567
1568 if (
1569 $status instanceof PermissionStatus
1570 && $status->isRateLimitExceeded()
1571 && !$status->hasMessage( 'apierror-ratelimited' )
1572 ) {
1573 $status->fatal( ApiMessage::create( 'apierror-ratelimited', 'ratelimited' ) );
1574 }
1575
1576 // ApiUsageException needs a fatal status, but this method has
1577 // historically accepted any non-good status. Convert it if necessary.
1578 $status->setOK( false );
1579 if ( !$status->getMessages( 'error' ) ) {
1580 $newStatus = Status::newGood();
1581 foreach ( $status->getMessages( 'warning' ) as $err ) {
1582 $newStatus->fatal( $err );
1583 }
1584 if ( !$newStatus->getMessages( 'error' ) ) {
1585 $newStatus->fatal( 'unknownerror-nocode' );
1586 }
1587 $status = $newStatus;
1588 }
1589
1590 throw new ApiUsageException( $this, $status );
1591 }
1592
1599 public function dieReadOnly(): never {
1600 $this->dieWithError(
1601 'apierror-readonly',
1602 'readonly',
1603 [ 'readonlyreason' => MediaWikiServices::getInstance()->getReadOnlyMode()->getReason() ]
1604 );
1605 }
1606
1615 public function checkUserRightsAny( $rights ) {
1616 $rights = (array)$rights;
1617 if ( !$this->getAuthority()->isAllowedAny( ...$rights ) ) {
1618 $this->dieWithError( [ 'apierror-permissiondenied', $this->msg( "action-{$rights[0]}" ) ] );
1619 }
1620 }
1621
1639 PageIdentity $pageIdentity,
1640 $actions,
1641 array $options = []
1642 ) {
1643 $authority = $options['user'] ?? $this->getAuthority();
1644 $status = new PermissionStatus();
1645 foreach ( (array)$actions as $action ) {
1646 if ( $this->isWriteMode() ) {
1647 $authority->authorizeWrite( $action, $pageIdentity, $status );
1648 } else {
1649 $authority->authorizeRead( $action, $pageIdentity, $status );
1650 }
1651 }
1652 if ( !$status->isGood() ) {
1653 if ( !empty( $options['autoblock'] ) ) {
1654 $this->getUser()->spreadAnyEditBlock();
1655 }
1656 $this->dieStatus( $status );
1657 }
1658 }
1659
1673 public function dieWithErrorOrDebug( $msg, $code = null, $data = null, $httpCode = null ) {
1674 if ( $this->getConfig()->get( MainConfigNames::DebugAPI ) !== true ) {
1675 $this->dieWithError( $msg, $code, $data, $httpCode ?? 0 );
1676 } else {
1677 $this->addWarning( $msg, $code, $data );
1678 }
1679 }
1680
1691 protected function parseContinueParamOrDie( string $continue, array $types ): array {
1692 $cont = explode( '|', $continue );
1693 $this->dieContinueUsageIf( count( $cont ) != count( $types ) );
1694
1695 foreach ( $cont as $i => &$value ) {
1696 switch ( $types[$i] ) {
1697 case 'string':
1698 // Do nothing
1699 break;
1700 case 'int':
1701 $this->dieContinueUsageIf( $value !== (string)(int)$value );
1702 $value = (int)$value;
1703 break;
1704 case 'timestamp':
1705 try {
1706 $dbTs = $this->getDB()->timestamp( $value );
1707 } catch ( TimestampException ) {
1708 $dbTs = false;
1709 }
1710 $this->dieContinueUsageIf( $value !== $dbTs );
1711 break;
1712 default:
1713 throw new InvalidArgumentException( "Unknown type '{$types[$i]}'" );
1714 }
1715 }
1716
1717 return $cont;
1718 }
1719
1730 protected function dieContinueUsageIf( $condition ) {
1731 if ( $condition ) {
1732 $this->dieWithError( 'apierror-badcontinue' );
1733 }
1734 }
1735
1743 protected static function dieDebug( $method, $message ): never {
1744 throw new LogicException( "Internal error in $method: $message" );
1745 }
1746
1754 public function logFeatureUsage( $feature ) {
1755 static $loggedFeatures = [];
1756
1757 // Only log each feature once per request. We can get multiple calls from calls to
1758 // extractRequestParams() with different values for 'parseLimit', for example.
1759 if ( isset( $loggedFeatures[$feature] ) ) {
1760 return;
1761 }
1762 $loggedFeatures[$feature] = true;
1763
1764 $request = $this->getRequest();
1765 $ctx = [
1766 'feature' => $feature,
1767 // Replace spaces with underscores in 'username' for historical reasons.
1768 'username' => str_replace( ' ', '_', $this->getUser()->getName() ),
1769 'clientip' => $request->getIP(),
1770 'referer' => (string)$request->getHeader( 'Referer' ),
1771 'agent' => $this->getMain()->getUserAgent(),
1772 ];
1773
1774 // Text string is deprecated. Remove (or replace with just $feature) in MW 1.34.
1775 $s = '"' . addslashes( $ctx['feature'] ) . '"' .
1776 ' "' . wfUrlencode( $ctx['username'] ) . '"' .
1777 ' "' . $ctx['clientip'] . '"' .
1778 ' "' . addslashes( $ctx['referer'] ) . '"' .
1779 ' "' . addslashes( $ctx['agent'] ) . '"';
1780
1781 wfDebugLog( 'api-feature-usage', $s, 'private', $ctx );
1782
1783 $this->getHookRunner()->onApiLogFeatureUsage(
1784 $feature,
1785 [
1786 'userName' => $this->getUser()->getName(),
1787 'userAgent' => $this->getMain()->getUserAgent(),
1788 'ipAddress' => $request->getIP()
1789 ]
1790 );
1791 }
1792
1793 // endregion -- end of warning and error reporting
1794
1795 /***************************************************************************/
1796 // region Help message generation
1809 protected function getSummaryMessage() {
1810 return "apihelp-{$this->getModulePath()}-summary";
1811 }
1812
1824 protected function getExtendedDescription() {
1825 return [ [
1826 "apihelp-{$this->getModulePath()}-extended-description",
1827 'api-help-no-extended-description',
1828 ] ];
1829 }
1830
1838 public function getFinalSummary() {
1839 return $this->msg(
1840 Message::newFromSpecifier( $this->getSummaryMessage() ),
1841 $this->getModulePrefix(),
1842 $this->getModuleName(),
1843 $this->getModulePath(),
1844 );
1845 }
1846
1854 public function getFinalDescription() {
1855 $summary = $this->msg(
1856 Message::newFromSpecifier( $this->getSummaryMessage() ),
1857 $this->getModulePrefix(),
1858 $this->getModuleName(),
1859 $this->getModulePath(),
1860 );
1861 $extendedDesc = $this->getExtendedDescription();
1862 if ( is_array( $extendedDesc ) && is_array( $extendedDesc[0] ) ) {
1863 // The definition in getExtendedDescription() may also specify fallback keys. This is weird,
1864 // and it was never needed for other API doc messages, so it's only supported here.
1865 $extendedDesc = Message::newFallbackSequence( $extendedDesc[0] )
1866 ->params( array_slice( $extendedDesc, 1 ) );
1867 }
1868 $extendedDesc = $this->msg(
1869 Message::newFromSpecifier( $extendedDesc ),
1870 $this->getModulePrefix(),
1871 $this->getModuleName(),
1872 $this->getModulePath(),
1873 );
1874
1875 $msgs = [ $summary, $extendedDesc ];
1876
1877 $this->getHookRunner()->onAPIGetDescriptionMessages( $this, $msgs );
1878
1879 return $msgs;
1880 }
1881
1890 public function getFinalParams( $flags = 0 ) {
1891 // @phan-suppress-next-line PhanParamTooMany
1892 $params = $this->getAllowedParams( $flags );
1893 if ( !$params ) {
1894 $params = [];
1895 }
1896
1897 if ( $this->needsToken() ) {
1898 $params['token'] = [
1899 ParamValidator::PARAM_TYPE => 'string',
1900 ParamValidator::PARAM_REQUIRED => true,
1901 ParamValidator::PARAM_SENSITIVE => true,
1902 self::PARAM_HELP_MSG => [
1903 'api-help-param-token',
1904 $this->needsToken(),
1905 ],
1906 ] + ( $params['token'] ?? [] );
1907 }
1908
1909 $this->getHookRunner()->onAPIGetAllowedParams( $this, $params, $flags );
1910
1911 return $params;
1912 }
1913
1921 public function getFinalParamDescription() {
1922 $prefix = $this->getModulePrefix();
1923 $name = $this->getModuleName();
1924 $path = $this->getModulePath();
1925
1926 $params = $this->getFinalParams( self::GET_VALUES_FOR_HELP );
1927 $msgs = [];
1928 foreach ( $params as $param => $settings ) {
1929 if ( !is_array( $settings ) ) {
1930 $settings = [];
1931 }
1932
1933 $msg = isset( $settings[self::PARAM_HELP_MSG] )
1934 ? Message::newFromSpecifier( $settings[self::PARAM_HELP_MSG] )
1935 : Message::newFallbackSequence( [ "apihelp-$path-param-$param", 'api-help-param-no-description' ] );
1936 $msg = $this->msg( $msg, $prefix, $param, $name, $path );
1937 $msgs[$param] = [ $msg ];
1938
1939 if ( isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1940 $settings[ParamValidator::PARAM_TYPE] === 'submodule'
1941 ) {
1942 if ( isset( $settings[SubmoduleDef::PARAM_SUBMODULE_MAP] ) ) {
1943 $map = $settings[SubmoduleDef::PARAM_SUBMODULE_MAP];
1944 } else {
1945 $prefix = $this->isMain() ? '' : ( $this->getModulePath() . '+' );
1946 $map = [];
1947 foreach ( $this->getModuleManager()->getNames( $param ) as $submoduleName ) {
1948 $map[$submoduleName] = $prefix . $submoduleName;
1949 }
1950 }
1951
1952 $submodules = [];
1953 $submoduleFlags = []; // for sorting: higher flags are sorted later
1954 $submoduleNames = []; // for sorting: lexicographical, ascending
1955 foreach ( $map as $v => $m ) {
1956 $isDeprecated = false;
1957 $isInternal = false;
1958 $summary = null;
1959 try {
1960 $submod = $this->getModuleFromPath( $m );
1961 if ( $submod ) {
1962 $summary = $submod->getFinalSummary();
1963 $isDeprecated = $submod->isDeprecated();
1964 $isInternal = $submod->isInternal();
1965 }
1966 } catch ( ApiUsageException ) {
1967 // Ignore
1968 }
1969 if ( $summary ) {
1970 $key = $summary->getKey();
1971 $params = $summary->getParams();
1972 } else {
1973 $key = 'api-help-undocumented-module';
1974 $params = [ $m ];
1975 }
1976 $m = new ApiHelpParamValueMessage(
1977 "[[Special:ApiHelp/$m|$v]]",
1978 $key,
1979 $params,
1980 $isDeprecated,
1981 $isInternal
1982 );
1983 $submodules[] = $m->setContext( $this->getContext() );
1984 $submoduleFlags[] = ( $isDeprecated ? 1 : 0 ) | ( $isInternal ? 2 : 0 );
1985 $submoduleNames[] = $v;
1986 }
1987 // sort $submodules by $submoduleFlags and $submoduleNames
1988 array_multisort( $submoduleFlags, $submoduleNames, $submodules );
1989 $msgs[$param] = array_merge( $msgs[$param], $submodules );
1990 } elseif ( isset( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1991 // ! keep these checks in sync with \MediaWiki\Api\Validator\ApiParamValidator::checkSettings
1992 if ( !is_array( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1993 self::dieDebug( __METHOD__,
1994 'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
1995 }
1996 $isArrayOfStrings = is_array( $settings[ParamValidator::PARAM_TYPE] )
1997 || (
1998 $settings[ParamValidator::PARAM_TYPE] === 'string'
1999 && ( $settings[ParamValidator::PARAM_ISMULTI] ?? false )
2000 );
2001 if ( !$isArrayOfStrings ) {
2002 self::dieDebug( __METHOD__,
2003 'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
2004 'ParamValidator::PARAM_TYPE is an array or it is \'string\' and ' .
2005 'ParamValidator::PARAM_ISMULTI is true' );
2006 }
2007
2008 $values = is_array( $settings[ParamValidator::PARAM_TYPE] ) ?
2009 $settings[ParamValidator::PARAM_TYPE] :
2010 array_keys( $settings[self::PARAM_HELP_MSG_PER_VALUE] );
2011 $valueMsgs = $settings[self::PARAM_HELP_MSG_PER_VALUE];
2012 $deprecatedValues = $settings[EnumDef::PARAM_DEPRECATED_VALUES] ?? [];
2013
2014 foreach ( $values as $value ) {
2015 $msg = Message::newFromSpecifier( $valueMsgs[$value] ?? "apihelp-$path-paramvalue-$param-$value" );
2016 $m = $this->msg( $msg, [ $prefix, $param, $name, $path, $value ] );
2017 $m = new ApiHelpParamValueMessage(
2018 $value,
2019 // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal
2020 [ $m->getKey(), 'api-help-param-no-description' ],
2021 $m->getParams(),
2022 isset( $deprecatedValues[$value] )
2023 );
2024 $msgs[$param][] = $m->setContext( $this->getContext() );
2025 }
2026 }
2027
2028 if ( isset( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
2029 if ( !is_array( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
2030 self::dieDebug( __METHOD__,
2031 'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
2032 }
2033 foreach ( $settings[self::PARAM_HELP_MSG_APPEND] as $m ) {
2034 $m = $this->msg( Message::newFromSpecifier( $m ), [ $prefix, $param, $name, $path ] );
2035 $msgs[$param][] = $m;
2036 }
2037 }
2038 }
2039
2040 $this->getHookRunner()->onAPIGetParamDescriptionMessages( $this, $msgs );
2041
2042 return $msgs;
2043 }
2044
2054 protected function getHelpFlags() {
2055 $flags = [];
2056
2057 if ( $this->isDeprecated() ) {
2058 $flags[] = 'deprecated';
2059 }
2060 if ( $this->isInternal() ) {
2061 $flags[] = 'internal';
2062 }
2063 if ( $this->isReadMode() ) {
2064 $flags[] = 'readrights';
2065 }
2066 if ( $this->isWriteMode() ) {
2067 $flags[] = 'writerights';
2068 }
2069 if ( $this->mustBePosted() ) {
2070 $flags[] = 'mustbeposted';
2071 }
2072
2073 return $flags;
2074 }
2075
2087 protected function getModuleSourceInfo() {
2088 if ( $this->mModuleSource !== false ) {
2089 return $this->mModuleSource;
2090 }
2091
2092 // First, try to find where the module comes from...
2093 $rClass = new ReflectionClass( $this );
2094 $path = $rClass->getFileName();
2095 if ( !$path ) {
2096 // No path known?
2097 $this->mModuleSource = null;
2098 return null;
2099 }
2100 $path = realpath( $path ) ?: $path;
2101
2102 // Build a map of extension directories to extension info
2103 if ( self::$extensionInfo === null ) {
2104 $extDir = $this->getConfig()->get( MainConfigNames::ExtensionDirectory );
2105 $baseDir = MW_INSTALL_PATH;
2106 self::$extensionInfo = [
2107 realpath( __DIR__ ) ?: __DIR__ => [
2108 'path' => $baseDir,
2109 'name' => 'MediaWiki',
2110 'license-name' => 'GPL-2.0-or-later',
2111 ],
2112 realpath( "$baseDir/extensions" ) ?: "$baseDir/extensions" => null,
2113 realpath( $extDir ) ?: $extDir => null,
2114 ];
2115 $keep = [
2116 'path' => null,
2117 'name' => null,
2118 'namemsg' => null,
2119 'license-name' => null,
2120 ];
2121 $credits = SpecialVersion::getCredits( ExtensionRegistry::getInstance(), $this->getConfig() );
2122 foreach ( $credits as $group ) {
2123 foreach ( $group as $ext ) {
2124 if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
2125 // This shouldn't happen, but does anyway.
2126 continue;
2127 }
2128
2129 $extpath = $ext['path'];
2130 if ( !is_dir( $extpath ) ) {
2131 $extpath = dirname( $extpath );
2132 }
2133 self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
2134 array_intersect_key( $ext, $keep );
2135 }
2136 }
2137 }
2138
2139 // Now traverse parent directories until we find a match or run out of parents.
2140 do {
2141 if ( array_key_exists( $path, self::$extensionInfo ) ) {
2142 // Found it!
2143 $this->mModuleSource = self::$extensionInfo[$path];
2144 return $this->mModuleSource;
2145 }
2146
2147 $oldpath = $path;
2148 $path = dirname( $path );
2149 } while ( $path !== $oldpath );
2150
2151 // No idea what extension this might be.
2152 $this->mModuleSource = null;
2153 return null;
2154 }
2155
2168 public function modifyHelp( array &$help, array $options, array &$tocData ) {
2169 }
2170
2171 // endregion -- end of help message generation
2172
2173 /***************************************************************************/
2174 // region Data Unified metrics
2183 protected function recordUnifiedMetrics( $latency = 0, $detailLabels = [] ) {
2184 // The concept of "module" is different in Action API and REST API
2185 // in REST API, it represents the "collection" of endpoints
2186 // in Action API, it represents the "module" of the API (or an endpoint)
2187 // In order to make the metrics consistent, we want the module to also reflect
2188 // the "collection" of endpoints. The closest we can get is to use the namespace
2189 // of the API module, and get the area of the code or extension it belongs to.
2190 // If module exists, we'll take the namespace for it, otherwise fall back on
2191 // the current namespace. In both cases we'll remove the class name to only keep
2192 // the namespace.
2193 // Since this method can also be called from module classes (ApiQuery, etc)
2194 // we need to allow for accepting the submodule's class name, too, if it's given.
2195 $fullClass = get_class( $this );
2196 $moduleNamespace = substr( $fullClass, 0, strrpos( $fullClass, '\\' ) );
2197
2198 // Get the endpoint representation, which for the moment is the module name.
2199 $endpoint = $this->getModuleName();
2200
2201 // The "path" should give us useful and consistent information about the endpoint.
2202 // The ->getModulePath() method should give us a string wih the module parent and
2203 // its own name, which should be enough to identify the endpoint and work with
2204 // RegEx patterns to extract information from the path.
2205 $path = $this->getModulePath();
2206
2207 // Unified metrics
2208 $metricsLabels = array_merge( [
2209 // This should represent the "collection" of endpoints
2210 'api_module' => $moduleNamespace,
2211 // This is the endpoint that is being executed
2212 'api_endpoint' => $endpoint,
2213 'path' => $path,
2214 'method' => $this->getRequest()->getMethod(),
2215 'status' => "200", // Success
2216 ], $detailLabels );
2217
2218 $approvedLabels = [
2219 'api_module',
2220 'api_endpoint',
2221 'path',
2222 'method',
2223 'status',
2224 ];
2225
2226 // Hit metrics
2227 $metricHitStats = $this->getMain()->getStatsFactory()->getCounter( 'action_api_modules_hit_total' )
2228 ->setLabel( 'api_type', 'ACTION_API' );
2229 foreach ( $approvedLabels as $label ) {
2230 // Set a fallback value for empty strings
2231 $value = (
2232 array_key_exists( $label, $metricsLabels ) &&
2233 is_string( $metricsLabels[$label] ) &&
2234 trim( $metricsLabels[$label] ) !== ''
2235 ) ? $metricsLabels[$label] : 'EMPTY_VALUE';
2236 $metricHitStats->setLabel( $label, $value );
2237 }
2238 $metricHitStats->increment();
2239
2240 // Latency metrics
2241 $metricLatencyStats = $this->getMain()->getStatsFactory()->getTiming( 'action_api_modules_latency' )
2242 ->setLabel( 'api_type', 'ACTION_API' );
2243 // Iterate over the approved labels and set the labels for the metric
2244 foreach ( $approvedLabels as $label ) {
2245 // Set a fallback value for empty strings
2246 $value = (
2247 array_key_exists( $label, $metricsLabels ) &&
2248 is_string( $metricsLabels[$label] ) &&
2249 trim( $metricsLabels[$label] ) !== ''
2250 ) ? $metricsLabels[$label] : 'EMPTY_VALUE';
2251
2252 $metricLatencyStats->setLabel( $label, $value );
2253 }
2254 $metricLatencyStats->observeNanoseconds( $latency );
2255 }
2256
2257 // endregion -- end of Unified metrics methods
2258}
2259
2260/*
2261 * This file uses VisualStudio style region/endregion fold markers which are
2262 * recognised by PHPStorm. If modelines are enabled, the following editor
2263 * configuration will also enable folding in vim, if it is in the last 5 lines
2264 * of the file. We also use "@name" which creates sections in Doxygen.
2265 *
2266 * vim: foldmarker=//\ region,//\ endregion foldmethod=marker
2267 */
2268
2270class_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:69
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:1506
checkUserRightsAny( $rights)
Helper function for permission-denied errors.
Definition ApiBase.php:1615
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition ApiBase.php:2054
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:1086
static clearCacheForTest()
Reset static caches of database state.
Definition ApiBase.php:1365
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition ApiBase.php:551
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:542
getSummaryMessage()
Return the summary message.
Definition ApiBase.php:1809
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition ApiBase.php:766
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:1024
getMain()
Get the main module.
Definition ApiBase.php:560
getModulePath()
Get the path to this module.
Definition ApiBase.php:621
getParameterFromSettings( $name, $settings, $parseLimit)
Using the settings, determine the value for the given parameter.
Definition ApiBase.php:1216
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:1055
getWebUITokenSalt(array $params)
Fetch the salt used in the Web UI corresponding to this module.
Definition ApiBase.php:510
static makeMessage( $msg, IContextSource $context, ?array $params=null)
Create a Message from a string or array.
Definition ApiBase.php:1330
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition ApiBase.php:1730
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition ApiBase.php:1354
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
Definition ApiBase.php:1691
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:1484
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition ApiBase.php:1292
getResult()
Get the result object.
Definition ApiBase.php:681
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:1754
getExtendedDescription()
Return the extended help text message.
Definition ApiBase.php:1824
isDeprecated()
Indicates whether this module is deprecated.
Definition ApiBase.php:460
requireMaxOneParameter( $params,... $required)
Dies if more than one parameter from a certain set of parameters are set and not false.
Definition ApiBase.php:997
isInternal()
Indicates whether this module is considered to be "internal".
Definition ApiBase.php:473
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition ApiBase.php:1424
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:1854
getParent()
Get the parent of this module.
Definition ApiBase.php:581
getDB()
Gets a default replica DB connection object.
Definition ApiBase.php:705
filterIDs( $fields, array $ids)
Filter out-of-range values from a list of positive integer IDs.
Definition ApiBase.php:1381
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
setContinuationManager(?ApiContinuationManager $manager=null)
Definition ApiBase.php:728
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition ApiBase.php:608
dieWithException(Throwable $exception, array $options=[])
Abort execution with an error derived from a throwable.
Definition ApiBase.php:1519
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition ApiBase.php:1743
dieBlocked(Block $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
Definition ApiBase.php:1534
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:1184
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:1471
modifyHelp(array &$help, array $options, array &$tocData)
Called from ApiHelp before the pieces are joined together and returned.
Definition ApiBase.php:2168
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:800
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
recordUnifiedMetrics( $latency=0, $detailLabels=[])
Record unified metrics for the API.
Definition ApiBase.php:2183
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition ApiBase.php:1438
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition ApiBase.php:1557
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition ApiBase.php:1244
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:822
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition ApiBase.php:741
getConditionalRequestData( $condition)
Returns data for HTTP conditional request mechanisms.
Definition ApiBase.php:527
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1921
getFinalParams( $flags=0)
Get the final list of parameters, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1890
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:1673
getFinalSummary()
Get the final module summary.
Definition ApiBase.php:1838
const PARAM_DEPRECATED_VALUES
Definition ApiBase.php:132
dieReadOnly()
Helper function for readonly errors.
Definition ApiBase.php:1599
checkTitleUserPermissions(PageIdentity $pageIdentity, $actions, array $options=[])
Helper function for permission-denied errors.
Definition ApiBase.php:1638
needsToken()
Returns the token type this module requires in order to execute.
Definition ApiBase.php:496
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition ApiBase.php:788
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition ApiBase.php:2087
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:1146
validateToken( $token, array $params)
Validate the supplied token.
Definition ApiBase.php:1256
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition ApiBase.php:570
getModuleFromPath( $path)
Get a module from its module path.
Definition ApiBase.php:641
requireOnlyOneParameter( $params,... $required)
Die if 0 or more than one of a certain set of parameters is set and not false.
Definition ApiBase.php:960
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition ApiBase.php:943
getHookContainer()
Get a HookContainer, for running extension hooks or for hook metadata.
Definition ApiBase.php:751
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
static getToken(User $user, \MediaWiki\Session\Session $session, $salt)
Get a token from a salt.
static getTokenTypeSalts()
Get the salts for known token types.
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.
const DebugAPI
Name constant for the DebugAPI setting, for use with Config::get()
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
static listParam(array $list, $type=ListType::AND)
Definition Message.php:1355
Base representation for an editable wiki page.
Definition WikiPage.php:82
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'=>[], '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, 'ThumbnailStepsRatio'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, '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',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'UseLegacyMediaStyles' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'default' => true, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, 'createwithcontentmodel' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, '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: ], '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, ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailStepsRatio' => [ 'number', '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', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'file' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], ], ], '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.