MediaWiki master
ApiBase.php
Go to the documentation of this file.
1<?php
9namespace MediaWiki\Api;
10
11use InvalidArgumentException;
12use LogicException;
34use ReflectionClass;
35use StatusValue;
36use stdClass;
37use Throwable;
44use Wikimedia\Timestamp\TimestampException;
45
61abstract class ApiBase extends ContextSource {
62
64 private $hookContainer;
65
67 private $hookRunner;
68
77 public const PARAM_DFLT = ParamValidator::PARAM_DEFAULT;
81 public const PARAM_ISMULTI = ParamValidator::PARAM_ISMULTI;
85 public const PARAM_TYPE = ParamValidator::PARAM_TYPE;
89 public const PARAM_MAX = IntegerDef::PARAM_MAX;
93 public const PARAM_MAX2 = IntegerDef::PARAM_MAX2;
97 public const PARAM_MIN = IntegerDef::PARAM_MIN;
101 public const PARAM_ALLOW_DUPLICATES = ParamValidator::PARAM_ALLOW_DUPLICATES;
105 public const PARAM_DEPRECATED = ParamValidator::PARAM_DEPRECATED;
109 public const PARAM_REQUIRED = ParamValidator::PARAM_REQUIRED;
113 public const PARAM_SUBMODULE_MAP = SubmoduleDef::PARAM_SUBMODULE_MAP;
117 public const PARAM_SUBMODULE_PARAM_PREFIX = SubmoduleDef::PARAM_SUBMODULE_PARAM_PREFIX;
121 public const PARAM_ALL = ParamValidator::PARAM_ALL;
125 public const PARAM_EXTRA_NAMESPACES = NamespaceDef::PARAM_EXTRA_NAMESPACES;
129 public const PARAM_SENSITIVE = ParamValidator::PARAM_SENSITIVE;
133 public const PARAM_DEPRECATED_VALUES = EnumDef::PARAM_DEPRECATED_VALUES;
137 public const PARAM_ISMULTI_LIMIT1 = ParamValidator::PARAM_ISMULTI_LIMIT1;
141 public const PARAM_ISMULTI_LIMIT2 = ParamValidator::PARAM_ISMULTI_LIMIT2;
156 public const PARAM_RANGE_ENFORCE = 'api-param-range-enforce';
157
158 // region API-specific constants for ::getAllowedParams() arrays
167 public const PARAM_HELP_MSG = 'api-param-help-msg';
168
175 public const PARAM_HELP_MSG_APPEND = 'api-param-help-msg-append';
176
185 public const PARAM_HELP_MSG_INFO = 'api-param-help-msg-info';
186
192 public const PARAM_VALUE_LINKS = 'api-param-value-links';
193
207 public const PARAM_HELP_MSG_PER_VALUE = 'api-param-help-msg-per-value';
208
225 public const PARAM_TEMPLATE_VARS = 'param-template-vars';
226
227 // endregion -- end of API-specific constants for ::getAllowedParams() arrays
228
229 public const ALL_DEFAULT_STRING = '*';
230
232 public const LIMIT_BIG1 = 500;
234 public const LIMIT_BIG2 = 5000;
236 public const LIMIT_SML1 = 50;
238 public const LIMIT_SML2 = 500;
239
245 public const GET_VALUES_FOR_HELP = 1;
246
248 private static $extensionInfo = null;
249
251 private static $filterIDsCache = [];
252
254 private const MESSAGE_CODE_MAP = [
255 'actionthrottled' => [ 'apierror-ratelimited', 'ratelimited' ],
256 'actionthrottledtext' => [ 'apierror-ratelimited', 'ratelimited' ],
257 ];
258
260 private $mMainModule;
261
262 // Adding inline type hints for these two fields is non-trivial because
263 // of tests that create mocks for ApiBase subclasses and use
264 // disableOriginalConstructor(): in those cases the constructor here is never
265 // hit and thus these will be empty and any uses will raise a "Typed property
266 // must not be accessed before initialization" error.
268 private $mModuleName;
270 private $mModulePrefix;
271
273 private $mReplicaDB = null;
277 private $mParamCache = [];
279 private $mModuleSource = false;
280
287 public function __construct( ApiMain $mainModule, string $moduleName, string $modulePrefix = '' ) {
288 $this->mMainModule = $mainModule;
289 $this->mModuleName = $moduleName;
290 $this->mModulePrefix = $modulePrefix;
291
292 if ( !$this->isMain() ) {
293 $this->setContext( $mainModule->getContext() );
294 }
295 }
296
297 /***************************************************************************/
298 // region Methods to implement
317 abstract public function execute();
318
326 public function getModuleManager() {
327 return null;
328 }
329
342 public function getCustomPrinter() {
343 return null;
344 }
345
358 protected function getExamplesMessages() {
359 return [];
360 }
361
369 public function getHelpUrls() {
370 return [];
371 }
372
386 protected function getAllowedParams( /* $flags = 0 */ ) {
387 // $flags is not declared because it causes "Strict standards"
388 // warning. Most derived classes do not implement it.
389 return [];
390 }
391
398 public function shouldCheckMaxlag() {
399 return true;
400 }
401
408 public function isReadMode() {
409 return true;
410 }
411
437 public function isWriteMode() {
438 return false;
439 }
440
450 public function mustBePosted() {
451 return $this->needsToken() !== false;
452 }
453
461 public function isDeprecated() {
462 return false;
463 }
464
474 public function isInternal() {
475 return false;
476 }
477
497 public function needsToken() {
498 return false;
499 }
500
511 protected function getWebUITokenSalt( array $params ) {
512 return null;
513 }
514
528 public function getConditionalRequestData( $condition ) {
529 return null;
530 }
531
532 // endregion -- end of methods to implement
533
534 /***************************************************************************/
535 // region Data access methods
543 public function getModuleName() {
544 return $this->mModuleName;
545 }
546
552 public function getModulePrefix() {
553 return $this->mModulePrefix;
554 }
555
561 public function getMain() {
562 return $this->mMainModule;
563 }
564
571 public function isMain() {
572 return $this === $this->mMainModule;
573 }
574
582 public function getParent() {
583 return $this->isMain() ? null : $this->getMain();
584 }
585
593 private function dieIfMain( string $methodName ) {
594 if ( $this->isMain() ) {
595 self::dieDebug( $methodName, 'base method was called on main module.' );
596 }
597 }
598
609 public function lacksSameOriginSecurity() {
610 // The Main module has this method overridden, avoid infinite loops
611 $this->dieIfMain( __METHOD__ );
612
613 return $this->getMain()->lacksSameOriginSecurity();
614 }
615
622 public function getModulePath() {
623 if ( $this->isMain() ) {
624 return 'main';
625 }
626
627 if ( $this->getParent()->isMain() ) {
628 return $this->getModuleName();
629 }
630
631 return $this->getParent()->getModulePath() . '+' . $this->getModuleName();
632 }
633
642 public function getModuleFromPath( $path ) {
643 $module = $this->getMain();
644 if ( $path === 'main' ) {
645 return $module;
646 }
647
648 $parts = explode( '+', $path );
649 if ( count( $parts ) === 1 ) {
650 // In case the '+' was typed into URL, it resolves as a space
651 $parts = explode( ' ', $path );
652 }
653
654 foreach ( $parts as $i => $v ) {
655 $parent = $module;
656 $manager = $parent->getModuleManager();
657 if ( $manager === null ) {
658 $errorPath = implode( '+', array_slice( $parts, 0, $i ) );
659 $this->dieWithError( [ 'apierror-badmodule-nosubmodules', $errorPath ], 'badmodule' );
660 }
661 $module = $manager->getModule( $v );
662
663 if ( $module === null ) {
664 $errorPath = $i
665 ? implode( '+', array_slice( $parts, 0, $i ) )
666 : $parent->getModuleName();
667 $this->dieWithError(
668 [ 'apierror-badmodule-badsubmodule', $errorPath, wfEscapeWikiText( $v ) ],
669 'badmodule'
670 );
671 }
672 }
673
674 return $module;
675 }
676
682 public function getResult() {
683 // The Main module has this method overridden, avoid infinite loops
684 $this->dieIfMain( __METHOD__ );
685
686 return $this->getMain()->getResult();
687 }
688
693 public function getErrorFormatter() {
694 // The Main module has this method overridden, avoid infinite loops
695 $this->dieIfMain( __METHOD__ );
696
697 return $this->getMain()->getErrorFormatter();
698 }
699
706 protected function getDB() {
707 if ( !$this->mReplicaDB ) {
708 $this->mReplicaDB = MediaWikiServices::getInstance()
709 ->getConnectionProvider()
710 ->getReplicaDatabase();
711 }
712
713 return $this->mReplicaDB;
714 }
715
719 public function getContinuationManager() {
720 // The Main module has this method overridden, avoid infinite loops
721 $this->dieIfMain( __METHOD__ );
722
723 return $this->getMain()->getContinuationManager();
724 }
725
729 public function setContinuationManager( ?ApiContinuationManager $manager = null ) {
730 // The Main module has this method overridden, avoid infinite loops
731 $this->dieIfMain( __METHOD__ );
732
733 $this->getMain()->setContinuationManager( $manager );
734 }
735
744 }
745
752 protected function getHookContainer() {
753 if ( !$this->hookContainer ) {
754 $this->hookContainer = MediaWikiServices::getInstance()->getHookContainer();
755 }
756 return $this->hookContainer;
757 }
758
767 protected function getHookRunner() {
768 if ( !$this->hookRunner ) {
769 $this->hookRunner = new ApiHookRunner( $this->getHookContainer() );
770 }
771 return $this->hookRunner;
772 }
773
774 // endregion -- end of data access methods
775
776 /***************************************************************************/
777 // region Parameter handling
790 return null;
791 }
792
801 public function encodeParamName( $paramName ) {
802 if ( is_array( $paramName ) ) {
803 return array_map( function ( $name ) {
804 return $this->mModulePrefix . $name;
805 }, $paramName );
806 }
807
808 return $this->mModulePrefix . $paramName;
809 }
810
823 public function extractRequestParams( $options = [] ) {
824 if ( is_bool( $options ) ) {
825 $options = [ 'parseLimit' => $options ];
826 }
827 $options += [
828 'parseLimit' => true,
829 'safeMode' => false,
830 ];
831
832 $parseLimit = (bool)$options['parseLimit'];
833 $cacheKey = (int)$parseLimit;
834
835 // Cache parameters, for performance and to avoid T26564.
836 if ( !isset( $this->mParamCache[$cacheKey] ) ) {
837 $params = $this->getFinalParams() ?: [];
838 $results = [];
839 $warned = [];
840
841 // Process all non-templates and save templates for secondary
842 // processing.
843 $toProcess = [];
844 foreach ( $params as $paramName => $paramSettings ) {
845 if ( isset( $paramSettings[self::PARAM_TEMPLATE_VARS] ) ) {
846 $toProcess[] = [ $paramName, $paramSettings[self::PARAM_TEMPLATE_VARS], $paramSettings ];
847 } else {
848 try {
849 $results[$paramName] = $this->getParameterFromSettings(
850 $paramName, $paramSettings, $parseLimit
851 );
852 } catch ( ApiUsageException $ex ) {
853 $results[$paramName] = $ex;
854 }
855 }
856 }
857
858 // Now process all the templates by successively replacing the
859 // placeholders with all client-supplied values.
860 // This bit duplicates JavaScript logic in
861 // ApiSandbox.PageLayout.prototype.updateTemplatedParams().
862 // If you update this, see if that needs updating too.
863 while ( $toProcess ) {
864 [ $name, $targets, $settings ] = array_shift( $toProcess );
865
866 foreach ( $targets as $placeholder => $target ) {
867 if ( !array_key_exists( $target, $results ) ) {
868 // The target wasn't processed yet, try the next one.
869 // If all hit this case, the parameter has no expansions.
870 continue;
871 }
872 if ( !is_array( $results[$target] ) || !$results[$target] ) {
873 // The target was processed but has no (valid) values.
874 // That means it has no expansions.
875 break;
876 }
877
878 // Expand this target in the name and all other targets,
879 // then requeue if there are more targets left or put in
880 // $results if all are done.
881 unset( $targets[$placeholder] );
882 $placeholder = '{' . $placeholder . '}';
883 // @phan-suppress-next-line PhanTypeNoAccessiblePropertiesForeach
884 foreach ( $results[$target] as $value ) {
885 if ( !preg_match( '/^[^{}]*$/', $value ) ) {
886 // Skip values that make invalid parameter names.
887 $encTargetName = $this->encodeParamName( $target );
888 if ( !isset( $warned[$encTargetName][$value] ) ) {
889 $warned[$encTargetName][$value] = true;
890 $this->addWarning( [
891 'apiwarn-ignoring-invalid-templated-value',
892 wfEscapeWikiText( $encTargetName ),
893 wfEscapeWikiText( $value ),
894 ] );
895 }
896 continue;
897 }
898
899 $newName = str_replace( $placeholder, $value, $name );
900 if ( !$targets ) {
901 try {
902 $results[$newName] = $this->getParameterFromSettings(
903 $newName,
904 $settings,
905 $parseLimit
906 );
907 } catch ( ApiUsageException $ex ) {
908 $results[$newName] = $ex;
909 }
910 } else {
911 $newTargets = [];
912 foreach ( $targets as $k => $v ) {
913 $newTargets[$k] = str_replace( $placeholder, $value, $v );
914 }
915 $toProcess[] = [ $newName, $newTargets, $settings ];
916 }
917 }
918 break;
919 }
920 }
921
922 $this->mParamCache[$cacheKey] = $results;
923 }
924
925 $ret = $this->mParamCache[$cacheKey];
926 if ( !$options['safeMode'] ) {
927 foreach ( $ret as $v ) {
928 if ( $v instanceof ApiUsageException ) {
929 throw $v;
930 }
931 }
932 }
933
934 return $this->mParamCache[$cacheKey];
935 }
936
944 protected function getParameter( $paramName, $parseLimit = true ) {
945 $ret = $this->extractRequestParams( [
946 'parseLimit' => $parseLimit,
947 'safeMode' => true,
948 ] )[$paramName];
949 if ( $ret instanceof ApiUsageException ) {
950 throw $ret;
951 }
952 return $ret;
953 }
954
961 public function requireOnlyOneParameter( $params, ...$required ) {
962 $intersection = array_intersect(
963 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
964 $required
965 );
966
967 if ( count( $intersection ) > 1 ) {
968 $this->dieWithError( [
969 'apierror-invalidparammix',
970 Message::listParam( array_map(
971 function ( $p ) {
972 return '<var>' . $this->encodeParamName( $p ) . '</var>';
973 },
974 array_values( $intersection )
975 ) ),
976 count( $intersection ),
977 ] );
978 } elseif ( count( $intersection ) == 0 ) {
979 $this->dieWithError( [
980 'apierror-missingparam-one-of',
981 Message::listParam( array_map(
982 function ( $p ) {
983 return '<var>' . $this->encodeParamName( $p ) . '</var>';
984 },
985 $required
986 ) ),
987 count( $required ),
988 ], 'missingparam' );
989 }
990 }
991
998 public function requireMaxOneParameter( $params, ...$required ) {
999 $intersection = array_intersect(
1000 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1001 $required
1002 );
1003
1004 if ( count( $intersection ) > 1 ) {
1005 $this->dieWithError( [
1006 'apierror-invalidparammix',
1007 Message::listParam( array_map(
1008 function ( $p ) {
1009 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1010 },
1011 array_values( $intersection )
1012 ) ),
1013 count( $intersection ),
1014 ] );
1015 }
1016 }
1017
1025 public function requireAtLeastOneParameter( $params, ...$required ) {
1026 $intersection = array_intersect(
1027 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1028 $required
1029 );
1030
1031 if ( count( $intersection ) == 0 ) {
1032 $this->dieWithError( [
1033 'apierror-missingparam-at-least-one-of',
1034 Message::listParam( array_map(
1035 function ( $p ) {
1036 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1037 },
1038 $required
1039 ) ),
1040 count( $required ),
1041 ], 'missingparam' );
1042 }
1043 }
1044
1056 public function requireNoConflictingParameters( $params, $trigger, $conflicts ) {
1057 $triggerValue = $params[$trigger] ?? null;
1058 if ( $triggerValue === null || $triggerValue === false ) {
1059 return;
1060 }
1061 $intersection = array_intersect(
1062 array_keys( array_filter( $params, $this->parameterNotEmpty( ... ) ) ),
1063 (array)$conflicts
1064 );
1065 if ( count( $intersection ) ) {
1066 $this->dieWithError( [
1067 'apierror-invalidparammix-cannotusewith',
1068 Message::listParam( array_map(
1069 function ( $p ) {
1070 return '<var>' . $this->encodeParamName( $p ) . '</var>';
1071 },
1072 array_values( $intersection )
1073 ) ),
1074 $trigger,
1075 ] );
1076 }
1077 }
1078
1087 public function requirePostedParameters( $params, $prefix = 'prefix' ) {
1088 if ( !$this->mustBePosted() ) {
1089 // In order to allow client code to choose the correct method (GET or POST) depending *only*
1090 // on mustBePosted(), make sure that the module requires posting if any of its potential
1091 // parameters require posting.
1092
1093 // TODO: Uncomment this
1094 // throw new LogicException( 'mustBePosted() must be true when using requirePostedParameters()' );
1095
1096 // This seems to already be the case in all modules in practice, but deprecate it first just
1097 // in case.
1098 wfDeprecatedMsg( 'mustBePosted() must be true when using requirePostedParameters()',
1099 '1.42' );
1100 }
1101
1102 // Skip if $wgDebugAPI is set, or if we're in internal mode
1103 if ( $this->getConfig()->get( MainConfigNames::DebugAPI ) ||
1104 $this->getMain()->isInternalMode() ) {
1105 return;
1106 }
1107
1108 $queryValues = $this->getRequest()->getQueryValuesOnly();
1109 $badParams = [];
1110 foreach ( $params as $param ) {
1111 if ( $prefix !== 'noprefix' ) {
1112 $param = $this->encodeParamName( $param );
1113 }
1114 if ( array_key_exists( $param, $queryValues ) ) {
1115 $badParams[] = $param;
1116 }
1117 }
1118
1119 if ( $badParams ) {
1120 $this->dieWithError(
1121 [ 'apierror-mustpostparams', implode( ', ', $badParams ), count( $badParams ) ]
1122 );
1123 }
1124 }
1125
1132 private function parameterNotEmpty( $x ) {
1133 return $x !== null && $x !== false;
1134 }
1135
1147 public function getTitleOrPageId( $params, $load = false ) {
1148 $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1149
1150 $pageObj = null;
1151 if ( isset( $params['title'] ) ) {
1152 $titleObj = Title::newFromText( $params['title'] );
1153 if ( !$titleObj || $titleObj->isExternal() ) {
1154 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1155 }
1156 if ( !$titleObj->canExist() ) {
1157 $this->dieWithError( 'apierror-pagecannotexist' );
1158 }
1159 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable T240141
1160 $pageObj = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromTitle( $titleObj );
1161 if ( $load !== false ) {
1162 $pageObj->loadPageData( $load );
1163 }
1164 } elseif ( isset( $params['pageid'] ) ) {
1165 if ( $load === false ) {
1166 $load = 'fromdb';
1167 }
1168 $pageObj = MediaWikiServices::getInstance()->getWikiPageFactory()->newFromID( $params['pageid'], $load );
1169 if ( !$pageObj ) {
1170 $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1171 }
1172 }
1173
1174 // @phan-suppress-next-line PhanTypeMismatchReturnNullable requireOnlyOneParameter guard it is always set
1175 return $pageObj;
1176 }
1177
1186 public function getTitleFromTitleOrPageId( $params ) {
1187 $this->requireOnlyOneParameter( $params, 'title', 'pageid' );
1188
1189 $titleObj = null;
1190 if ( isset( $params['title'] ) ) {
1191 $titleObj = Title::newFromText( $params['title'] );
1192 if ( !$titleObj || $titleObj->isExternal() ) {
1193 $this->dieWithError( [ 'apierror-invalidtitle', wfEscapeWikiText( $params['title'] ) ] );
1194 }
1195 // @phan-suppress-next-line PhanTypeMismatchReturnNullable T240141
1196 return $titleObj;
1197 }
1198
1199 if ( isset( $params['pageid'] ) ) {
1200 $titleObj = Title::newFromID( $params['pageid'] );
1201 if ( !$titleObj ) {
1202 $this->dieWithError( [ 'apierror-nosuchpageid', $params['pageid'] ] );
1203 }
1204 }
1205
1206 // @phan-suppress-next-line PhanTypeMismatchReturnNullable requireOnlyOneParameter guard it is always set
1207 return $titleObj;
1208 }
1209
1219 protected function getParameterFromSettings( $name, $settings, $parseLimit ) {
1220 $validator = $this->getMain()->getParamValidator();
1221 $value = $validator->getValue( $this, $name, $settings, [
1222 'parse-limit' => $parseLimit,
1223 'raw' => ( $settings[ParamValidator::PARAM_TYPE] ?? '' ) === 'raw',
1224 ] );
1225
1226 // @todo Deprecate and remove this, if possible.
1227 if ( $parseLimit && isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1228 $settings[ParamValidator::PARAM_TYPE] === 'limit' &&
1229 $this->getMain()->getVal( $this->encodeParamName( $name ) ) === 'max'
1230 ) {
1231 $this->getResult()->addParsedLimit( $this->getModuleName(), $value );
1232 }
1233
1234 return $value;
1235 }
1236
1247 public function handleParamNormalization( $paramName, $value, $rawValue ) {
1248 $this->addWarning( [ 'apiwarn-badutf8', $paramName ] );
1249 }
1250
1259 final public function validateToken( $token, array $params ) {
1260 $tokenType = $this->needsToken();
1262 if ( !isset( $salts[$tokenType] ) ) {
1263 throw new LogicException(
1264 "Module '{$this->getModuleName()}' tried to use token type '$tokenType' " .
1265 'without registering it'
1266 );
1267 }
1268
1269 $tokenObj = ApiQueryTokens::getToken(
1270 $this->getUser(), $this->getRequest()->getSession(), $salts[$tokenType]
1271 );
1272 if ( $tokenObj->match( $token ) ) {
1273 return true;
1274 }
1275
1276 $webUiSalt = $this->getWebUITokenSalt( $params );
1277
1278 return $webUiSalt !== null && $this->getUser()->matchEditToken(
1279 $token, $webUiSalt, $this->getRequest()
1280 );
1281 }
1282
1283 // endregion -- end of parameter handling
1284
1285 /***************************************************************************/
1286 // region Utility methods
1295 public function getWatchlistUser( $params ) {
1296 if ( $params['owner'] !== null && $params['token'] !== null ) {
1297 $services = MediaWikiServices::getInstance();
1298 $user = $services->getUserFactory()->newFromName( $params['owner'], UserRigorOptions::RIGOR_NONE );
1299 if ( !$user || !$user->isRegistered() ) {
1300 $this->dieWithError(
1301 [ 'nosuchusershort', wfEscapeWikiText( $params['owner'] ) ], 'bad_wlowner'
1302 );
1303 }
1304 // @phan-suppress-next-line PhanTypeMismatchArgumentNullable T240141
1305 $token = $services->getUserOptionsLookup()->getOption( $user, 'watchlisttoken' );
1306 if ( $token == '' || !hash_equals( $token, $params['token'] ) ) {
1307 $this->dieWithError( 'apierror-bad-watchlist-token', 'bad_wltoken' );
1308 }
1309 } else {
1310 $user = $this->getUser();
1311 if ( !$user->isRegistered() ) {
1312 $this->dieWithError( 'watchlistanontext', 'notloggedin' );
1313 }
1314 $this->checkUserRightsAny( 'viewmywatchlist' );
1315 }
1316
1317 // @phan-suppress-next-line PhanTypeMismatchReturnNullable T240141
1318 return $user;
1319 }
1320
1335 public static function makeMessage( $msg, IContextSource $context, ?array $params = null ) {
1336 wfDeprecated( __METHOD__, '1.43' );
1337 if ( is_string( $msg ) ) {
1338 $msg = wfMessage( $msg );
1339 } elseif ( is_array( $msg ) ) {
1340 $msg = wfMessage( ...$msg );
1341 }
1342 if ( !$msg instanceof Message ) {
1343 return null;
1344 }
1345
1346 $msg->setContext( $context );
1347 if ( $params ) {
1348 $msg->params( $params );
1349 }
1350
1351 return $msg;
1352 }
1353
1359 protected function useTransactionalTimeLimit() {
1360 if ( $this->getRequest()->wasPosted() ) {
1362 }
1363 }
1364
1370 public static function clearCacheForTest(): void {
1371 if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
1372 throw new LogicException( 'Not allowed outside tests' );
1373 }
1374 self::$filterIDsCache = [];
1375 }
1376
1386 protected function filterIDs( $fields, array $ids ) {
1387 $min = INF;
1388 $max = 0;
1389 foreach ( $fields as [ $table, $field ] ) {
1390 if ( isset( self::$filterIDsCache[$table][$field] ) ) {
1391 $row = self::$filterIDsCache[$table][$field];
1392 } else {
1393 $row = $this->getDB()->newSelectQueryBuilder()
1394 ->select( [ 'min_id' => "MIN($field)", 'max_id' => "MAX($field)" ] )
1395 ->from( $table )
1396 ->caller( __METHOD__ )->fetchRow();
1397 self::$filterIDsCache[$table][$field] = $row;
1398 }
1399 $min = min( $min, $row->min_id );
1400 $max = max( $max, $row->max_id );
1401 }
1402 return array_filter( $ids, static function ( $id ) use ( $min, $max ) {
1403 return ( ( is_int( $id ) && $id >= 0 ) || ctype_digit( (string)$id ) )
1404 && $id >= $min && $id <= $max;
1405 } );
1406 }
1407
1408 // endregion -- end of utility methods
1409
1410 /***************************************************************************/
1411 // region Warning and error reporting
1429 public function addWarning( $msg, $code = null, $data = null ) {
1430 $this->getErrorFormatter()->addWarning( $this->getModulePath(), $msg, $code, $data );
1431 }
1432
1443 public function addDeprecation( $msg, $feature, $data = [] ) {
1444 $data = (array)$data;
1445 if ( $feature !== null ) {
1446 $data['feature'] = $feature;
1447 $this->logFeatureUsage( $feature );
1448 }
1449 $this->addWarning( $msg, 'deprecation', $data );
1450
1451 // No real need to deduplicate here, ApiErrorFormatter does that for
1452 // us (assuming the hook is deterministic).
1453 $msgs = [ $this->msg( 'api-usage-mailinglist-ref' ) ];
1454 $this->getHookRunner()->onApiDeprecationHelp( $msgs );
1455 if ( count( $msgs ) > 1 ) {
1456 $key = '$' . implode( ' $', range( 1, count( $msgs ) ) );
1457 $msg = ( new RawMessage( $key ) )->params( $msgs );
1458 } else {
1459 $msg = reset( $msgs );
1460 }
1461 $this->getMain()->addWarning( $msg, 'deprecation-help' );
1462 }
1463
1476 public function addError( $msg, $code = null, $data = null ) {
1477 $this->getErrorFormatter()->addError( $this->getModulePath(), $msg, $code, $data );
1478 }
1479
1489 public function addMessagesFromStatus(
1490 StatusValue $status, $types = [ 'warning', 'error' ], array $filter = []
1491 ) {
1492 $this->getErrorFormatter()->addMessagesFromStatus(
1493 $this->getModulePath(), $status, $types, $filter
1494 );
1495 }
1496
1511 public function dieWithError( $msg, $code = null, $data = null, $httpCode = 0 ): never {
1512 throw ApiUsageException::newWithMessage( $this, $msg, $code, $data, $httpCode );
1513 }
1514
1524 public function dieWithException( Throwable $exception, array $options = [] ): never {
1525 $this->dieWithError(
1526 $this->getErrorFormatter()->getMessageFromException( $exception, $options )
1527 );
1528 }
1529
1539 public function dieBlocked( Block $block ): never {
1540 $blockErrorFormatter = MediaWikiServices::getInstance()->getFormatterFactory()
1541 ->getBlockErrorFormatter( $this->getContext() );
1542
1543 $msg = $blockErrorFormatter->getMessage(
1544 $block,
1545 $this->getUser(),
1546 null,
1547 $this->getRequest()->getIP()
1548 );
1549
1550 $this->dieWithError( $msg );
1551 }
1552
1562 public function dieStatus( StatusValue $status ): never {
1563 if ( $status->isGood() ) {
1564 throw new InvalidArgumentException( 'Successful status passed to ApiBase::dieStatus' );
1565 }
1566
1567 foreach ( self::MESSAGE_CODE_MAP as $msg => [ $apiMsg, $code ] ) {
1568 if ( $status->hasMessage( $msg ) ) {
1569 $status->replaceMessage( $msg, ApiMessage::create( $apiMsg, $code ) );
1570 }
1571 }
1572
1573 if (
1574 $status instanceof PermissionStatus
1575 && $status->isRateLimitExceeded()
1576 && !$status->hasMessage( 'apierror-ratelimited' )
1577 ) {
1578 $status->fatal( ApiMessage::create( 'apierror-ratelimited', 'ratelimited' ) );
1579 }
1580
1581 // ApiUsageException needs a fatal status, but this method has
1582 // historically accepted any non-good status. Convert it if necessary.
1583 $status->setOK( false );
1584 if ( !$status->getMessages( 'error' ) ) {
1585 $newStatus = Status::newGood();
1586 foreach ( $status->getMessages( 'warning' ) as $err ) {
1587 $newStatus->fatal( $err );
1588 }
1589 if ( !$newStatus->getMessages( 'error' ) ) {
1590 $newStatus->fatal( 'unknownerror-nocode' );
1591 }
1592 $status = $newStatus;
1593 }
1594
1595 throw new ApiUsageException( $this, $status );
1596 }
1597
1604 public function dieReadOnly(): never {
1605 $this->dieWithError(
1606 'apierror-readonly',
1607 'readonly',
1608 [ 'readonlyreason' => MediaWikiServices::getInstance()->getReadOnlyMode()->getReason() ]
1609 );
1610 }
1611
1620 public function checkUserRightsAny( $rights ) {
1621 $rights = (array)$rights;
1622 if ( !$this->getAuthority()->isAllowedAny( ...$rights ) ) {
1623 $this->dieWithError( [ 'apierror-permissiondenied', $this->msg( "action-{$rights[0]}" ) ] );
1624 }
1625 }
1626
1644 PageIdentity $pageIdentity,
1645 $actions,
1646 array $options = []
1647 ) {
1648 $authority = $options['user'] ?? $this->getAuthority();
1649 $status = new PermissionStatus();
1650 foreach ( (array)$actions as $action ) {
1651 if ( $this->isWriteMode() ) {
1652 $authority->authorizeWrite( $action, $pageIdentity, $status );
1653 } else {
1654 $authority->authorizeRead( $action, $pageIdentity, $status );
1655 }
1656 }
1657 if ( !$status->isGood() ) {
1658 if ( !empty( $options['autoblock'] ) ) {
1659 $this->getUser()->spreadAnyEditBlock();
1660 }
1661 $this->dieStatus( $status );
1662 }
1663 }
1664
1678 public function dieWithErrorOrDebug( $msg, $code = null, $data = null, $httpCode = null ) {
1679 if ( $this->getConfig()->get( MainConfigNames::DebugAPI ) !== true ) {
1680 $this->dieWithError( $msg, $code, $data, $httpCode ?? 0 );
1681 } else {
1682 $this->addWarning( $msg, $code, $data );
1683 }
1684 }
1685
1696 protected function parseContinueParamOrDie( string $continue, array $types ): array {
1697 $cont = explode( '|', $continue );
1698 $this->dieContinueUsageIf( count( $cont ) != count( $types ) );
1699
1700 foreach ( $cont as $i => &$value ) {
1701 switch ( $types[$i] ) {
1702 case 'string':
1703 // Do nothing
1704 break;
1705 case 'int':
1706 $this->dieContinueUsageIf( $value !== (string)(int)$value );
1707 $value = (int)$value;
1708 break;
1709 case 'timestamp':
1710 try {
1711 $dbTs = $this->getDB()->timestamp( $value );
1712 } catch ( TimestampException ) {
1713 $dbTs = false;
1714 }
1715 $this->dieContinueUsageIf( $value !== $dbTs );
1716 break;
1717 default:
1718 throw new InvalidArgumentException( "Unknown type '{$types[$i]}'" );
1719 }
1720 }
1721
1722 return $cont;
1723 }
1724
1735 protected function dieContinueUsageIf( $condition ) {
1736 if ( $condition ) {
1737 $this->dieWithError( 'apierror-badcontinue' );
1738 }
1739 }
1740
1748 protected static function dieDebug( $method, $message ): never {
1749 throw new MWException( "Internal error in $method: $message" );
1750 }
1751
1759 public function logFeatureUsage( $feature ) {
1760 static $loggedFeatures = [];
1761
1762 // Only log each feature once per request. We can get multiple calls from calls to
1763 // extractRequestParams() with different values for 'parseLimit', for example.
1764 if ( isset( $loggedFeatures[$feature] ) ) {
1765 return;
1766 }
1767 $loggedFeatures[$feature] = true;
1768
1769 $request = $this->getRequest();
1770 $ctx = [
1771 'feature' => $feature,
1772 // Replace spaces with underscores in 'username' for historical reasons.
1773 'username' => str_replace( ' ', '_', $this->getUser()->getName() ),
1774 'clientip' => $request->getIP(),
1775 'referer' => (string)$request->getHeader( 'Referer' ),
1776 'agent' => $this->getMain()->getUserAgent(),
1777 ];
1778
1779 // Text string is deprecated. Remove (or replace with just $feature) in MW 1.34.
1780 $s = '"' . addslashes( $ctx['feature'] ) . '"' .
1781 ' "' . wfUrlencode( $ctx['username'] ) . '"' .
1782 ' "' . $ctx['clientip'] . '"' .
1783 ' "' . addslashes( $ctx['referer'] ) . '"' .
1784 ' "' . addslashes( $ctx['agent'] ) . '"';
1785
1786 wfDebugLog( 'api-feature-usage', $s, 'private', $ctx );
1787
1788 $this->getHookRunner()->onApiLogFeatureUsage(
1789 $feature,
1790 [
1791 'userName' => $this->getUser()->getName(),
1792 'userAgent' => $this->getMain()->getUserAgent(),
1793 'ipAddress' => $request->getIP()
1794 ]
1795 );
1796 }
1797
1798 // endregion -- end of warning and error reporting
1799
1800 /***************************************************************************/
1801 // region Help message generation
1814 protected function getSummaryMessage() {
1815 return "apihelp-{$this->getModulePath()}-summary";
1816 }
1817
1829 protected function getExtendedDescription() {
1830 return [ [
1831 "apihelp-{$this->getModulePath()}-extended-description",
1832 'api-help-no-extended-description',
1833 ] ];
1834 }
1835
1843 public function getFinalSummary() {
1844 return $this->msg(
1845 Message::newFromSpecifier( $this->getSummaryMessage() ),
1846 $this->getModulePrefix(),
1847 $this->getModuleName(),
1848 $this->getModulePath(),
1849 );
1850 }
1851
1859 public function getFinalDescription() {
1860 $summary = $this->msg(
1861 Message::newFromSpecifier( $this->getSummaryMessage() ),
1862 $this->getModulePrefix(),
1863 $this->getModuleName(),
1864 $this->getModulePath(),
1865 );
1866 $extendedDesc = $this->getExtendedDescription();
1867 if ( is_array( $extendedDesc ) && is_array( $extendedDesc[0] ) ) {
1868 // The definition in getExtendedDescription() may also specify fallback keys. This is weird,
1869 // and it was never needed for other API doc messages, so it's only supported here.
1870 $extendedDesc = Message::newFallbackSequence( $extendedDesc[0] )
1871 ->params( array_slice( $extendedDesc, 1 ) );
1872 }
1873 $extendedDesc = $this->msg(
1874 Message::newFromSpecifier( $extendedDesc ),
1875 $this->getModulePrefix(),
1876 $this->getModuleName(),
1877 $this->getModulePath(),
1878 );
1879
1880 $msgs = [ $summary, $extendedDesc ];
1881
1882 $this->getHookRunner()->onAPIGetDescriptionMessages( $this, $msgs );
1883
1884 return $msgs;
1885 }
1886
1895 public function getFinalParams( $flags = 0 ) {
1896 // @phan-suppress-next-line PhanParamTooMany
1897 $params = $this->getAllowedParams( $flags );
1898 if ( !$params ) {
1899 $params = [];
1900 }
1901
1902 if ( $this->needsToken() ) {
1903 $params['token'] = [
1904 ParamValidator::PARAM_TYPE => 'string',
1905 ParamValidator::PARAM_REQUIRED => true,
1906 ParamValidator::PARAM_SENSITIVE => true,
1907 self::PARAM_HELP_MSG => [
1908 'api-help-param-token',
1909 $this->needsToken(),
1910 ],
1911 ] + ( $params['token'] ?? [] );
1912 }
1913
1914 $this->getHookRunner()->onAPIGetAllowedParams( $this, $params, $flags );
1915
1916 return $params;
1917 }
1918
1926 public function getFinalParamDescription() {
1927 $prefix = $this->getModulePrefix();
1928 $name = $this->getModuleName();
1929 $path = $this->getModulePath();
1930
1931 $params = $this->getFinalParams( self::GET_VALUES_FOR_HELP );
1932 $msgs = [];
1933 foreach ( $params as $param => $settings ) {
1934 if ( !is_array( $settings ) ) {
1935 $settings = [];
1936 }
1937
1938 $msg = isset( $settings[self::PARAM_HELP_MSG] )
1939 ? Message::newFromSpecifier( $settings[self::PARAM_HELP_MSG] )
1940 : Message::newFallbackSequence( [ "apihelp-$path-param-$param", 'api-help-param-no-description' ] );
1941 $msg = $this->msg( $msg, $prefix, $param, $name, $path );
1942 $msgs[$param] = [ $msg ];
1943
1944 if ( isset( $settings[ParamValidator::PARAM_TYPE] ) &&
1945 $settings[ParamValidator::PARAM_TYPE] === 'submodule'
1946 ) {
1947 if ( isset( $settings[SubmoduleDef::PARAM_SUBMODULE_MAP] ) ) {
1948 $map = $settings[SubmoduleDef::PARAM_SUBMODULE_MAP];
1949 } else {
1950 $prefix = $this->isMain() ? '' : ( $this->getModulePath() . '+' );
1951 $map = [];
1952 foreach ( $this->getModuleManager()->getNames( $param ) as $submoduleName ) {
1953 $map[$submoduleName] = $prefix . $submoduleName;
1954 }
1955 }
1956
1957 $submodules = [];
1958 $submoduleFlags = []; // for sorting: higher flags are sorted later
1959 $submoduleNames = []; // for sorting: lexicographical, ascending
1960 foreach ( $map as $v => $m ) {
1961 $isDeprecated = false;
1962 $isInternal = false;
1963 $summary = null;
1964 try {
1965 $submod = $this->getModuleFromPath( $m );
1966 if ( $submod ) {
1967 $summary = $submod->getFinalSummary();
1968 $isDeprecated = $submod->isDeprecated();
1969 $isInternal = $submod->isInternal();
1970 }
1971 } catch ( ApiUsageException ) {
1972 // Ignore
1973 }
1974 if ( $summary ) {
1975 $key = $summary->getKey();
1976 $params = $summary->getParams();
1977 } else {
1978 $key = 'api-help-undocumented-module';
1979 $params = [ $m ];
1980 }
1981 $m = new ApiHelpParamValueMessage(
1982 "[[Special:ApiHelp/$m|$v]]",
1983 $key,
1984 $params,
1985 $isDeprecated,
1986 $isInternal
1987 );
1988 $submodules[] = $m->setContext( $this->getContext() );
1989 $submoduleFlags[] = ( $isDeprecated ? 1 : 0 ) | ( $isInternal ? 2 : 0 );
1990 $submoduleNames[] = $v;
1991 }
1992 // sort $submodules by $submoduleFlags and $submoduleNames
1993 array_multisort( $submoduleFlags, $submoduleNames, $submodules );
1994 $msgs[$param] = array_merge( $msgs[$param], $submodules );
1995 } elseif ( isset( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1996 // ! keep these checks in sync with \MediaWiki\Api\Validator\ApiParamValidator::checkSettings
1997 if ( !is_array( $settings[self::PARAM_HELP_MSG_PER_VALUE] ) ) {
1998 self::dieDebug( __METHOD__,
1999 'ApiBase::PARAM_HELP_MSG_PER_VALUE is not valid' );
2000 }
2001 $isArrayOfStrings = is_array( $settings[ParamValidator::PARAM_TYPE] )
2002 || (
2003 $settings[ParamValidator::PARAM_TYPE] === 'string'
2004 && ( $settings[ParamValidator::PARAM_ISMULTI] ?? false )
2005 );
2006 if ( !$isArrayOfStrings ) {
2007 self::dieDebug( __METHOD__,
2008 'ApiBase::PARAM_HELP_MSG_PER_VALUE may only be used when ' .
2009 'ParamValidator::PARAM_TYPE is an array or it is \'string\' and ' .
2010 'ParamValidator::PARAM_ISMULTI is true' );
2011 }
2012
2013 $values = is_array( $settings[ParamValidator::PARAM_TYPE] ) ?
2014 $settings[ParamValidator::PARAM_TYPE] :
2015 array_keys( $settings[self::PARAM_HELP_MSG_PER_VALUE] );
2016 $valueMsgs = $settings[self::PARAM_HELP_MSG_PER_VALUE];
2017 $deprecatedValues = $settings[EnumDef::PARAM_DEPRECATED_VALUES] ?? [];
2018
2019 foreach ( $values as $value ) {
2020 $msg = Message::newFromSpecifier( $valueMsgs[$value] ?? "apihelp-$path-paramvalue-$param-$value" );
2021 $m = $this->msg( $msg, [ $prefix, $param, $name, $path, $value ] );
2022 $m = new ApiHelpParamValueMessage(
2023 $value,
2024 // @phan-suppress-next-line PhanTypeMismatchArgumentProbablyReal
2025 [ $m->getKey(), 'api-help-param-no-description' ],
2026 $m->getParams(),
2027 isset( $deprecatedValues[$value] )
2028 );
2029 $msgs[$param][] = $m->setContext( $this->getContext() );
2030 }
2031 }
2032
2033 if ( isset( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
2034 if ( !is_array( $settings[self::PARAM_HELP_MSG_APPEND] ) ) {
2035 self::dieDebug( __METHOD__,
2036 'Value for ApiBase::PARAM_HELP_MSG_APPEND is not an array' );
2037 }
2038 foreach ( $settings[self::PARAM_HELP_MSG_APPEND] as $m ) {
2039 $m = $this->msg( Message::newFromSpecifier( $m ), [ $prefix, $param, $name, $path ] );
2040 $msgs[$param][] = $m;
2041 }
2042 }
2043 }
2044
2045 $this->getHookRunner()->onAPIGetParamDescriptionMessages( $this, $msgs );
2046
2047 return $msgs;
2048 }
2049
2059 protected function getHelpFlags() {
2060 $flags = [];
2061
2062 if ( $this->isDeprecated() ) {
2063 $flags[] = 'deprecated';
2064 }
2065 if ( $this->isInternal() ) {
2066 $flags[] = 'internal';
2067 }
2068 if ( $this->isReadMode() ) {
2069 $flags[] = 'readrights';
2070 }
2071 if ( $this->isWriteMode() ) {
2072 $flags[] = 'writerights';
2073 }
2074 if ( $this->mustBePosted() ) {
2075 $flags[] = 'mustbeposted';
2076 }
2077
2078 return $flags;
2079 }
2080
2092 protected function getModuleSourceInfo() {
2093 if ( $this->mModuleSource !== false ) {
2094 return $this->mModuleSource;
2095 }
2096
2097 // First, try to find where the module comes from...
2098 $rClass = new ReflectionClass( $this );
2099 $path = $rClass->getFileName();
2100 if ( !$path ) {
2101 // No path known?
2102 $this->mModuleSource = null;
2103 return null;
2104 }
2105 $path = realpath( $path ) ?: $path;
2106
2107 // Build a map of extension directories to extension info
2108 if ( self::$extensionInfo === null ) {
2109 $extDir = $this->getConfig()->get( MainConfigNames::ExtensionDirectory );
2110 $baseDir = MW_INSTALL_PATH;
2111 self::$extensionInfo = [
2112 realpath( __DIR__ ) ?: __DIR__ => [
2113 'path' => $baseDir,
2114 'name' => 'MediaWiki',
2115 'license-name' => 'GPL-2.0-or-later',
2116 ],
2117 realpath( "$baseDir/extensions" ) ?: "$baseDir/extensions" => null,
2118 realpath( $extDir ) ?: $extDir => null,
2119 ];
2120 $keep = [
2121 'path' => null,
2122 'name' => null,
2123 'namemsg' => null,
2124 'license-name' => null,
2125 ];
2126 $credits = SpecialVersion::getCredits( ExtensionRegistry::getInstance(), $this->getConfig() );
2127 foreach ( $credits as $group ) {
2128 foreach ( $group as $ext ) {
2129 if ( !isset( $ext['path'] ) || !isset( $ext['name'] ) ) {
2130 // This shouldn't happen, but does anyway.
2131 continue;
2132 }
2133
2134 $extpath = $ext['path'];
2135 if ( !is_dir( $extpath ) ) {
2136 $extpath = dirname( $extpath );
2137 }
2138 self::$extensionInfo[realpath( $extpath ) ?: $extpath] =
2139 array_intersect_key( $ext, $keep );
2140 }
2141 }
2142 }
2143
2144 // Now traverse parent directories until we find a match or run out of parents.
2145 do {
2146 if ( array_key_exists( $path, self::$extensionInfo ) ) {
2147 // Found it!
2148 $this->mModuleSource = self::$extensionInfo[$path];
2149 return $this->mModuleSource;
2150 }
2151
2152 $oldpath = $path;
2153 $path = dirname( $path );
2154 } while ( $path !== $oldpath );
2155
2156 // No idea what extension this might be.
2157 $this->mModuleSource = null;
2158 return null;
2159 }
2160
2173 public function modifyHelp( array &$help, array $options, array &$tocData ) {
2174 }
2175
2176 // endregion -- end of help message generation
2177
2178 /***************************************************************************/
2179 // region Data Unified metrics
2188 protected function recordUnifiedMetrics( $latency = 0, $detailLabels = [] ) {
2189 // The concept of "module" is different in Action API and REST API
2190 // in REST API, it represents the "collection" of endpoints
2191 // in Action API, it represents the "module" of the API (or an endpoint)
2192 // In order to make the metrics consistent, we want the module to also reflect
2193 // the "collection" of endpoints. The closest we can get is to use the namespace
2194 // of the API module, and get the area of the code or extension it belongs to.
2195 // If module exists, we'll take the namespace for it, otherwise fall back on
2196 // the current namespace. In both cases we'll remove the class name to only keep
2197 // the namespace.
2198 // Since this method can also be called from module classes (ApiQuery, etc)
2199 // we need to allow for accepting the submodule's class name, too, if it's given.
2200 $fullClass = get_class( $this );
2201 $moduleNamespace = substr( $fullClass, 0, strrpos( $fullClass, '\\' ) );
2202
2203 // Get the endpoint representation, which for the moment is the module name.
2204 $endpoint = $this->getModuleName();
2205
2206 // The "path" should give us useful and consistent information about the endpoint.
2207 // The ->getModulePath() method should give us a string wih the module parent and
2208 // its own name, which should be enough to identify the endpoint and work with
2209 // RegEx patterns to extract information from the path.
2210 $path = $this->getModulePath();
2211
2212 // Unified metrics
2213 $metricsLabels = array_merge( [
2214 // This should represent the "collection" of endpoints
2215 'api_module' => $moduleNamespace,
2216 // This is the endpoint that is being executed
2217 'api_endpoint' => $endpoint,
2218 'path' => $path,
2219 'method' => $this->getRequest()->getMethod(),
2220 'status' => "200", // Success
2221 ], $detailLabels );
2222
2223 $approvedLabels = [
2224 'api_module',
2225 'api_endpoint',
2226 'path',
2227 'method',
2228 'status',
2229 ];
2230
2231 // Hit metrics
2232 $metricHitStats = $this->getMain()->getStatsFactory()->getCounter( 'action_api_modules_hit_total' )
2233 ->setLabel( 'api_type', 'ACTION_API' );
2234 foreach ( $approvedLabels as $label ) {
2235 // Set a fallback value for empty strings
2236 $value = (
2237 array_key_exists( $label, $metricsLabels ) &&
2238 is_string( $metricsLabels[$label] ) &&
2239 trim( $metricsLabels[$label] ) !== ''
2240 ) ? $metricsLabels[$label] : 'EMPTY_VALUE';
2241 $metricHitStats->setLabel( $label, $value );
2242 }
2243 $metricHitStats->increment();
2244
2245 // Latency metrics
2246 $metricLatencyStats = $this->getMain()->getStatsFactory()->getTiming( 'action_api_modules_latency' )
2247 ->setLabel( 'api_type', 'ACTION_API' );
2248 // Iterate over the approved labels and set the labels for the metric
2249 foreach ( $approvedLabels as $label ) {
2250 // Set a fallback value for empty strings
2251 $value = (
2252 array_key_exists( $label, $metricsLabels ) &&
2253 is_string( $metricsLabels[$label] ) &&
2254 trim( $metricsLabels[$label] ) !== ''
2255 ) ? $metricsLabels[$label] : 'EMPTY_VALUE';
2256
2257 $metricLatencyStats->setLabel( $label, $value );
2258 }
2259 $metricLatencyStats->observeNanoseconds( $latency );
2260 }
2261
2262 // endregion -- end of Unified metrics methods
2263}
2264
2265/*
2266 * This file uses VisualStudio style region/endregion fold markers which are
2267 * recognised by PHPStorm. If modelines are enabled, the following editor
2268 * configuration will also enable folding in vim, if it is in the last 5 lines
2269 * of the file. We also use "@name" which creates sections in Doxygen.
2270 *
2271 * vim: foldmarker=//\ region,//\ endregion foldmethod=marker
2272 */
2273
2275class_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:68
This abstract class implements many basic API functions, and is the base of all API classes.
Definition ApiBase.php:61
const LIMIT_SML1
Slow query, standard limit.
Definition ApiBase.php:236
dieWithError( $msg, $code=null, $data=null, $httpCode=0)
Abort execution with an error.
Definition ApiBase.php:1511
checkUserRightsAny( $rights)
Helper function for permission-denied errors.
Definition ApiBase.php:1620
getHelpFlags()
Generates the list of flags for the help screen and for action=paraminfo.
Definition ApiBase.php:2059
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:1087
static clearCacheForTest()
Reset static caches of database state.
Definition ApiBase.php:1370
getModulePrefix()
Get parameter prefix (usually two letters or an empty string).
Definition ApiBase.php:552
shouldCheckMaxlag()
Indicates if this module needs maxlag to be checked.
Definition ApiBase.php:398
getModuleName()
Get the name of the module being executed by this instance.
Definition ApiBase.php:543
getSummaryMessage()
Return the summary message.
Definition ApiBase.php:1814
getHookRunner()
Get an ApiHookRunner for running core API hooks.
Definition ApiBase.php:767
const PARAM_VALUE_LINKS
Deprecated and unused.
Definition ApiBase.php:192
const PARAM_HELP_MSG_INFO
(array) Specify additional information tags for the parameter.
Definition ApiBase.php:185
requireAtLeastOneParameter( $params,... $required)
Die if 0 of a certain set of parameters is set and not false.
Definition ApiBase.php:1025
getMain()
Get the main module.
Definition ApiBase.php:561
getModulePath()
Get the path to this module.
Definition ApiBase.php:622
getParameterFromSettings( $name, $settings, $parseLimit)
Using the settings, determine the value for the given parameter.
Definition ApiBase.php:1219
const ALL_DEFAULT_STRING
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:229
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:1056
getWebUITokenSalt(array $params)
Fetch the salt used in the Web UI corresponding to this module.
Definition ApiBase.php:511
static makeMessage( $msg, IContextSource $context, ?array $params=null)
Create a Message from a string or array.
Definition ApiBase.php:1335
dieContinueUsageIf( $condition)
Die with the 'badcontinue' error.
Definition ApiBase.php:1735
useTransactionalTimeLimit()
Call wfTransactionalTimeLimit() if this request was POSTed.
Definition ApiBase.php:1359
parseContinueParamOrDie(string $continue, array $types)
Parse the 'continue' parameter in the usual format and validate the types of each part,...
Definition ApiBase.php:1696
getHelpUrls()
Return links to more detailed help pages about the module.
Definition ApiBase.php:369
getModuleManager()
Get the module manager, or null if this module has no submodules.
Definition ApiBase.php:326
addMessagesFromStatus(StatusValue $status, $types=[ 'warning', 'error'], array $filter=[])
Add warnings and/or errors from a Status.
Definition ApiBase.php:1489
getWatchlistUser( $params)
Gets the user for whom to get the watchlist.
Definition ApiBase.php:1295
getResult()
Get the result object.
Definition ApiBase.php:682
isReadMode()
Indicates whether this module requires read rights.
Definition ApiBase.php:408
const PARAM_HELP_MSG_PER_VALUE
((string|array|Message)[]) When PARAM_TYPE is an array, or 'string' with PARAM_ISMULTI,...
Definition ApiBase.php:207
getCustomPrinter()
If the module may only be used with a certain format module, it should override this method to return...
Definition ApiBase.php:342
logFeatureUsage( $feature)
Write logging information for API features to a debug log, for usage analysis.
Definition ApiBase.php:1759
getExtendedDescription()
Return the extended help text message.
Definition ApiBase.php:1829
isDeprecated()
Indicates whether this module is deprecated.
Definition ApiBase.php:461
requireMaxOneParameter( $params,... $required)
Dies if more than one parameter from a certain set of parameters are set and not false.
Definition ApiBase.php:998
isInternal()
Indicates whether this module is considered to be "internal".
Definition ApiBase.php:474
addWarning( $msg, $code=null, $data=null)
Add a warning for this module.
Definition ApiBase.php:1429
const PARAM_RANGE_ENFORCE
(boolean) Inverse of IntegerDef::PARAM_IGNORE_RANGE
Definition ApiBase.php:156
getFinalDescription()
Get the final module description, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1859
getParent()
Get the parent of this module.
Definition ApiBase.php:582
getDB()
Gets a default replica DB connection object.
Definition ApiBase.php:706
filterIDs( $fields, array $ids)
Filter out-of-range values from a list of positive integer IDs.
Definition ApiBase.php:1386
const LIMIT_SML2
Slow query, apihighlimits limit.
Definition ApiBase.php:238
__construct(ApiMain $mainModule, string $moduleName, string $modulePrefix='')
Definition ApiBase.php:287
const PARAM_HELP_MSG_APPEND
((string|array|Message)[]) Specify additional i18n messages to append to the normal message for this ...
Definition ApiBase.php:175
setContinuationManager(?ApiContinuationManager $manager=null)
Definition ApiBase.php:729
lacksSameOriginSecurity()
Returns true if the current request breaks the same-origin policy.
Definition ApiBase.php:609
dieWithException(Throwable $exception, array $options=[])
Abort execution with an error derived from a throwable.
Definition ApiBase.php:1524
static dieDebug( $method, $message)
Internal code errors should be reported with this method.
Definition ApiBase.php:1748
dieBlocked(Block $block)
Throw an ApiUsageException, which will (if uncaught) call the main module's error handler and die wit...
Definition ApiBase.php:1539
const PARAM_SUBMODULE_PARAM_PREFIX
Definition ApiBase.php:117
getTitleFromTitleOrPageId( $params)
Get a Title object from a title or pageid param, if it is possible.
Definition ApiBase.php:1186
const PARAM_TEMPLATE_VARS
(array) Indicate that this is a templated parameter, and specify replacements.
Definition ApiBase.php:225
const PARAM_HELP_MSG
(string|array|Message) Specify an alternative i18n documentation message for this parameter.
Definition ApiBase.php:167
addError( $msg, $code=null, $data=null)
Add an error for this module without aborting.
Definition ApiBase.php:1476
modifyHelp(array &$help, array $options, array &$tocData)
Called from ApiHelp before the pieces are joined together and returned.
Definition ApiBase.php:2173
execute()
Evaluates the parameters, performs the requested query, and sets up the result.
const LIMIT_BIG2
Fast query, apihighlimits limit.
Definition ApiBase.php:234
encodeParamName( $paramName)
This method mangles parameter name based on the prefix supplied to the constructor.
Definition ApiBase.php:801
getAllowedParams()
Returns an array of allowed parameters (parameter name) => (default value) or (parameter name) => (ar...
Definition ApiBase.php:386
getExamplesMessages()
Returns usage examples for this module.
Definition ApiBase.php:358
recordUnifiedMetrics( $latency=0, $detailLabels=[])
Record unified metrics for the API.
Definition ApiBase.php:2188
addDeprecation( $msg, $feature, $data=[])
Add a deprecation warning for this module.
Definition ApiBase.php:1443
dieStatus(StatusValue $status)
Throw an ApiUsageException based on the Status object.
Definition ApiBase.php:1562
handleParamNormalization( $paramName, $value, $rawValue)
Handle when a parameter was Unicode-normalized.
Definition ApiBase.php:1247
extractRequestParams( $options=[])
Using getAllowedParams(), this function makes an array of the values provided by the user,...
Definition ApiBase.php:823
getPermissionManager()
Obtain a PermissionManager instance that subclasses may use in their authorization checks.
Definition ApiBase.php:742
getConditionalRequestData( $condition)
Returns data for HTTP conditional request mechanisms.
Definition ApiBase.php:528
getFinalParamDescription()
Get final parameter descriptions, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1926
getFinalParams( $flags=0)
Get the final list of parameters, after hooks have had a chance to tweak it as needed.
Definition ApiBase.php:1895
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:1678
getFinalSummary()
Get the final module summary.
Definition ApiBase.php:1843
const PARAM_DEPRECATED_VALUES
Definition ApiBase.php:133
dieReadOnly()
Helper function for readonly errors.
Definition ApiBase.php:1604
checkTitleUserPermissions(PageIdentity $pageIdentity, $actions, array $options=[])
Helper function for permission-denied errors.
Definition ApiBase.php:1643
needsToken()
Returns the token type this module requires in order to execute.
Definition ApiBase.php:497
dynamicParameterDocumentation()
Indicate if the module supports dynamically-determined parameters that cannot be included in self::ge...
Definition ApiBase.php:789
getModuleSourceInfo()
Returns information about the source of this module, if known.
Definition ApiBase.php:2092
isWriteMode()
Indicates whether this module requires write access to the wiki.
Definition ApiBase.php:437
mustBePosted()
Indicates whether this module must be called with a POST request.
Definition ApiBase.php:450
getTitleOrPageId( $params, $load=false)
Attempts to load a WikiPage object from a title or pageid parameter, if possible.
Definition ApiBase.php:1147
validateToken( $token, array $params)
Validate the supplied token.
Definition ApiBase.php:1259
isMain()
Returns true if this module is the main module ($this === $this->mMainModule), false otherwise.
Definition ApiBase.php:571
getModuleFromPath( $path)
Get a module from its module path.
Definition ApiBase.php:642
requireOnlyOneParameter( $params,... $required)
Die if 0 or more than one of a certain set of parameters is set and not false.
Definition ApiBase.php:961
getParameter( $paramName, $parseLimit=true)
Get a value for the given parameter.
Definition ApiBase.php:944
getHookContainer()
Get a HookContainer, for running extension hooks or for hook metadata.
Definition ApiBase.php:752
const GET_VALUES_FOR_HELP
getAllowedParams() flag: When this is set, the result could take longer to generate,...
Definition ApiBase.php:245
const LIMIT_BIG1
Fast query, standard limit.
Definition ApiBase.php:232
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:1352
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'=> false, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 250, 300,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailStepsRatio'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'EnableSpecialMute'=> false, 'EnableUserEmailMuteList'=> false, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'UserEmailConfirmationUseHTML'=> false, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ImageLinksSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400, 'WarmParsoidParserCache'=> false,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'PHPSessionHandling'=> 'warn', 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> '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, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editviewmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editviewmywatchlist' => 'low', 'editmycssjs' => 'security', 'editmyoptions' => 'security', 'editinterface' => 'vandalism', 'editsiteconfig' => 'security', 'rollback' => 'low', 'blockusers' => 'vandalism', 'delete' => 'vandalism', 'viewdeleted' => 'vandalism', 'viewrestrictedlogs' => 'security', 'protect' => 'vandalism', 'oversight' => 'security', 'createaccount' => 'low', 'mergehistory' => 'vandalism', 'import' => 'security', 'highvolume' => 'low', 'privateinfo' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'CachePrefix' => false, 'DebugToolbar' => false, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCEngines' => [ 'redis' => 'MediaWiki\\RCFeed\\RedisPubSubFeedEngine', 'udp' => 'MediaWiki\\RCFeed\\UDPRCFeedEngine', ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'cdnPurge' => 'MediaWiki\\JobQueue\\Jobs\\CdnPurgeJob', 'userGroupExpiry' => 'MediaWiki\\User\\UserGroupExpiryJob', 'clearWatchlistNotifications' => 'MediaWiki\\Watchlist\\ClearWatchlistNotificationsJob', 'userOptionsUpdate' => 'MediaWiki\\User\\Options\\UserOptionsUpdateJob', 'revertedTagUpdate' => 'MediaWiki\\JobQueue\\Jobs\\RevertedTagUpdateJob', 'null' => 'MediaWiki\\JobQueue\\Jobs\\NullJob', 'userEditCountInit' => 'MediaWiki\\User\\UserEditCountInitJob', 'parsoidCachePrewarm' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\ParsoidCachePrewarmJob', 'services' => [ 'ParserOutputAccess', 'PageStore', 'RevisionLookup', 'ParsoidSiteConfig', ], 'needsPage' => false, ], 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestSandboxSpecs' => [ ], 'MaxShellMemory' => 307200, 'MaxShellFileSize' => 102400, 'MaxShellTime' => 180, 'MaxShellWallClockTime' => 180, 'ShellCgroup' => false, 'PhpCli' => '/usr/bin/php', 'ShellRestrictionMethod' => 'autodetect', 'ShellboxUrls' => [ 'default' => null, ], 'ShellboxSecretKey' => null, 'ShellboxShell' => '/bin/sh', 'HTTPTimeout' => 25, 'HTTPConnectTimeout' => 5.0, 'HTTPMaxTimeout' => 0, 'HTTPMaxConnectTimeout' => 0, 'HTTPImportTimeout' => 25, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => null, 'VirtualRestConfig' => [ 'paths' => [ ], 'modules' => [ ], 'global' => [ 'timeout' => 360, 'forwardCookies' => false, 'HTTPProxy' => null, ], ], 'EventRelayerConfig' => [ 'default' => [ 'class' => 'Wikimedia\\EventRelayer\\EventRelayerNull', ], ], 'Pingback' => false, 'OriginTrials' => [ ], 'ReportToExpiry' => 86400, 'ReportToEndpoints' => [ ], 'FeaturePolicyReportOnly' => [ ], 'SkinsPreferred' => [ 'vector-2022', 'vector', ], 'SpecialContributeSkinsEnabled' => [ ], 'SpecialContributeNewPageTarget' => null, 'EnableEditRecovery' => false, 'EditRecoveryExpiry' => 2592000, 'UseCodexSpecialBlock' => false, 'ShowLogoutConfirmation' => false, 'EnableProtectionIndicators' => true, 'OutputPipelineStages' => [ ], 'FeatureShutdown' => [ ], 'CloneArticleParserOutput' => true, 'UseLeximorph' => false, 'UsePostprocCache' => false, 'ParserOptionsLogUnsafeSampleRate' => 0, ], 'type' => [ 'ConfigRegistry' => 'object', 'AssumeProxiesUseDefaultProtocolPorts' => 'boolean', 'ForceHTTPS' => 'boolean', 'ExtensionDirectory' => [ 'string', 'null', ], 'StyleDirectory' => [ 'string', 'null', ], 'UploadDirectory' => [ 'string', 'boolean', 'null', ], 'Logos' => [ 'object', 'boolean', ], 'ReferrerPolicy' => [ 'array', 'string', 'boolean', ], 'ActionPaths' => 'object', 'MainPageIsDomainRoot' => 'boolean', 'ImgAuthUrlPathMap' => 'object', 'LocalFileRepo' => 'object', 'ForeignFileRepos' => 'array', 'UseSharedUploads' => 'boolean', 'SharedUploadDirectory' => [ 'string', 'null', ], 'SharedUploadPath' => [ 'string', 'null', ], 'HashedSharedUploadDirectory' => 'boolean', 'FetchCommonsDescriptions' => 'boolean', 'SharedUploadDBname' => [ 'boolean', 'string', ], 'SharedUploadDBprefix' => 'string', 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailStepsRatio' => [ 'number', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'UserEmailConfirmationUseHTML' => 'boolean', 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ImageLinksSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => 'string', 'PHPSessionHandling' => 'string', 'SuspiciousIpExpiry' => [ 'integer', 'boolean', ], 'MemCachedServers' => 'array', 'LocalisationCacheConf' => 'object', 'ExtensionInfoMTime' => [ 'integer', 'boolean', ], 'CdnServers' => 'object', 'CdnServersNoPurge' => 'object', 'HTCPRouting' => 'object', 'GrammarForms' => 'object', 'ExtraInterlanguageLinkPrefixes' => 'array', 'InterlanguageLinkCodeMap' => 'object', 'ExtraLanguageNames' => 'object', 'ExtraLanguageCodes' => 'object', 'DummyLanguageCodes' => 'object', 'DisabledVariants' => 'object', 'ForceUIMsgAsContentMsg' => 'object', 'RawHtmlMessages' => 'array', 'OverrideUcfirstCharacters' => 'object', 'XhtmlNamespaces' => 'object', 'BrowserFormatDetection' => 'string', 'SkinMetaTags' => 'object', 'SkipSkins' => 'object', 'FragmentMode' => 'array', 'FooterIcons' => 'object', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'RCEngines' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestSandboxSpecs' => 'object', 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'VirtualRestConfig' => 'object', 'EventRelayerConfig' => 'object', 'Pingback' => 'boolean', 'OriginTrials' => 'array', 'ReportToExpiry' => 'integer', 'ReportToEndpoints' => 'array', 'FeaturePolicyReportOnly' => 'array', 'SkinsPreferred' => 'array', 'SpecialContributeSkinsEnabled' => 'array', 'SpecialContributeNewPageTarget' => [ 'string', 'null', ], 'EnableEditRecovery' => 'boolean', 'EditRecoveryExpiry' => 'integer', 'UseCodexSpecialBlock' => 'boolean', 'ShowLogoutConfirmation' => 'boolean', 'EnableProtectionIndicators' => 'boolean', 'OutputPipelineStages' => 'object', 'FeatureShutdown' => 'array', 'CloneArticleParserOutput' => 'boolean', 'UseLeximorph' => 'boolean', 'UsePostprocCache' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', ], 'mergeStrategy' => [ 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'VirtualRestConfig' => 'array_plus_2d', ], 'dynamicDefault' => [ 'UsePathInfo' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUsePathInfo', ], ], 'Script' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultScript', ], ], 'LoadScript' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLoadScript', ], ], 'RestPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultRestPath', ], ], 'StylePath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultStylePath', ], ], 'LocalStylePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalStylePath', ], ], 'ExtensionAssetsPath' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultExtensionAssetsPath', ], ], 'ArticlePath' => [ 'use' => [ 'Script', 'UsePathInfo', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultArticlePath', ], ], 'UploadPath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultUploadPath', ], ], 'FileCacheDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultFileCacheDirectory', ], ], 'Logo' => [ 'use' => [ 'ResourceBasePath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLogo', ], ], 'DeletedDirectory' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDeletedDirectory', ], ], 'ShowEXIF' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultShowEXIF', ], ], 'SharedPrefix' => [ 'use' => [ 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedPrefix', ], ], 'SharedSchema' => [ 'use' => [ 'DBmwschema', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultSharedSchema', ], ], 'DBerrorLogTZ' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultDBerrorLogTZ', ], ], 'Localtimezone' => [ 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocaltimezone', ], ], 'LocalTZoffset' => [ 'use' => [ 'Localtimezone', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultLocalTZoffset', ], ], 'ResourceBasePath' => [ 'use' => [ 'ScriptPath', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultResourceBasePath', ], ], 'MetaNamespace' => [ 'use' => [ 'Sitename', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultMetaNamespace', ], ], 'CookieSecure' => [ 'use' => [ 'ForceHTTPS', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookieSecure', ], ], 'CookiePrefix' => [ 'use' => [ 'SharedDB', 'SharedPrefix', 'SharedTables', 'DBname', 'DBprefix', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultCookiePrefix', ], ], 'ReadOnlyFile' => [ 'use' => [ 'UploadDirectory', ], 'callback' => [ 'MediaWiki\\MainConfigSchema', 'getDefaultReadOnlyFile', ], ], ], ], 'config-schema' => [ 'UploadStashScalerBaseUrl' => [ 'deprecated' => 'since 1.36 Use thumbProxyUrl in $wgLocalFileRepo', ], 'IllegalFileChars' => [ 'deprecated' => 'since 1.41; no longer customizable', ], 'ThumbnailNamespaces' => [ 'items' => [ 'type' => 'integer', ], ], 'LocalDatabases' => [ 'items' => [ 'type' => 'string', ], ], 'ParserCacheFilterConfig' => [ 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of namespace IDs to filter definitions.', 'additionalProperties' => [ 'type' => 'object', 'description' => 'A map of filter names to values.', 'properties' => [ 'minCpuTime' => [ 'type' => 'number', ], ], ], ], ], 'PHPSessionHandling' => [ 'deprecated' => 'since 1.45 Integration with PHP session handling will be removed in the future', ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'AllowSecuritySensitiveOperationIfCannotReauthenticate' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'ChangeCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'RemoveCredentialsBlacklist' => [ 'items' => [ 'type' => 'string', ], ], 'GroupPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GroupInheritsPermissions' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'AvailableRights' => [ 'items' => [ 'type' => 'string', ], ], 'ImplicitRights' => [ 'items' => [ 'type' => 'string', ], ], 'SoftBlockRanges' => [ 'items' => [ 'type' => 'string', ], ], 'ExternalQuerySources' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'enabled' => [ 'type' => 'boolean', 'default' => false, ], 'url' => [ 'type' => 'string', 'format' => 'uri', ], 'timeout' => [ 'type' => 'integer', 'default' => 10, ], ], 'required' => [ 'enabled', 'url', ], 'additionalProperties' => false, ], ], 'GrantPermissions' => [ 'additionalProperties' => [ 'type' => 'object', 'additionalProperties' => [ 'type' => 'boolean', ], ], ], 'GrantPermissionGroups' => [ 'additionalProperties' => [ 'type' => 'string', ], ], 'SitemapNamespacesPriorities' => [ 'deprecated' => 'since 1.45 and ignored', ], 'SitemapApiConfig' => [ 'additionalProperties' => [ 'enabled' => [ 'type' => 'bool', ], 'sitemapsPerIndex' => [ 'type' => 'int', ], 'pagesPerSitemap' => [ 'type' => 'int', ], 'expiry' => [ 'type' => 'int', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestSandboxSpecs' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'url' => [ 'type' => 'string', 'format' => 'url', ], 'name' => [ 'type' => 'string', ], 'msg' => [ 'type' => 'string', 'description' => 'a message key', ], ], 'required' => [ 'url', ], ], ], 'ShellboxUrls' => [ 'additionalProperties' => [ 'type' => [ 'string', 'boolean', 'null', ], ], ], ], 'obsolete-config' => [ 'MangleFlashPolicy' => 'Since 1.39; no longer has any effect.', 'EnableOpenSearchSuggest' => 'Since 1.35, no longer used', 'AutoloadAttemptLowercase' => 'Since 1.40; no longer has any effect.', ],]
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.