MediaWiki master
FileRepo.php
Go to the documentation of this file.
1<?php
10namespace MediaWiki\FileRepo;
11
12use InvalidArgumentException;
13use LogicException;
27use RuntimeException;
28use Shellbox\Command\BoxedCommand;
29use StatusValue;
35
51class FileRepo {
52 public const DELETE_SOURCE = 1;
53 public const OVERWRITE = 2;
54 public const OVERWRITE_SAME = 4;
56 public const SKIP_LOCKING = 8;
57
58 public const NAME_AND_TIME_ONLY = 1;
59
64
67
69 protected $hasSha1Storage = false;
70
72 protected $supportsSha1URLs = false;
73
75 protected $backend;
76
78 protected $zones = [];
79
81 protected $thumbScriptUrl;
82
87
91 protected $descBaseUrl;
92
96 protected $scriptDirUrl;
97
99 protected $articleUrl;
100
107
113 protected $pathDisclosureProtection = 'simple';
114
116 protected $url;
117
119 protected $thumbUrl;
120
122 protected $hashLevels;
123
126
132
134 protected $favicon = null;
135
137 protected $isPrivate;
138
140 protected $fileFactory = [ UnregisteredLocalFile::class, 'newFromTitle' ];
142 protected $oldFileFactory = false;
144 protected $fileFactoryKey = false;
146 protected $oldFileFactoryKey = false;
147
151 protected $thumbProxyUrl;
154
156 protected $disableLocalTransform = false;
157
159 protected $wanCache;
160
166 public $name;
167
173 public function __construct( ?array $info = null ) {
174 // Verify required settings presence
175 if (
176 $info === null
177 || !array_key_exists( 'name', $info )
178 || !array_key_exists( 'backend', $info )
179 ) {
180 throw new InvalidArgumentException( __CLASS__ .
181 " requires an array of options having both 'name' and 'backend' keys.\n" );
182 }
183
184 // Required settings
185 $this->name = $info['name'];
186 if ( $info['backend'] instanceof FileBackend ) {
187 $this->backend = $info['backend']; // useful for testing
188 } else {
189 $this->backend =
190 MediaWikiServices::getInstance()->getFileBackendGroup()->get( $info['backend'] );
191 }
192
193 // Optional settings that can have no value
194 $optionalSettings = [
195 'descBaseUrl', 'scriptDirUrl', 'articleUrl', 'fetchDescription',
196 'thumbScriptUrl', 'pathDisclosureProtection', 'descriptionCacheExpiry',
197 'favicon', 'thumbProxyUrl', 'thumbProxySecret', 'disableLocalTransform'
198 ];
199 foreach ( $optionalSettings as $var ) {
200 if ( isset( $info[$var] ) ) {
201 $this->$var = $info[$var];
202 }
203 }
204
205 // Optional settings that have a default
206 $localCapitalLinks =
207 MediaWikiServices::getInstance()->getNamespaceInfo()->isCapitalized( NS_FILE );
208 $this->initialCapital = $info['initialCapital'] ?? $localCapitalLinks;
209 if ( $localCapitalLinks && !$this->initialCapital ) {
210 // If the local wiki's file namespace requires an initial capital, but a foreign file
211 // repo doesn't, complications will result. Linker code will want to auto-capitalize the
212 // first letter of links to files, but those links might actually point to files on
213 // foreign wikis with initial-lowercase names. This combination is not likely to be
214 // used by anyone anyway, so we just outlaw it to save ourselves the bugs. If you want
215 // to include a foreign file repo with initialCapital false, set your local file
216 // namespace to not be capitalized either.
217 throw new InvalidArgumentException(
218 'File repos with initial capital false are not allowed on wikis where the File ' .
219 'namespace has initial capital true' );
220 }
221
222 $this->url = $info['url'] ?? false; // a subclass may set the URL (e.g. ForeignAPIRepo)
223 $this->thumbUrl = $info['thumbUrl'] ?? ( $this->url ? $this->url . '/thumb' : false );
224 $this->hashLevels = $info['hashLevels'] ?? 2;
225 $this->deletedHashLevels = $info['deletedHashLevels'] ?? $this->hashLevels;
226 $this->transformVia404 = !empty( $info['transformVia404'] );
227 $this->abbrvThreshold = $info['abbrvThreshold'] ?? 255;
228 $this->isPrivate = !empty( $info['isPrivate'] );
229 // Give defaults for the basic zones...
230 $this->zones = $info['zones'] ?? [];
231 foreach ( [ 'public', 'thumb', 'transcoded', 'temp', 'deleted' ] as $zone ) {
232 if ( !isset( $this->zones[$zone]['container'] ) ) {
233 $this->zones[$zone]['container'] = "{$this->name}-{$zone}";
234 }
235 if ( !isset( $this->zones[$zone]['directory'] ) ) {
236 $this->zones[$zone]['directory'] = '';
237 }
238 if ( !isset( $this->zones[$zone]['urlsByExt'] ) ) {
239 $this->zones[$zone]['urlsByExt'] = [];
240 }
241 }
242
243 $this->supportsSha1URLs = !empty( $info['supportsSha1URLs'] );
244
245 $this->wanCache = $info['wanCache'] ?? WANObjectCache::newEmpty();
246 }
247
253 public function getBackend() {
254 return $this->backend;
255 }
256
263 protected function getBackendOperationOptions(): array {
264 return [];
265 }
266
273 public function getReadOnlyReason() {
274 return $this->backend->getReadOnlyReason();
275 }
276
282 protected function initZones( $doZones = [] ): void {
283 foreach ( (array)$doZones as $zone ) {
284 $root = $this->getZonePath( $zone );
285 if ( $root === null ) {
286 throw new RuntimeException( "No '$zone' zone defined in the {$this->name} repo." );
287 }
288 }
289 }
290
297 public static function isVirtualUrl( $url ) {
298 return str_starts_with( $url, 'mwrepo://' );
299 }
300
309 public function getVirtualUrl( $suffix = false ) {
310 $path = 'mwrepo://' . $this->name;
311 if ( $suffix !== false ) {
312 $path .= '/' . rawurlencode( $suffix );
313 }
314
315 return $path;
316 }
317
325 public function getZoneUrl( $zone, $ext = null ) {
326 if ( in_array( $zone, [ 'public', 'thumb', 'transcoded' ] ) ) {
327 // standard public zones
328 if ( $ext !== null && isset( $this->zones[$zone]['urlsByExt'][$ext] ) ) {
329 // custom URL for extension/zone
330 // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
331 return $this->zones[$zone]['urlsByExt'][$ext];
332 } elseif ( isset( $this->zones[$zone]['url'] ) ) {
333 // custom URL for zone
334 return $this->zones[$zone]['url'];
335 }
336 }
337 switch ( $zone ) {
338 case 'public':
339 return $this->url;
340 case 'temp':
341 case 'deleted':
342 return false; // no public URL
343 case 'thumb':
344 return $this->thumbUrl;
345 case 'transcoded':
346 return "{$this->url}/transcoded";
347 default:
348 return false;
349 }
350 }
351
355 public function backendSupportsUnicodePaths() {
356 return (bool)( $this->getBackend()->getFeatures() & FileBackend::ATTR_UNICODE_PATHS );
357 }
358
367 public function resolveVirtualUrl( $url ) {
368 if ( !str_starts_with( $url, 'mwrepo://' ) ) {
369 throw new InvalidArgumentException( __METHOD__ . ': unknown protocol' );
370 }
371 $bits = explode( '/', substr( $url, 9 ), 3 );
372 if ( count( $bits ) != 3 ) {
373 throw new InvalidArgumentException( __METHOD__ . ": invalid mwrepo URL: $url" );
374 }
375 [ $repo, $zone, $rel ] = $bits;
376 if ( $repo !== $this->name ) {
377 throw new InvalidArgumentException( __METHOD__ . ": fetching from a foreign repo is not supported" );
378 }
379 $base = $this->getZonePath( $zone );
380 if ( !$base ) {
381 throw new InvalidArgumentException( __METHOD__ . ": invalid zone: $zone" );
382 }
383
384 return $base . '/' . rawurldecode( $rel );
385 }
386
393 protected function getZoneLocation( $zone ) {
394 if ( !isset( $this->zones[$zone] ) ) {
395 return [ null, null ]; // bogus
396 }
397
398 return [ $this->zones[$zone]['container'], $this->zones[$zone]['directory'] ];
399 }
400
407 public function getZonePath( $zone ) {
408 [ $container, $base ] = $this->getZoneLocation( $zone );
409 if ( $container === null || $base === null ) {
410 return null;
411 }
412 $backendName = $this->backend->getName();
413 if ( $base != '' ) { // may not be set
414 $base = "/{$base}";
415 }
416
417 return "mwstore://$backendName/{$container}{$base}";
418 }
419
431 public function newFile( $title, $time = false ) {
432 $title = File::normalizeTitle( $title );
433 if ( !$title ) {
434 return null;
435 }
436 if ( $time ) {
437 if ( $this->oldFileFactory ) {
438 return ( $this->oldFileFactory )( $title, $this, $time );
439 } else {
440 return null;
441 }
442 } else {
443 return ( $this->fileFactory )( $title, $this );
444 }
445 }
446
466 public function findFile( $title, $options = [] ) {
467 if ( !empty( $options['private'] ) && !( $options['private'] instanceof Authority ) ) {
468 throw new InvalidArgumentException(
469 __METHOD__ . ' called with the `private` option set to something ' .
470 'other than an Authority object'
471 );
472 }
473
474 $title = File::normalizeTitle( $title );
475 if ( !$title ) {
476 return false;
477 }
478 if ( isset( $options['bypassCache'] ) ) {
479 $options['latest'] = $options['bypassCache']; // b/c
480 }
481 $time = $options['time'] ?? false;
482 $flags = !empty( $options['latest'] ) ? IDBAccessObject::READ_LATEST : 0;
483 # First try the current version of the file to see if it precedes the timestamp
484 $img = $this->newFile( $title );
485 if ( !$img ) {
486 return false;
487 }
488 $img->load( $flags );
489 if ( $img->exists() && ( !$time || $img->getTimestamp() == $time ) ) {
490 return $img;
491 }
492 # Now try an old version of the file
493 if ( $time !== false ) {
494 $img = $this->newFile( $title, $time );
495 if ( $img ) {
496 $img->load( $flags );
497 if ( $img->exists() ) {
498 if ( !$img->isDeleted( File::DELETED_FILE ) ) {
499 return $img; // always OK
500 } elseif (
501 // If its not empty, its an Authority object
502 !empty( $options['private'] ) &&
503 $img->userCan( File::DELETED_FILE, $options['private'] )
504 ) {
505 return $img;
506 }
507 }
508 }
509 }
510
511 # Now try redirects
512 if ( !empty( $options['ignoreRedirect'] ) ) {
513 return false;
514 }
515 $redir = $this->checkRedirect( $title );
516 if ( $redir && $title->getNamespace() === NS_FILE ) {
517 $img = $this->newFile( $redir );
518 if ( !$img ) {
519 return false;
520 }
521 $img->load( $flags );
522 if ( $img->exists() ) {
523 $img->redirectedFrom( $title->getDBkey() );
524
525 return $img;
526 }
527 }
528
529 return false;
530 }
531
549 public function findFiles( array $items, $flags = 0 ) {
550 $result = [];
551 foreach ( $items as $item ) {
552 if ( is_array( $item ) ) {
553 $title = $item['title'];
554 $options = $item;
555 unset( $options['title'] );
556
557 if (
558 !empty( $options['private'] ) &&
559 !( $options['private'] instanceof Authority )
560 ) {
561 $options['private'] = RequestContext::getMain()->getAuthority();
562 }
563 } else {
564 $title = $item;
565 $options = [];
566 }
567 $file = $this->findFile( $title, $options );
568 if ( $file ) {
569 $searchName = File::normalizeTitle( $title )->getDBkey(); // must be valid
570 if ( $flags & self::NAME_AND_TIME_ONLY ) {
571 $result[$searchName] = [
572 'title' => $file->getTitle()->getDBkey(),
573 'timestamp' => $file->getTimestamp()
574 ];
575 } else {
576 $result[$searchName] = $file;
577 }
578 }
579 }
580
581 return $result;
582 }
583
594 public function findFileFromKey( $sha1, $options = [] ) {
595 if ( !empty( $options['private'] ) && !( $options['private'] instanceof Authority ) ) {
596 throw new InvalidArgumentException(
597 __METHOD__ . ' called with the `private` option set to something ' .
598 'other than an Authority object'
599 );
600 }
601
602 $time = $options['time'] ?? false;
603 # First try to find a matching current version of a file...
604 if ( !$this->fileFactoryKey ) {
605 return false; // find-by-sha1 not supported
606 }
607 $img = ( $this->fileFactoryKey )( $sha1, $this, $time );
608 if ( $img && $img->exists() ) {
609 return $img;
610 }
611 # Now try to find a matching old version of a file...
612 if ( $time !== false && $this->oldFileFactoryKey ) { // find-by-sha1 supported?
613 $img = ( $this->oldFileFactoryKey )( $sha1, $this, $time );
614 if ( $img && $img->exists() ) {
615 if ( !$img->isDeleted( File::DELETED_FILE ) ) {
616 return $img; // always OK
617 } elseif (
618 // If its not empty, its an Authority object
619 !empty( $options['private'] ) &&
620 $img->userCan( File::DELETED_FILE, $options['private'] )
621 ) {
622 return $img;
623 }
624 }
625 }
626
627 return false;
628 }
629
638 public function findBySha1( $hash ) {
639 return [];
640 }
641
649 public function findBySha1s( array $hashes ) {
650 $result = [];
651 foreach ( $hashes as $hash ) {
652 $files = $this->findBySha1( $hash );
653 if ( count( $files ) ) {
654 $result[$hash] = $files;
655 }
656 }
657
658 return $result;
659 }
660
669 public function findFilesByPrefix( $prefix, $limit ) {
670 return [];
671 }
672
678 public function getThumbScriptUrl() {
679 return $this->thumbScriptUrl;
680 }
681
687 public function getThumbProxyUrl() {
688 return $this->thumbProxyUrl;
689 }
690
696 public function getThumbProxySecret() {
697 return $this->thumbProxySecret;
698 }
699
705 public function canTransformVia404() {
706 return $this->transformVia404;
707 }
708
715 public function canTransformLocally() {
716 return !$this->disableLocalTransform;
717 }
718
725 public function getNameFromTitle( $title ) {
726 if (
727 $this->initialCapital !=
728 MediaWikiServices::getInstance()->getNamespaceInfo()->isCapitalized( NS_FILE )
729 ) {
730 $name = $title->getDBkey();
731 if ( $this->initialCapital ) {
732 $name = MediaWikiServices::getInstance()->getContentLanguage()->ucfirst( $name );
733 }
734 } else {
735 $name = $title->getDBkey();
736 }
737
738 return $name;
739 }
740
746 public function getRootDirectory() {
747 return $this->getZonePath( 'public' );
748 }
749
757 public function getHashPath( $name ) {
758 return self::getHashPathForLevel( $name, $this->hashLevels );
759 }
760
768 public function getTempHashPath( $suffix ) {
769 $parts = explode( '!', $suffix, 2 ); // format is <timestamp>!<name> or just <name>
770 $name = $parts[1] ?? $suffix; // hash path is not based on timestamp
771 return self::getHashPathForLevel( $name, $this->hashLevels );
772 }
773
779 protected static function getHashPathForLevel( $name, $levels ) {
780 if ( $levels == 0 ) {
781 return '';
782 } else {
783 $hash = md5( $name );
784 $path = '';
785 for ( $i = 1; $i <= $levels; $i++ ) {
786 $path .= substr( $hash, 0, $i ) . '/';
787 }
788
789 return $path;
790 }
791 }
792
798 public function getHashLevels() {
799 return $this->hashLevels;
800 }
801
807 public function getName() {
808 return $this->name;
809 }
810
818 public function makeUrl( $query = '', $entry = 'index' ) {
819 if ( $this->scriptDirUrl !== null ) {
820 return wfAppendQuery( "{$this->scriptDirUrl}/{$entry}.php", $query );
821 }
822
823 return false;
824 }
825
838 public function getDescriptionUrl( $name ) {
839 $encName = wfUrlencode( $name );
840 if ( $this->descBaseUrl !== null ) {
841 # "http://example.com/wiki/File:"
842 return $this->descBaseUrl . $encName;
843 }
844 if ( $this->articleUrl !== null ) {
845 # "http://example.com/wiki/$1"
846 # We use "Image:" as the canonical namespace for
847 # compatibility across all MediaWiki versions.
848 return str_replace( '$1',
849 "Image:$encName", $this->articleUrl );
850 }
851 if ( $this->scriptDirUrl !== null ) {
852 # "http://example.com/w"
853 # We use "Image:" as the canonical namespace for
854 # compatibility across all MediaWiki versions,
855 # and just sort of hope index.php is right. ;)
856 return $this->makeUrl( "title=Image:$encName" );
857 }
858
859 return false;
860 }
861
872 public function getDescriptionRenderUrl( $name, $lang = null ) {
873 $query = 'action=render';
874 if ( $lang !== null ) {
875 $query .= '&uselang=' . urlencode( $lang );
876 }
877 if ( $this->scriptDirUrl !== null ) {
878 return $this->makeUrl(
879 'title=' .
880 wfUrlencode( 'Image:' . $name ) .
881 "&$query" );
882 } else {
883 $descUrl = $this->getDescriptionUrl( $name );
884 if ( $descUrl ) {
885 return wfAppendQuery( $descUrl, $query );
886 } else {
887 return false;
888 }
889 }
890 }
891
897 public function getDescriptionStylesheetUrl() {
898 if ( $this->scriptDirUrl !== null ) {
899 // Must match canonical query parameter order for optimum caching
900 // See HTMLCacheUpdater::getUrls
901 return $this->makeUrl( 'title=MediaWiki:Filepage.css&action=raw&ctype=text/css' );
902 }
903
904 return false;
905 }
906
923 public function store( $srcPath, $dstZone, $dstRel, $flags = 0 ) {
924 $this->assertWritableRepo(); // fail out if read-only
925
926 $status = $this->storeBatch( [ [ $srcPath, $dstZone, $dstRel ] ], $flags );
927 if ( $status->successCount == 0 ) {
928 $status->setOK( false );
929 }
930
931 return $status;
932 }
933
946 public function storeBatch( array $triplets, $flags = 0 ) {
947 $this->assertWritableRepo(); // fail out if read-only
948
949 if ( $flags & self::DELETE_SOURCE ) {
950 throw new InvalidArgumentException( "DELETE_SOURCE not supported in " . __METHOD__ );
951 }
952
953 $status = $this->newGood();
954 $backend = $this->backend; // convenience
955
956 $operations = [];
957 // Validate each triplet and get the store operation...
958 foreach ( $triplets as [ $src, $dstZone, $dstRel ] ) {
959 $srcPath = ( $src instanceof FSFile ) ? $src->getPath() : $src;
960 wfDebug( __METHOD__
961 . "( \$src='$srcPath', \$dstZone='$dstZone', \$dstRel='$dstRel' )"
962 );
963 // Resolve source path
964 if ( $src instanceof FSFile ) {
965 $op = 'store';
966 } else {
967 $src = $this->resolveToStoragePathIfVirtual( $src );
968 $op = FileBackend::isStoragePath( $src ) ? 'copy' : 'store';
969 }
970 // Resolve destination path
971 $root = $this->getZonePath( $dstZone );
972 if ( !$root ) {
973 throw new RuntimeException( "Invalid zone: $dstZone" );
974 }
975 if ( !$this->validateFilename( $dstRel ) ) {
976 throw new RuntimeException( 'Validation error in $dstRel' );
977 }
978 $dstPath = "$root/$dstRel";
979 $dstDir = dirname( $dstPath );
980 // Create destination directories for this triplet
981 if ( !$this->initDirectory( $dstDir )->isOK() ) {
982 return $this->newFatal( 'directorycreateerror', $dstDir );
983 }
984
985 // Copy the source file to the destination
986 $operations[] = [
987 'op' => $op,
988 'src' => $src, // storage path (copy) or local file path (store)
989 'dst' => $dstPath,
990 'overwrite' => (bool)( $flags & self::OVERWRITE ),
991 'overwriteSame' => (bool)( $flags & self::OVERWRITE_SAME ),
992 ];
993 }
994
995 // Execute the store operation for each triplet
996 $opts = $this->getBackendOperationOptions();
997 // Attempt each operation regardless of others failing
998 $opts['force'] = true;
999
1000 return $status->merge( $backend->doOperations( $operations, $opts ) );
1001 }
1002
1012 public function cleanupBatch( array $files, $flags = 0 ) {
1013 $this->assertWritableRepo(); // fail out if read-only
1014
1015 $status = $this->newGood();
1016
1017 $operations = [];
1018 foreach ( $files as $path ) {
1019 if ( is_array( $path ) ) {
1020 // This is a pair, extract it
1021 [ $zone, $rel ] = $path;
1022 $path = $this->getZonePath( $zone ) . "/$rel";
1023 } else {
1024 // Resolve source to a storage path if virtual
1025 $path = $this->resolveToStoragePathIfVirtual( $path );
1026 }
1027 $operations[] = [ 'op' => 'delete', 'src' => $path ];
1028 }
1029
1030 $opts = $this->getBackendOperationOptions();
1031 // Attempt each operation regardless of others failing
1032 $opts['force'] = true;
1033
1034 return $status->merge( $this->backend->doOperations( $operations, $opts ) );
1035 }
1036
1054 final public function quickImport( $src, $dst, $options = null ) {
1055 return $this->quickImportBatch( [ [ $src, $dst, $options ] ] );
1056 }
1057
1072 public function quickImportBatch( array $triples ) {
1073 $status = $this->newGood();
1074 $operations = [];
1075 foreach ( $triples as $triple ) {
1076 [ $src, $dst ] = $triple;
1077 if ( $src instanceof FSFile ) {
1078 $op = 'store';
1079 } else {
1080 $src = $this->resolveToStoragePathIfVirtual( $src );
1081 $op = FileBackend::isStoragePath( $src ) ? 'copy' : 'store';
1082 }
1083 $dst = $this->resolveToStoragePathIfVirtual( $dst );
1084
1085 if ( !isset( $triple[2] ) ) {
1086 $headers = [];
1087 } elseif ( is_string( $triple[2] ) ) {
1088 // back-compat
1089 $headers = [ 'Content-Disposition' => $triple[2] ];
1090 } elseif ( is_array( $triple[2] ) && isset( $triple[2]['headers'] ) ) {
1091 $headers = $triple[2]['headers'];
1092 } else {
1093 $headers = [];
1094 }
1095
1096 $operations[] = [
1097 'op' => $op,
1098 'src' => $src, // storage path (copy) or local path/FSFile (store)
1099 'dst' => $dst,
1100 'headers' => $headers
1101 ];
1102 $status->merge( $this->initDirectory( dirname( $dst ) ) );
1103 }
1104
1105 return $status->merge( $this->backend->doQuickOperations( $operations ) );
1106 }
1107
1116 final public function quickPurge( $path ) {
1117 return $this->quickPurgeBatch( [ $path ] );
1118 }
1119
1127 public function quickCleanDir( $dir ) {
1128 return $this->newGood()->merge(
1129 $this->backend->clean(
1130 [ 'dir' => $this->resolveToStoragePathIfVirtual( $dir ) ]
1131 )
1132 );
1133 }
1134
1143 public function quickPurgeBatch( array $paths ) {
1144 $status = $this->newGood();
1145 $operations = [];
1146 foreach ( $paths as $path ) {
1147 $operations[] = [
1148 'op' => 'delete',
1149 'src' => $this->resolveToStoragePathIfVirtual( $path ),
1150 'ignoreMissingSource' => true
1151 ];
1152 }
1153 $status->merge( $this->backend->doQuickOperations( $operations ) );
1154
1155 return $status;
1156 }
1157
1168 public function storeTemp( $originalName, $srcPath ) {
1169 $this->assertWritableRepo(); // fail out if read-only
1170
1171 $date = MWTimestamp::getInstance()->format( 'YmdHis' );
1172 $hashPath = $this->getHashPath( $originalName );
1173 $dstUrlRel = $hashPath . $date . '!' . rawurlencode( $originalName );
1174 $virtualUrl = $this->getVirtualUrl( 'temp' ) . '/' . $dstUrlRel;
1175
1176 $result = $this->quickImport( $srcPath, $virtualUrl );
1177 $result->value = $virtualUrl;
1178
1179 return $result;
1180 }
1181
1188 public function freeTemp( $virtualUrl ) {
1189 $this->assertWritableRepo(); // fail out if read-only
1190
1191 $temp = $this->getVirtualUrl( 'temp' );
1192 if ( !str_starts_with( $virtualUrl, $temp ) ) {
1193 wfDebug( __METHOD__ . ": Invalid temp virtual URL" );
1194
1195 return false;
1196 }
1197
1198 return $this->quickPurge( $virtualUrl )->isOK();
1199 }
1200
1210 public function concatenate( array $srcPaths, $dstPath, $flags = 0 ) {
1211 $this->assertWritableRepo(); // fail out if read-only
1212
1213 $status = $this->newGood();
1214
1215 $sources = [];
1216 foreach ( $srcPaths as $srcPath ) {
1217 // Resolve source to a storage path if virtual
1218 $source = $this->resolveToStoragePathIfVirtual( $srcPath );
1219 $sources[] = $source; // chunk to merge
1220 }
1221
1222 // Concatenate the chunks into one FS file
1223 $params = [ 'srcs' => $sources, 'dst' => $dstPath ];
1224 $status->merge( $this->backend->concatenate( $params ) );
1225 if ( !$status->isOK() ) {
1226 return $status;
1227 }
1228
1229 // Delete the sources if required
1230 if ( $flags & self::DELETE_SOURCE ) {
1231 $status->merge( $this->quickPurgeBatch( $srcPaths ) );
1232 }
1233
1234 // Make sure status is OK, despite any quickPurgeBatch() fatals
1235 $status->setResult( true );
1236
1237 return $status;
1238 }
1239
1263 public function publish(
1264 $src, $dstRel, $archiveRel, $flags = 0, array $options = []
1265 ) {
1266 $this->assertWritableRepo(); // fail out if read-only
1267
1268 $status = $this->publishBatch(
1269 [ [ $src, $dstRel, $archiveRel, $options ] ], $flags );
1270 if ( $status->successCount == 0 ) {
1271 $status->setOK( false );
1272 }
1273 $status->value = $status->value[0] ?? false;
1274
1275 return $status;
1276 }
1277
1289 public function publishBatch( array $ntuples, $flags = 0 ) {
1290 $this->assertWritableRepo(); // fail out if read-only
1291
1292 $backend = $this->backend; // convenience
1293 // Try creating directories
1294 $this->initZones( 'public' );
1295
1296 $status = $this->newGood( [] );
1297
1298 $operations = [];
1299 $sourceFSFilesToDelete = []; // cleanup for disk source files
1300 // Validate each triplet and get the store operation...
1301 foreach ( $ntuples as $ntuple ) {
1302 [ $src, $dstRel, $archiveRel ] = $ntuple;
1303 $srcPath = ( $src instanceof FSFile ) ? $src->getPath() : $src;
1304
1305 $options = $ntuple[3] ?? [];
1306 // Resolve source to a storage path if virtual
1307 $srcPath = $this->resolveToStoragePathIfVirtual( $srcPath );
1308 if ( !$this->validateFilename( $dstRel ) ) {
1309 throw new RuntimeException( 'Validation error in $dstRel' );
1310 }
1311 if ( !$this->validateFilename( $archiveRel ) ) {
1312 throw new RuntimeException( 'Validation error in $archiveRel' );
1313 }
1314
1315 $publicRoot = $this->getZonePath( 'public' );
1316 $dstPath = "$publicRoot/$dstRel";
1317 $archivePath = "$publicRoot/$archiveRel";
1318
1319 $dstDir = dirname( $dstPath );
1320 $archiveDir = dirname( $archivePath );
1321 // Abort immediately on directory creation errors since they're likely to be repetitive
1322 if ( !$this->initDirectory( $dstDir )->isOK() ) {
1323 return $this->newFatal( 'directorycreateerror', $dstDir );
1324 }
1325 if ( !$this->initDirectory( $archiveDir )->isOK() ) {
1326 return $this->newFatal( 'directorycreateerror', $archiveDir );
1327 }
1328
1329 // Set any desired headers to be use in GET/HEAD responses
1330 $headers = $options['headers'] ?? [];
1331
1332 // Archive destination file if it exists.
1333 // This will check if the archive file also exists and fail if does.
1334 // This is a check to avoid data loss. On Windows and Linux,
1335 // copy() will overwrite, so the existence check is vulnerable to
1336 // race conditions unless a functioning LockManager is used.
1337 // LocalFile also uses SELECT FOR UPDATE for synchronization.
1338 $operations[] = [
1339 'op' => 'copy',
1340 'src' => $dstPath,
1341 'dst' => $archivePath,
1342 'ignoreMissingSource' => true
1343 ];
1344
1345 // Copy (or move) the source file to the destination
1346 if ( FileBackend::isStoragePath( $srcPath ) ) {
1347 $operations[] = [
1348 'op' => ( $flags & self::DELETE_SOURCE ) ? 'move' : 'copy',
1349 'src' => $srcPath,
1350 'dst' => $dstPath,
1351 'overwrite' => true, // replace current
1352 'headers' => $headers
1353 ];
1354 } else {
1355 $operations[] = [
1356 'op' => 'store',
1357 'src' => $src, // storage path (copy) or local path/FSFile (store)
1358 'dst' => $dstPath,
1359 'overwrite' => true, // replace current
1360 'headers' => $headers
1361 ];
1362 if ( $flags & self::DELETE_SOURCE ) {
1363 $sourceFSFilesToDelete[] = $srcPath;
1364 }
1365 }
1366 }
1367
1368 // Execute the operations for each triplet
1369 $opts = $this->getBackendOperationOptions();
1370 $status->merge( $backend->doOperations( $operations, $opts ) );
1371 // Find out which files were archived...
1372 foreach ( $ntuples as $i => $ntuple ) {
1373 [ , , $archiveRel ] = $ntuple;
1374 $archivePath = $this->getZonePath( 'public' ) . "/$archiveRel";
1375 if ( $this->fileExists( $archivePath ) ) {
1376 $status->value[$i] = 'archived';
1377 } else {
1378 $status->value[$i] = 'new';
1379 }
1380 }
1381 // Cleanup for disk source files...
1382 foreach ( $sourceFSFilesToDelete as $file ) {
1383 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1384 @unlink( $file ); // FS cleanup
1385 }
1386
1387 return $status;
1388 }
1389
1397 protected function initDirectory( $dir ) {
1398 $path = $this->resolveToStoragePathIfVirtual( $dir );
1399 [ , $container, ] = FileBackend::splitStoragePath( $path );
1400
1401 $params = [ 'dir' => $path ];
1402 if ( $this->isPrivate
1403 || $container === $this->zones['deleted']['container']
1404 || $container === $this->zones['temp']['container']
1405 ) {
1406 # Take all available measures to prevent web accessibility of new deleted
1407 # directories, in case the user has not configured offline storage
1408 $params = [ 'noAccess' => true, 'noListing' => true ] + $params;
1409 }
1410
1411 return $this->newGood()->merge( $this->backend->prepare( $params ) );
1412 }
1413
1420 public function cleanDir( $dir ) {
1421 $this->assertWritableRepo(); // fail out if read-only
1422
1423 return $this->newGood()->merge(
1424 $this->backend->clean(
1425 [ 'dir' => $this->resolveToStoragePathIfVirtual( $dir ) ]
1426 )
1427 );
1428 }
1429
1436 public function fileExists( $file ) {
1437 $result = $this->fileExistsBatch( [ $file ] );
1438
1439 return $result[0];
1440 }
1441
1449 public function fileExistsBatch( array $files ) {
1450 $paths = array_map( $this->resolveToStoragePathIfVirtual( ... ), $files );
1451 $this->backend->preloadFileStat( [ 'srcs' => $paths ] );
1452
1453 $result = [];
1454 foreach ( $paths as $key => $path ) {
1455 $result[$key] = $this->backend->fileExists( [ 'src' => $path ] );
1456 }
1457
1458 return $result;
1459 }
1460
1471 public function delete( $srcRel, $archiveRel ) {
1472 $this->assertWritableRepo(); // fail out if read-only
1473
1474 return $this->deleteBatch( [ [ $srcRel, $archiveRel ] ] );
1475 }
1476
1493 public function deleteBatch( array $sourceDestPairs ) {
1494 $this->assertWritableRepo(); // fail out if read-only
1495
1496 // Try creating directories
1497 $this->initZones( [ 'public', 'deleted' ] );
1498
1499 $status = $this->newGood();
1500
1501 $backend = $this->backend; // convenience
1502 $operations = [];
1503 // Validate filenames and create archive directories
1504 foreach ( $sourceDestPairs as [ $srcRel, $archiveRel ] ) {
1505 if ( !$this->validateFilename( $srcRel ) ) {
1506 throw new RuntimeException( __METHOD__ . ':Validation error in $srcRel' );
1507 } elseif ( !$this->validateFilename( $archiveRel ) ) {
1508 throw new RuntimeException( __METHOD__ . ':Validation error in $archiveRel' );
1509 }
1510
1511 $publicRoot = $this->getZonePath( 'public' );
1512 $srcPath = "{$publicRoot}/$srcRel";
1513
1514 $deletedRoot = $this->getZonePath( 'deleted' );
1515 $archivePath = "{$deletedRoot}/{$archiveRel}";
1516 $archiveDir = dirname( $archivePath ); // does not touch FS
1517
1518 // Create destination directories
1519 if ( !$this->initDirectory( $archiveDir )->isGood() ) {
1520 return $this->newFatal( 'directorycreateerror', $archiveDir );
1521 }
1522
1523 $operations[] = [
1524 'op' => 'move',
1525 'src' => $srcPath,
1526 'dst' => $archivePath,
1527 // We may have 2+ identical files being deleted,
1528 // all of which will map to the same destination file
1529 'overwriteSame' => true // also see T33792
1530 ];
1531 }
1532
1533 $opts = $this->getBackendOperationOptions();
1534 // Move the files by executing the operations for each pair.
1535 // We're now committed to returning an OK result, which will
1536 // lead to the files being moved in the DB also.
1537 $opts['force'] = true;
1538
1539 return $status->merge( $backend->doOperations( $operations, $opts ) );
1540 }
1541
1548 public function cleanupDeletedBatch( array $storageKeys ) {
1549 $this->assertWritableRepo();
1550 }
1551
1559 public function getDeletedHashPath( $key ) {
1560 if ( strlen( $key ) < 31 ) {
1561 throw new InvalidArgumentException( "Invalid storage key '$key'." );
1562 }
1563 $path = '';
1564 for ( $i = 0; $i < $this->deletedHashLevels; $i++ ) {
1565 $path .= $key[$i] . '/';
1566 }
1567
1568 return $path;
1569 }
1570
1578 protected function resolveToStoragePathIfVirtual( $path ) {
1579 if ( self::isVirtualUrl( $path ) ) {
1580 return $this->resolveVirtualUrl( $path );
1581 }
1582
1583 return $path;
1584 }
1585
1593 public function getLocalCopy( $virtualUrl ) {
1594 $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
1595
1596 return $this->backend->getLocalCopy( [ 'src' => $path ] );
1597 }
1598
1607 public function getLocalReference( $virtualUrl ) {
1608 $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
1609
1610 return $this->backend->getLocalReference( [ 'src' => $path ] );
1611 }
1612
1622 public function addShellboxInputFile( BoxedCommand $command, string $boxedName,
1623 string $virtualUrl
1624 ) {
1625 $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
1626
1627 return $this->backend->addShellboxInputFile( $command, $boxedName, [ 'src' => $path ] );
1628 }
1629
1637 public function getFileProps( $virtualUrl ) {
1638 $fsFile = $this->getLocalReference( $virtualUrl );
1639 $mwProps = new MWFileProps( MediaWikiServices::getInstance()->getMimeAnalyzer() );
1640 if ( $fsFile ) {
1641 $props = $mwProps->getPropsFromPath( $fsFile->getPath(), true );
1642 } else {
1643 $props = $mwProps->newPlaceholderProps();
1644 }
1645
1646 return $props;
1647 }
1648
1655 public function getFileTimestamp( $virtualUrl ) {
1656 $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
1657
1658 return $this->backend->getFileTimestamp( [ 'src' => $path ] );
1659 }
1660
1667 public function getFileSize( $virtualUrl ) {
1668 $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
1669
1670 return $this->backend->getFileSize( [ 'src' => $path ] );
1671 }
1672
1679 public function getFileSha1( $virtualUrl ) {
1680 $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
1681
1682 return $this->backend->getFileSha1Base36( [ 'src' => $path ] );
1683 }
1684
1694 public function streamFileWithStatus( $virtualUrl, $headers = [], $optHeaders = [] ) {
1695 $path = $this->resolveToStoragePathIfVirtual( $virtualUrl );
1696 $params = [ 'src' => $path, 'headers' => $headers, 'options' => $optHeaders ];
1697
1698 // T172851: HHVM does not flush the output properly, causing OOM
1699 ob_start( null, 1_048_576 );
1700 ob_implicit_flush( true );
1701
1702 $status = $this->newGood()->merge( $this->backend->streamFile( $params ) );
1703
1704 // T186565: Close the buffer, unless it has already been closed
1705 // in HTTPFileStreamer::resetOutputBuffers().
1706 if ( ob_get_status() ) {
1707 ob_end_flush();
1708 }
1709
1710 return $status;
1711 }
1712
1721 public function enumFiles( $callback ) {
1722 $this->enumFilesInStorage( $callback );
1723 }
1724
1732 protected function enumFilesInStorage( $callback ) {
1733 $publicRoot = $this->getZonePath( 'public' );
1734 $numDirs = 1 << ( $this->hashLevels * 4 );
1735 // Use a priori assumptions about directory structure
1736 // to reduce the tree height of the scanning process.
1737 for ( $flatIndex = 0; $flatIndex < $numDirs; $flatIndex++ ) {
1738 $hexString = sprintf( "%0{$this->hashLevels}x", $flatIndex );
1739 $path = $publicRoot;
1740 for ( $hexPos = 0; $hexPos < $this->hashLevels; $hexPos++ ) {
1741 $path .= '/' . substr( $hexString, 0, $hexPos + 1 );
1742 }
1743 $iterator = $this->backend->getFileList( [ 'dir' => $path ] );
1744 if ( $iterator === null ) {
1745 throw new RuntimeException( __METHOD__ . ': could not get file listing for ' . $path );
1746 }
1747 foreach ( $iterator as $name ) {
1748 // Each item returned is a public file
1749 $callback( "{$path}/{$name}" );
1750 }
1751 }
1752 }
1753
1760 public function validateFilename( $filename ) {
1761 if ( strval( $filename ) == '' ) {
1762 return false;
1763 }
1764
1765 return FileBackend::isPathTraversalFree( $filename );
1766 }
1767
1773 private function getErrorCleanupFunction() {
1774 switch ( $this->pathDisclosureProtection ) {
1775 case 'none':
1776 case 'simple': // b/c
1777 $callback = $this->passThrough( ... );
1778 break;
1779 default: // 'paranoid'
1780 $callback = $this->paranoidClean( ... );
1781 }
1782 return $callback;
1783 }
1784
1791 public function paranoidClean( $param ) {
1792 return '[hidden]';
1793 }
1794
1801 public function passThrough( $param ) {
1802 return $param;
1803 }
1804
1812 public function newFatal( $message, ...$parameters ) {
1813 $status = Status::newFatal( $message, ...$parameters );
1814 $status->cleanCallback = $this->getErrorCleanupFunction();
1815
1816 return $status;
1817 }
1818
1825 public function newGood( $value = null ) {
1826 $status = Status::newGood( $value );
1827 $status->cleanCallback = $this->getErrorCleanupFunction();
1828
1829 return $status;
1830 }
1831
1840 public function checkRedirect( $title ) {
1841 return false;
1842 }
1843
1851 public function invalidateImageRedirect( $title ) {
1852 }
1853
1859 public function getDisplayName() {
1860 $sitename = MediaWikiServices::getInstance()->getMainConfig()->get( MainConfigNames::Sitename );
1861
1862 if ( $this->isLocal() ) {
1863 return $sitename;
1864 }
1865
1866 // 'shared-repo-name-wikimediacommons' is used when $wgUseInstantCommons = true
1867 return wfMessageFallback( 'shared-repo-name-' . $this->name, 'shared-repo' )->text();
1868 }
1869
1877 public function nameForThumb( $name ) {
1878 if ( strlen( $name ) > $this->abbrvThreshold ) {
1879 $ext = FileBackend::extensionFromPath( $name );
1880 $name = ( $ext == '' ) ? 'thumbnail' : "thumbnail.$ext";
1881 }
1882
1883 return $name;
1884 }
1885
1891 public function isLocal() {
1892 return $this->getName() == 'local';
1893 }
1894
1906 public function getSharedCacheKey( $kClassSuffix, ...$components ) {
1907 return false;
1908 }
1909
1921 public function getLocalCacheKey( $kClassSuffix, ...$components ) {
1922 return $this->wanCache->makeKey(
1923 'filerepo-' . $kClassSuffix,
1924 $this->getName(),
1925 ...$components
1926 );
1927 }
1928
1937 public function getTempRepo() {
1938 return new TempFileRepo( [
1939 'name' => "{$this->name}-temp",
1940 'backend' => $this->backend,
1941 'zones' => [
1942 'public' => [
1943 // Same place storeTemp() uses in the base repo, though
1944 // the path hashing is mismatched, which is annoying.
1945 'container' => $this->zones['temp']['container'],
1946 'directory' => $this->zones['temp']['directory']
1947 ],
1948 'thumb' => [
1949 'container' => $this->zones['temp']['container'],
1950 'directory' => $this->zones['temp']['directory'] == ''
1951 ? 'thumb'
1952 : $this->zones['temp']['directory'] . '/thumb'
1953 ],
1954 'transcoded' => [
1955 'container' => $this->zones['temp']['container'],
1956 'directory' => $this->zones['temp']['directory'] == ''
1957 ? 'transcoded'
1958 : $this->zones['temp']['directory'] . '/transcoded'
1959 ]
1960 ],
1961 'hashLevels' => $this->hashLevels, // performance
1962 'isPrivate' => true // all in temp zone
1963 ] );
1964 }
1965
1972 protected function assertWritableRepo() {
1973 }
1974
1981 public function getInfo() {
1982 $ret = [
1983 'name' => $this->getName(),
1984 'displayname' => $this->getDisplayName(),
1985 'rootUrl' => $this->getZoneUrl( 'public' ),
1986 'local' => $this->isLocal(),
1987 ];
1988
1989 $optionalSettings = [
1990 'url',
1991 'thumbUrl',
1992 'initialCapital',
1993 'descBaseUrl',
1994 'scriptDirUrl',
1995 'articleUrl',
1996 'fetchDescription',
1997 'descriptionCacheExpiry',
1998 ];
1999 foreach ( $optionalSettings as $k ) {
2000 if ( $this->$k !== null ) {
2001 $ret[$k] = $this->$k;
2002 }
2003 }
2004 if ( $this->favicon !== null ) {
2005 // Expand any local path to full URL to improve API usability (T77093).
2006 $ret['favicon'] = MediaWikiServices::getInstance()->getUrlUtils()
2007 ->expand( $this->favicon );
2008 }
2009
2010 return $ret;
2011 }
2012
2017 public function hasSha1Storage() {
2018 return $this->hasSha1Storage;
2019 }
2020
2025 public function supportsSha1URLs() {
2026 return $this->supportsSha1URLs;
2027 }
2028}
2029
2031class_alias( FileRepo::class, 'FileRepo' );
const NS_FILE
Definition Defines.php:57
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
wfMessageFallback(... $keys)
This function accepts multiple message keys and returns a message instance for the first message whic...
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
Group all the pieces relevant to the context of a request into one instance.
Base class for file repositories.
Definition FileRepo.php:51
addShellboxInputFile(BoxedCommand $command, string $boxedName, string $virtualUrl)
Add a file to a Shellbox command as an input file.
getLocalReference( $virtualUrl)
Get a local FS file with a given virtual URL/storage path.
static getHashPathForLevel( $name, $levels)
Definition FileRepo.php:779
findFile( $title, $options=[])
Find an instance of the named file created at the specified time Returns false if the file does not e...
Definition FileRepo.php:466
quickPurge( $path)
Purge a file from the repo.
getDescriptionStylesheetUrl()
Get the URL of the stylesheet to apply to description pages.
Definition FileRepo.php:897
fileExistsBatch(array $files)
Checks existence of an array of files.
initZones( $doZones=[])
Ensure that a single zone or list of zones is defined for usage.
Definition FileRepo.php:282
storeTemp( $originalName, $srcPath)
Pick a random name in the temp zone and store a file to it.
getDescriptionUrl( $name)
Get the URL of an image description page.
Definition FileRepo.php:838
getFileTimestamp( $virtualUrl)
Get the timestamp of a file with a given virtual URL/storage path.
string null $descBaseUrl
URL of image description pages, e.g.
Definition FileRepo.php:91
deleteBatch(array $sourceDestPairs)
Move a group of files to the deletion archive.
findBySha1( $hash)
Get an array or iterator of file objects for files that have a given SHA-1 content hash.
Definition FileRepo.php:638
bool $initialCapital
Equivalent to $wgCapitalLinks (or $wgCapitalLinkOverrides[NS_FILE], determines whether filenames impl...
Definition FileRepo.php:106
getNameFromTitle( $title)
Get the name of a file from its title.
Definition FileRepo.php:725
invalidateImageRedirect( $title)
Invalidates image redirect cache related to that image Doesn't do anything for repositories that don'...
getZoneLocation( $zone)
The storage container and base path of a zone.
Definition FileRepo.php:393
static isVirtualUrl( $url)
Determine if a string is an mwrepo:// URL.
Definition FileRepo.php:297
store( $srcPath, $dstZone, $dstRel, $flags=0)
Store a file to a given destination.
Definition FileRepo.php:923
resolveVirtualUrl( $url)
Get the backend storage path corresponding to a virtual URL.
Definition FileRepo.php:367
int $hashLevels
The number of directory levels for hash-based division of files.
Definition FileRepo.php:122
getDeletedHashPath( $key)
Get a relative path for a deletion archive key, e.g.
quickImport( $src, $dst, $options=null)
Import a file from the local file system into the repo.
passThrough( $param)
Path disclosure protection function.
bool $transformVia404
Whether to skip media file transformation on parse and rely on a 404 handler instead.
Definition FileRepo.php:86
cleanDir( $dir)
Deletes a directory if empty.
bool $isPrivate
Whether all zones should be private (e.g.
Definition FileRepo.php:137
canTransformLocally()
Returns true if the repository can transform files locally.
Definition FileRepo.php:715
checkRedirect( $title)
Checks if there is a redirect named as $title.
newGood( $value=null)
Create a new good result.
findBySha1s(array $hashes)
Get an array of arrays or iterators of file objects for files that have the given SHA-1 content hashe...
Definition FileRepo.php:649
string false $url
Public zone URL.
Definition FileRepo.php:116
findFiles(array $items, $flags=0)
Find many files at once.
Definition FileRepo.php:549
string $pathDisclosureProtection
May be 'paranoid' to remove all parameters from error messages, 'none' to leave the paths in unchange...
Definition FileRepo.php:113
null string $favicon
The URL to a favicon (optional, may be a server-local path URL).
Definition FileRepo.php:134
enumFiles( $callback)
Call a callback function for every public regular file in the repository.
publish( $src, $dstRel, $archiveRel, $flags=0, array $options=[])
Copy or move a file either from a storage path, virtual URL, or file system path, into this repositor...
getTempHashPath( $suffix)
Get a relative path including trailing slash, e.g.
Definition FileRepo.php:768
quickPurgeBatch(array $paths)
Purge a batch of files from the repo.
getName()
Get the name of this repository, as specified by $info['name]' to the constructor.
Definition FileRepo.php:807
getInfo()
Return information about the repository.
enumFilesInStorage( $callback)
Call a callback function for every public file in the repository.
newFile( $title, $time=false)
Create a new File object from the local repository.
Definition FileRepo.php:431
getDescriptionRenderUrl( $name, $lang=null)
Get the URL of the content-only fragment of the description page.
Definition FileRepo.php:872
assertWritableRepo()
Throw an exception if this repo is read-only by design.
publishBatch(array $ntuples, $flags=0)
Publish a batch of files.
string $thumbProxySecret
Secret key to pass as an X-Swift-Secret header to the proxied thumb service.
Definition FileRepo.php:153
cleanupDeletedBatch(array $storageKeys)
Delete files in the deleted directory if they are not referenced in the filearchive table.
getVirtualUrl( $suffix=false)
Get a URL referring to this repository, with the private mwrepo protocol.
Definition FileRepo.php:309
getLocalCacheKey( $kClassSuffix,... $components)
Get a site-local, repository-qualified, WAN cache key.
getRootDirectory()
Get the public zone root storage directory of the repository.
Definition FileRepo.php:746
canTransformVia404()
Returns true if the repository can transform files via a 404 handler.
Definition FileRepo.php:705
getThumbProxyUrl()
Get the URL thumb.php requests are being proxied to.
Definition FileRepo.php:687
fileExists( $file)
Checks existence of a file.
resolveToStoragePathIfVirtual( $path)
If a path is a virtual URL, resolve it to a storage path.
getBackend()
Get the file backend instance.
Definition FileRepo.php:253
array $zones
Map of zones to config.
Definition FileRepo.php:78
__construct(?array $info=null)
Definition FileRepo.php:173
getThumbScriptUrl()
Get the URL of thumb.php.
Definition FileRepo.php:678
findFilesByPrefix( $prefix, $limit)
Return an array of files where the name starts with $prefix.
Definition FileRepo.php:669
getTempRepo()
Get a temporary private FileRepo associated with this repo.
cleanupBatch(array $files, $flags=0)
Deletes a batch of files.
string null $scriptDirUrl
URL of the MediaWiki installation, equivalent to $wgScriptPath, e.g.
Definition FileRepo.php:96
getBackendOperationOptions()
FileRepo is responsible for locking since there can be both file objects and metadata.
Definition FileRepo.php:263
initDirectory( $dir)
Creates a directory with the appropriate zone permissions.
string $thumbProxyUrl
URL of where to proxy thumb.php requests to.
Definition FileRepo.php:151
getFileSize( $virtualUrl)
Get the size of a file with a given virtual URL/storage path.
getLocalCopy( $virtualUrl)
Get a local FS copy of a file with a given virtual URL/storage path.
streamFileWithStatus( $virtualUrl, $headers=[], $optHeaders=[])
Attempt to stream a file with the given virtual URL/storage path.
callable false $oldFileFactoryKey
Override these in the base class.
Definition FileRepo.php:146
getFileSha1( $virtualUrl)
Get the sha1 (base 36) of a file with a given virtual URL/storage path.
nameForThumb( $name)
Get the portion of the file that contains the origin file name.
quickImportBatch(array $triples)
Import a batch of files from the local file system into the repo.
getZonePath( $zone)
Get the storage path corresponding to one of the zones.
Definition FileRepo.php:407
string false $thumbUrl
The base thumbnail URL.
Definition FileRepo.php:119
string $thumbScriptUrl
URL of thumb.php.
Definition FileRepo.php:81
int $deletedHashLevels
The number of directory levels for hash-based division of deleted files.
Definition FileRepo.php:125
getHashPath( $name)
Get a relative path including trailing slash, e.g.
Definition FileRepo.php:757
string null $articleUrl
Equivalent to $wgArticlePath, e.g.
Definition FileRepo.php:99
getThumbProxySecret()
Get the secret key for the proxied thumb service.
Definition FileRepo.php:696
newFatal( $message,... $parameters)
Create a new fatal error.
getDisplayName()
Get the human-readable name of the repo.
getFileProps( $virtualUrl)
Get properties of a file with a given virtual URL/storage path.
callable false $oldFileFactory
Override these in the base class.
Definition FileRepo.php:142
bool $fetchDescription
Whether to fetch commons image description pages and display them on the local wiki.
Definition FileRepo.php:63
findFileFromKey( $sha1, $options=[])
Find an instance of the file with this key, created at the specified time Returns false if the file d...
Definition FileRepo.php:594
concatenate(array $srcPaths, $dstPath, $flags=0)
Concatenate a list of temporary files into a target file location.
callable false $fileFactoryKey
Override these in the base class.
Definition FileRepo.php:144
callable $fileFactory
Override these in the base class.
Definition FileRepo.php:140
isLocal()
Returns true if this the local file repository.
getReadOnlyReason()
Get an explanatory message if this repo is read-only.
Definition FileRepo.php:273
getZoneUrl( $zone, $ext=null)
Get the URL corresponding to one of the four basic zones.
Definition FileRepo.php:325
freeTemp( $virtualUrl)
Remove a temporary file or mark it for garbage collection.
storeBatch(array $triplets, $flags=0)
Store a batch of files.
Definition FileRepo.php:946
getHashLevels()
Get the number of hash directory levels.
Definition FileRepo.php:798
bool $disableLocalTransform
Disable local image scaling.
Definition FileRepo.php:156
getSharedCacheKey( $kClassSuffix,... $components)
Get a global, repository-qualified, WAN cache key.
quickCleanDir( $dir)
Deletes a directory if empty.
supportsSha1URLs()
Returns whether or not repo supports having originals SHA-1s in the thumb URLs.
paranoidClean( $param)
Path disclosure protection function.
hasSha1Storage()
Returns whether or not storage is SHA-1 based.
makeUrl( $query='', $entry='index')
Make an url to this repo.
Definition FileRepo.php:818
int $abbrvThreshold
File names over this size will use the short form of thumbnail names.
Definition FileRepo.php:131
validateFilename( $filename)
Determine if a relative path is valid, i.e.
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition File.php:80
Local file in the wiki's own database.
Definition LocalFile.php:80
File without associated database record.
FileRepo for temporary files created by FileRepo::getTempRepo()
A class containing constants representing the names of configuration variables.
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
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
MimeMagic helper wrapper.
Library for creating and parsing MW-style timestamps.
Generic operation result class Has warning/error list, boolean status and arbitrary value.
Class representing a non-directory file on the file system.
Definition FSFile.php:20
This class is used to hold the location and do limited manipulation of files stored temporarily (this...
Base class for all file backend classes (including multi-write backends).
Multi-datacenter aware caching interface.
return[ 'config-schema-inverse'=>['default'=>['ConfigRegistry'=>['main'=> 'MediaWiki\\Config\\GlobalVarConfig::newInstance',], 'Sitename'=> 'MediaWiki', 'Server'=> false, 'CanonicalServer'=> false, 'ServerName'=> false, 'AssumeProxiesUseDefaultProtocolPorts'=> true, 'HttpsPort'=> 443, 'ForceHTTPS'=> false, 'ScriptPath'=> '/wiki', 'UsePathInfo'=> null, 'Script'=> false, 'LoadScript'=> false, 'RestPath'=> false, 'StylePath'=> false, 'LocalStylePath'=> false, 'ExtensionAssetsPath'=> false, 'ExtensionDirectory'=> null, 'StyleDirectory'=> null, 'ArticlePath'=> false, 'UploadPath'=> false, 'ImgAuthPath'=> false, 'ThumbPath'=> false, 'UploadDirectory'=> false, 'FileCacheDirectory'=> false, 'Logo'=> false, 'Logos'=> false, 'Favicon'=> '/favicon.ico', 'AppleTouchIcon'=> false, 'ReferrerPolicy'=> false, 'TmpDirectory'=> false, 'UploadBaseUrl'=> '', 'UploadStashScalerBaseUrl'=> false, 'ActionPaths'=>[], 'MainPageIsDomainRoot'=> false, 'EnableUploads'=> false, 'UploadStashMaxAge'=> 21600, 'EnableAsyncUploads'=> false, 'EnableAsyncUploadsByURL'=> false, 'EnableChunkedUploads'=> 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'=> '', 'SharedUploadDBschema'=> null, 'CacheSharedUploads'=> true, 'ForeignUploadTargets'=>['local',], 'UploadDialog'=>['fields'=>['description'=> true, 'date'=> false, 'categories'=> false,], 'licensemessages'=>['local'=> 'generic-local', 'foreign'=> 'generic-foreign',], 'comment'=>['local'=> '', 'foreign'=> '',], 'format'=>['filepage'=> ' $DESCRIPTION', 'description'=> ' $TEXT', 'ownwork'=> '', 'license'=> '', 'uncategorized'=> '',],], 'FileBackends'=>[], 'LockManagers'=>[], 'DefaultLockManager'=> null, 'ShowEXIF'=> null, 'UpdateCompatibleMetadata'=> false, 'AllowCopyUploads'=> false, 'CopyUploadsDomains'=>[], 'CopyUploadsFromSpecialUpload'=> false, 'CopyUploadProxy'=> false, 'CopyUploadTimeout'=> false, 'CopyUploadAllowOnWikiDomainConfig'=> false, 'MaxUploadSize'=> 104857600, 'MinUploadChunkSize'=> 1024, 'UploadNavigationUrl'=> false, 'UploadMissingFileUrl'=> false, 'ThumbnailScriptPath'=> false, 'SharedThumbnailScriptPath'=> false, 'HashedUploadDirectory'=> true, 'CSPUploadEntryPoint'=> true, 'FileExtensions'=>['png', 'gif', 'jpg', 'jpeg', 'webp',], 'ProhibitedFileExtensions'=>['html', 'htm', 'js', 'jsb', 'mhtml', 'mht', 'xhtml', 'xht', 'php', 'phtml', 'php3', 'php4', 'php5', 'phps', 'phar', 'shtml', 'jhtml', 'pl', 'py', 'cgi', 'exe', 'scr', 'dll', 'msi', 'vbs', 'bat', 'com', 'pif', 'cmd', 'vxd', 'cpl', 'xml',], 'MimeTypeExclusions'=>['text/html', 'application/javascript', 'text/javascript', 'text/x-javascript', 'application/x-shellscript', 'application/x-php', 'text/x-php', 'text/x-python', 'text/x-perl', 'text/x-bash', 'text/x-sh', 'text/x-csh', 'text/scriptlet', 'application/x-msdownload', 'application/x-msmetafile', 'application/java', 'application/xml', 'text/xml',], 'CheckFileExtensions'=> true, 'StrictFileExtensions'=> true, 'DisableUploadScriptChecks'=> false, 'UploadSizeWarning'=> false, 'TrustedMediaFormats'=>['BITMAP', 'AUDIO', 'VIDEO', 'image/svg+xml', 'application/pdf',], 'MediaHandlers'=>[], 'NativeImageLazyLoading'=> true, '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 -l $lang -o $output $input', 'ImagickExt'=>['SvgHandler::rasterizeImagickExt',],], 'SVGConverter'=> 'ImageMagick', 'SVGConverterPath'=> '', 'SVGMaxSize'=> 5120, 'SVGMetadataCutoff'=> 5242880, 'SVGNativeRendering'=> true, 'SVGNativeRenderingSizeLimit'=> 51200, 'MediaInTargetLanguage'=> true, 'MaxImageArea'=> 12500000, 'MaxAnimatedGifArea'=> 12500000, 'MaxAnimatedWebPArea'=> 12500000, 'WebPThumbnailType'=>['webp', 'image/webp',], 'TiffThumbnailType'=>[], 'ThumbnailEpoch'=> '20030516000000', 'AttemptFailureEpoch'=> 1, 'IgnoreImageErrors'=> false, 'GenerateThumbnailOnParse'=> true, 'ShowArchiveThumbnails'=> true, 'EnableAutoRotation'=> null, 'Antivirus'=> null, 'AntivirusSetup'=>['clamav'=>['command'=> 'clamscan --no-summary ', 'codemap'=>[0=> 0, 1=> 1, 52=> -1, ' *'=> false,], 'messagepattern'=> '/.*?:(.*)/sim',],], 'AntivirusRequired'=> true, 'VerifyMimeType'=> true, 'MimeTypeFile'=> 'internal', 'MimeInfoFile'=> 'internal', 'MimeDetectorCommand'=> null, 'TrivialMimeDetection'=> false, 'XMLMimeTypes'=>['http:'svg'=> 'image/svg+xml', 'http:'http:'html'=> 'text/html',], 'ImageLimits'=>[[320, 240,], [640, 480,], [800, 600,], [1024, 768,], [1280, 1024,], [2560, 2048,],], 'ThumbLimits'=>[120, 150, 180, 200, 220, 250, 300, 400,], 'ThumbnailNamespaces'=>[6,], 'ThumbnailSteps'=> null, 'ThumbnailBuckets'=> null, 'ThumbnailMinimumBucketDistance'=> 50, 'UploadThumbnailRenderMap'=>[], 'UploadThumbnailRenderMethod'=> 'jobqueue', 'UploadThumbnailRenderHttpCustomHost'=> false, 'UploadThumbnailRenderHttpCustomDomain'=> false, 'UseTinyRGBForJPGThumbnails'=> false, 'GalleryOptions'=>[], 'ThumbUpright'=> 0.75, 'DirectoryMode'=> 511, 'ResponsiveImages'=> true, 'ImagePreconnect'=> false, 'TrackMediaRequestProvenance'=> false, 'DjvuUseBoxedCommand'=> false, 'DjvuDump'=> null, 'DjvuRenderer'=> null, 'DjvuTxt'=> null, 'DjvuPostProcessor'=> 'pnmtojpeg', 'DjvuOutputExtension'=> 'jpg', 'EmergencyContact'=> false, 'PasswordSender'=> false, 'NoReplyAddress'=> false, 'EnableEmail'=> true, 'EnableUserEmail'=> true, 'UserEmailUseReplyTo'=> true, 'PasswordReminderResendTime'=> 24, 'NewPasswordExpiry'=> 604800, 'UserEmailConfirmationTokenExpiry'=> 604800, 'PasswordExpirationDays'=> false, 'PasswordExpireGrace'=> 604800, 'SMTP'=> false, 'AdditionalMailParams'=> null, 'AllowHTMLEmail'=> false, 'EnotifFromEditor'=> false, 'EmailAuthentication'=> true, 'EmailConfirmationBanner'=> false, 'EnotifWatchlist'=> false, 'EnotifUserTalk'=> false, 'EnotifRevealEditorAddress'=> false, 'EnotifMinorEdits'=> true, 'EnotifUseRealName'=> false, 'UsersNotifiedOnAllChanges'=>[], 'DBname'=> 'my_wiki', 'DBmwschema'=> null, 'DBprefix'=> '', 'DBserver'=> 'localhost', 'DBport'=> 5432, 'DBuser'=> 'wikiuser', 'DBpassword'=> '', 'DBtype'=> 'mysql', 'DBssl'=> false, 'DBcompress'=> false, 'DBStrictWarnings'=> false, 'DBadminuser'=> null, 'DBadminpassword'=> null, 'SearchType'=> null, 'SearchTypeAlternatives'=> null, 'DBTableOptions'=> 'ENGINE=InnoDB, DEFAULT CHARSET=binary', 'SQLMode'=> '', 'SQLiteDataDir'=> '', 'SharedDB'=> null, 'SharedPrefix'=> false, 'SharedTables'=>['user', 'user_properties', 'user_autocreate_serial',], 'SharedSchema'=> false, 'DBservers'=> false, 'LBFactoryConf'=>['class'=> 'Wikimedia\\Rdbms\\LBFactorySimple',], 'DataCenterUpdateStickTTL'=> 10, 'DBerrorLog'=> false, 'DBerrorLogTZ'=> false, 'LocalDatabases'=>[], 'DatabaseReplicaLagWarning'=> 10, 'DatabaseReplicaLagCritical'=> 30, 'MaxExecutionTimeForExpensiveQueries'=> 0, 'VirtualDomainsMapping'=>[], 'RemoteVirtualDomainsMapping'=>[], 'FileSchemaMigrationStage'=> 3, 'ExternalLinksDomainGaps'=>[], 'ContentHandlers'=>['wikitext'=>['class'=> 'MediaWiki\\Content\\WikitextContentHandler', 'services'=>['TitleFactory', 'ParserFactory', 'GlobalIdGenerator', 'LanguageNameUtils', 'LinkRenderer', 'MagicWordFactory', 'ParsoidParserFactory',],], 'javascript'=>['class'=> 'MediaWiki\\Content\\JavaScriptContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'json'=>['class'=> 'MediaWiki\\Content\\JsonContentHandler', 'services'=>['ParsoidParserFactory', 'TitleFactory',],], 'css'=>['class'=> 'MediaWiki\\Content\\CssContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'UserOptionsLookup', 'CodeHighlighter',],], 'vue'=>['class'=> 'MediaWiki\\Content\\VueContentHandler', 'services'=>['MainConfig', 'ParserFactory', 'CodeHighlighter',],], 'text'=> 'MediaWiki\\Content\\TextContentHandler', 'unknown'=> 'MediaWiki\\Content\\FallbackContentHandler',], 'NamespaceContentModels'=>[], 'TextModelsToParse'=>['wikitext', 'javascript', 'css',], 'CompressRevisions'=> false, 'ExternalStores'=>[], 'ExternalServers'=>[], 'DefaultExternalStore'=> false, 'RevisionCacheExpiry'=> 604800, 'PageLanguageUseDB'=> false, 'DiffEngine'=> null, 'ExternalDiffEngine'=> false, 'Wikidiff2Options'=>[], 'RequestTimeLimit'=> null, 'TransactionalTimeLimit'=> 120, 'CriticalSectionTimeLimit'=> 180.0, 'MiserMode'=> false, 'DisableQueryPages'=> false, 'QueryCacheLimit'=> 1000, 'WantedPagesThreshold'=> 1, 'AllowSlowParserFunctions'=> false, 'AllowSchemaUpdates'=> true, 'MaxArticleSize'=> 2048, 'MemoryLimit'=> '50M', 'PoolCounterConf'=> null, 'PoolCountClientConf'=>['servers'=>['127.0.0.1',], 'timeout'=> 0.1,], 'MaxUserDBWriteDuration'=> false, 'MaxJobDBWriteDuration'=> false, 'LinkHolderBatchSize'=> 1000, 'MaximumMovedPages'=> 100, 'ForceDeferredUpdatesPreSend'=> false, 'MultiShardSiteStats'=> false, 'CacheDirectory'=> false, 'MainCacheType'=> 0, 'MessageCacheType'=> -1, 'ParserCacheType'=> -1, 'SessionCacheType'=> -1, 'AnonSessionCacheType'=> false, 'LanguageConverterCacheType'=> -1, 'ObjectCaches'=>[0=>['class'=> 'Wikimedia\\ObjectCache\\EmptyBagOStuff', 'reportDupes'=> false,], 1=>['class'=> 'MediaWiki\\ObjectCache\\SqlBagOStuff', 'loggroup'=> 'SQLBagOStuff',], 'memcached-php'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPhpBagOStuff', 'loggroup'=> 'memcached',], 'memcached-pecl'=>['class'=> 'Wikimedia\\ObjectCache\\MemcachedPeclBagOStuff', 'loggroup'=> 'memcached',], 'hash'=>['class'=> 'Wikimedia\\ObjectCache\\HashBagOStuff', 'reportDupes'=> false,], 'apc'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,], 'apcu'=>['class'=> 'Wikimedia\\ObjectCache\\APCUBagOStuff', 'reportDupes'=> false,],], 'WANObjectCache'=>[], 'MicroStashType'=> -1, 'MainStash'=> 1, 'ParsoidCacheConfig'=>['StashType'=> null, 'StashDuration'=> 86400,], 'ParsoidSelectiveUpdateSampleRate'=> 0, 'SplitParsoidParserCache'=> false, 'ParserCacheFilterConfig'=>['pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-pcache'=>['default'=>['minCpuTime'=> 9223372036854775807,],], 'parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],], 'postproc-parsoid-pcache'=>['default'=>['minCpuTime'=> 0,],],], 'ChronologyProtectorSecret'=> '', 'ParserCacheExpireTime'=> 86400, 'ParserCacheAsyncExpireTime'=> 60, 'ParserCacheAsyncRefreshJobs'=> true, 'OldRevisionParserCacheExpireTime'=> 3600, 'ObjectCacheSessionExpiry'=> 3600, 'SuspiciousIpExpiry'=> false, 'SessionPbkdf2Iterations'=> 10001, 'UseSessionCookieJwt'=> false, 'JwtSessionCookieIssuer'=> null, 'MemCachedServers'=>['127.0.0.1:11211',], 'MemCachedPersistent'=> false, 'MemCachedTimeout'=> 500000, 'UseLocalMessageCache'=> false, 'AdaptiveMessageCache'=> false, 'LocalisationCacheConf'=>['class'=> 'MediaWiki\\Language\\LocalisationCache', 'store'=> 'detect', 'storeClass'=> false, 'storeDirectory'=> false, 'storeServer'=>[], 'forceRecache'=> false, 'manualRecache'=> false,], 'CachePages'=> true, 'CacheEpoch'=> '20030516000000', 'GitInfoCacheDirectory'=> false, 'UseFileCache'=> false, 'FileCacheDepth'=> 2, 'RenderHashAppend'=> '', 'EnableSidebarCache'=> false, 'SidebarCacheExpiry'=> 86400, 'UseGzip'=> false, 'InvalidateCacheOnLocalSettingsChange'=> true, 'ExtensionInfoMTime'=> false, 'EnableRemoteBagOStuffTests'=> false, 'UseCdn'=> false, 'VaryOnXFP'=> false, 'InternalServer'=> false, 'CdnMaxAge'=> 18000, 'CdnMaxageLagged'=> 30, 'CdnMaxageStale'=> 10, 'CdnReboundPurgeDelay'=> 0, 'CdnMaxageSubstitute'=> 60, 'ForcedRawSMaxage'=> 300, 'CdnServers'=>[], 'CdnServersNoPurge'=>[], 'HTCPRouting'=>[], 'HTCPMulticastTTL'=> 1, 'UsePrivateIPs'=> false, 'CdnMatchParameterOrder'=> true, 'LanguageCode'=> 'en', 'GrammarForms'=>[], 'InterwikiMagic'=> true, 'HideInterlanguageLinks'=> false, 'ExtraInterlanguageLinkPrefixes'=>[], 'InterlanguageLinkCodeMap'=>[], 'ExtraLanguageNames'=>[], 'ExtraLanguageCodes'=>['bh'=> 'bho', 'no'=> 'nb', 'simple'=> 'en',], 'DummyLanguageCodes'=>[], 'AllUnicodeFixes'=> false, 'LegacyEncoding'=> false, 'AmericanDates'=> false, 'TranslateNumerals'=> true, 'UseDatabaseMessages'=> true, 'MaxMsgCacheEntrySize'=> 10000, 'DisableLangConversion'=> false, 'DisableTitleConversion'=> false, 'DefaultLanguageVariant'=> false, 'UsePigLatinVariant'=> false, 'DisabledVariants'=>[], 'VariantArticlePath'=> false, 'UseXssLanguage'=> false, 'LoginLanguageSelector'=> false, 'ForceUIMsgAsContentMsg'=>[], 'RawHtmlMessages'=>[], 'Localtimezone'=> null, 'LocalTZoffset'=> null, 'OverrideUcfirstCharacters'=>[], 'MimeType'=> 'text/html', 'Html5Version'=> null, 'EditSubmitButtonLabelPublish'=> false, 'XhtmlNamespaces'=>[], 'SiteNotice'=> '', 'BrowserFormatDetection'=> 'telephone=no', 'SkinMetaTags'=>[], 'DefaultSkin'=> 'vector-2022', 'FallbackSkin'=> 'fallback', 'SkipSkins'=>[], 'DisableOutputCompression'=> false, 'FragmentMode'=>['html5', 'legacy',], 'ExternalInterwikiFragmentMode'=> 'legacy', 'FooterIcons'=>['copyright'=>['copyright'=>[],], 'poweredby'=>['mediawiki'=>['src'=> null, 'url'=> 'https:'alt'=> 'Powered by MediaWiki', 'lang'=> 'en',],],], 'EnableSectionShare'=> false, 'PageShareSkinsEnabled'=>[], 'UseCombinedLoginLink'=> false, 'Edititis'=> false, 'Send404Code'=> true, 'ShowRollbackEditCount'=> 10, 'EnableCanonicalServerLink'=> false, 'InterwikiLogoOverride'=>[], 'ResourceModules'=>[], 'ResourceModuleSkinStyles'=>[], 'ResourceLoaderSources'=>[], 'ResourceBasePath'=> null, 'ResourceLoaderMaxage'=>[], 'ResourceLoaderDebug'=> false, 'ResourceLoaderMaxQueryLength'=> false, 'ResourceLoaderValidateJS'=> true, 'ResourceLoaderEnableJSProfiler'=> false, 'ResourceLoaderStorageEnabled'=> true, 'ResourceLoaderStorageVersion'=> 1, 'ResourceLoaderEnableSourceMapLinks'=> true, 'AllowSiteCSSOnRestrictedPages'=> false, 'VueDevelopmentMode'=> false, 'CodexDevelopmentDir'=> null, 'MetaNamespace'=> false, 'MetaNamespaceTalk'=> false, 'CanonicalNamespaceNames'=>[-2=> 'Media', -1=> 'Special', 0=> '', 1=> 'Talk', 2=> 'User', 3=> 'User_talk', 4=> 'Project', 5=> 'Project_talk', 6=> 'File', 7=> 'File_talk', 8=> 'MediaWiki', 9=> 'MediaWiki_talk', 10=> 'Template', 11=> 'Template_talk', 12=> 'Help', 13=> 'Help_talk', 14=> 'Category', 15=> 'Category_talk',], 'ExtraNamespaces'=>[], 'ExtraGenderNamespaces'=>[], 'NamespaceAliases'=>[], 'LegalTitleChars'=> ' %!"$&\'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+', 'CapitalLinks' => true, 'CapitalLinkOverrides' => [ ], 'NamespacesWithSubpages' => [ 1 => true, 2 => true, 3 => true, 4 => true, 5 => true, 7 => true, 8 => true, 9 => true, 10 => true, 11 => true, 12 => true, 13 => true, 15 => true, ], 'NamespacesWithoutAutoSummaries' => [ ], 'ContentNamespaces' => [ 0, ], 'ShortPagesNamespaceExclusions' => [ ], 'ExtraSignatureNamespaces' => [ ], 'InvalidRedirectTargets' => [ 'Filepath', 'Mypage', 'Mytalk', 'Redirect', 'Mylog', ], 'DisableHardRedirects' => false, 'FixDoubleRedirects' => false, 'LocalInterwikis' => [ ], 'InterwikiExpiry' => 10800, 'InterwikiCache' => false, 'InterwikiScopes' => 3, 'InterwikiFallbackSite' => 'wiki', 'RedirectSources' => false, 'SiteTypes' => [ 'mediawiki' => 'MediaWiki\\Site\\MediaWikiSite', ], 'MaxTocLevel' => 999, 'MaxPPNodeCount' => 1000000, 'MaxTemplateDepth' => 100, 'MaxPPExpandDepth' => 100, 'UrlProtocols' => [ 'bitcoin:', 'ftp: 'ftps: 'geo:', 'git: 'gopher: 'http: 'https: 'irc: 'ircs: 'magnet:', 'mailto:', 'matrix:', 'mms: 'news:', 'nntp: 'redis: 'sftp: 'sip:', 'sips:', 'sms:', 'ssh: 'svn: 'tel:', 'telnet: 'urn:', 'wikipedia: 'worldwind: 'xmpp:', ' ], 'CleanSignatures' => true, 'AllowExternalImages' => false, 'AllowExternalImagesFrom' => '', 'EnableImageWhitelist' => false, 'TidyConfig' => [ ], 'ParsoidSettings' => [ 'useSelser' => true, ], 'ParsoidExperimentalParserFunctionOutput' => false, 'RawHtml' => false, 'ExternalLinkTarget' => false, 'NoFollowLinks' => true, 'NoFollowNsExceptions' => [ ], 'NoFollowDomainExceptions' => [ 'mediawiki.org', ], 'RegisterInternalExternals' => false, 'ExternalLinksIgnoreDomains' => [ ], 'AllowDisplayTitle' => true, 'RestrictDisplayTitle' => true, 'ExpensiveParserFunctionLimit' => 100, 'PreprocessorCacheThreshold' => 1000, 'EnableScaryTranscluding' => false, 'TranscludeCacheExpiry' => 3600, 'EnableMagicLinks' => [ 'ISBN' => false, 'PMID' => false, 'RFC' => false, ], 'ParserEnableUserLanguage' => false, 'ArticleCountMethod' => 'link', 'ActiveUserDays' => 30, 'LearnerEdits' => 10, 'LearnerMemberSince' => 4, 'ExperiencedUserEdits' => 500, 'ExperiencedUserMemberSince' => 30, 'ManualRevertSearchRadius' => 15, 'RevertedTagMaxDepth' => 15, 'CentralIdLookupProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\CentralId\\LocalIdLookup', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', 'HideUserUtils', ], ], ], 'CentralIdLookupProvider' => 'local', 'UserRegistrationProviders' => [ 'local' => [ 'class' => 'MediaWiki\\User\\Registration\\LocalUserRegistrationProvider', 'services' => [ 'ConnectionProvider', ], ], ], 'PasswordPolicy' => [ 'policies' => [ 'bureaucrat' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'sysop' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'interface-admin' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'bot' => [ 'MinimalPasswordLength' => 10, 'MinimumPasswordLengthToLogin' => 1, ], 'default' => [ 'MinimalPasswordLength' => [ 'value' => 8, 'suggestChangeOnLogin' => true, ], 'PasswordCannotBeSubstringInUsername' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'PasswordCannotMatchDefaults' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], 'MaximalPasswordLength' => [ 'value' => 4096, 'suggestChangeOnLogin' => true, ], 'PasswordNotInCommonList' => [ 'value' => true, 'suggestChangeOnLogin' => true, ], ], ], 'checks' => [ 'MinimalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimalPasswordLength', ], 'MinimumPasswordLengthToLogin' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMinimumPasswordLengthToLogin', ], 'PasswordCannotBeSubstringInUsername' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotBeSubstringInUsername', ], 'PasswordCannotMatchDefaults' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordCannotMatchDefaults', ], 'MaximalPasswordLength' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkMaximalPasswordLength', ], 'PasswordNotInCommonList' => [ 'MediaWiki\\Password\\PasswordPolicyChecks', 'checkPasswordNotInCommonList', ], ], ], 'AuthManagerConfig' => null, 'AuthManagerAutoConfig' => [ 'preauth' => [ 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ThrottlePreAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\PreviouslyRenamedAccountPreAuthenticationProvider', 'services' => [ 'ConnectionProvider', 'UserFactory', ], 'sort' => 0, ], ], 'primaryauth' => [ 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\TemporaryPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', 'UserOptionsLookup', ], 'args' => [ [ 'authoritative' => false, ], ], 'sort' => 0, ], 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\LocalPasswordPrimaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'args' => [ [ 'authoritative' => true, ], ], 'sort' => 100, ], ], 'secondaryauth' => [ 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\CheckBlocksSecondaryAuthenticationProvider', 'sort' => 0, ], 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\ResetPasswordSecondaryAuthenticationProvider', 'sort' => 100, ], 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider' => [ 'class' => 'MediaWiki\\Auth\\EmailNotificationSecondaryAuthenticationProvider', 'services' => [ 'DBLoadBalancerFactory', ], 'sort' => 200, ], ], ], 'RememberMe' => 'choose', 'ReauthenticateTime' => [ 'default' => 3600, ], 'ChangeCredentialsBlacklist' => [ 'MediaWiki\\Auth\\TemporaryPasswordAuthenticationRequest', ], 'RemoveCredentialsBlacklist' => [ 'MediaWiki\\Auth\\PasswordAuthenticationRequest', ], 'InvalidPasswordReset' => true, 'PasswordDefault' => 'pbkdf2', 'PasswordConfig' => [ 'A' => [ 'class' => 'MediaWiki\\Password\\MWOldPassword', ], 'B' => [ 'class' => 'MediaWiki\\Password\\MWSaltedPassword', ], 'pbkdf2-legacyA' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'A', 'pbkdf2', ], ], 'pbkdf2-legacyB' => [ 'class' => 'MediaWiki\\Password\\LayeredParameterizedPassword', 'types' => [ 'B', 'pbkdf2', ], ], 'bcrypt' => [ 'class' => 'MediaWiki\\Password\\BcryptPassword', 'cost' => 9, ], 'pbkdf2' => [ 'class' => 'MediaWiki\\Password\\Pbkdf2PasswordUsingOpenSSL', 'algo' => 'sha512', 'cost' => '30000', 'length' => '64', ], 'argon2' => [ 'class' => 'MediaWiki\\Password\\Argon2Password', 'algo' => 'auto', ], ], 'PasswordResetRoutes' => [ 'username' => true, 'email' => true, ], 'MaxSigChars' => 255, 'SignatureValidation' => 'warning', 'SignatureAllowedLintErrors' => [ 'obsolete-tag', ], 'MaxNameChars' => 255, 'ReservedUsernames' => [ 'MediaWiki default', 'Conversion script', 'Maintenance script', 'Template namespace initialisation script', 'ScriptImporter', 'Delete page script', 'Move page script', 'Command line script', 'Unknown user', 'msg:double-redirect-fixer', 'msg:usermessage-editor', 'msg:proxyblocker', 'msg:sorbs', 'msg:spambot_username', 'msg:autochange-username', ], 'DefaultUserOptions' => [ 'ccmeonemails' => 0, 'date' => 'default', 'diffonly' => 0, 'diff-type' => 'table', 'disablemail' => 0, 'editfont' => 'monospace', 'editondblclick' => 0, 'editrecovery' => 0, 'editsectiononrightclick' => 0, 'email-allow-new-users' => 1, 'enotifminoredits' => 0, 'enotifrevealaddr' => 0, 'enotifusertalkpages' => 1, 'enotifwatchlistpages' => 1, 'extendwatchlist' => 1, 'fancysig' => 0, 'forceeditsummary' => 0, 'forcesafemode' => 0, 'gender' => 'unknown', 'hidecategorization' => 1, 'hideminor' => 0, 'hidepatrolled' => 0, 'imagesize' => 2, 'minordefault' => 0, 'newpageshidepatrolled' => 0, 'nickname' => '', 'norollbackdiff' => 0, 'prefershttps' => 1, 'previewonfirst' => 0, 'previewontop' => 1, 'pst-cssjs' => 1, 'rcdays' => 7, 'rcenhancedfilters-disable' => 0, 'rclimit' => 50, 'requireemail' => 0, 'search-match-redirect' => true, 'search-special-page' => 'Search', 'search-thumbnail-extra-namespaces' => true, 'searchlimit' => 20, 'showhiddencats' => 0, 'shownumberswatching' => 1, 'showrollbackconfirmation' => 0, 'skin' => false, 'skin-responsive' => 1, 'thumbsize' => 5, 'underline' => 2, 'useeditwarning' => 1, 'uselivepreview' => 0, 'usenewrc' => 1, 'watchcreations' => 1, 'watchcreations-expiry' => 'infinite', 'watchdefault' => 1, 'watchdefault-expiry' => 'infinite', 'watchdeletion' => 0, 'watchlistdays' => 7, 'watchlisthideanons' => 0, 'watchlisthidebots' => 0, 'watchlisthidecategorization' => 1, 'watchlisthideliu' => 0, 'watchlisthideminor' => 0, 'watchlisthideown' => 0, 'watchlisthidepatrolled' => 0, 'watchlistreloadautomatically' => 0, 'watchlistunwatchlinks' => 0, 'watchmoves' => 0, 'watchrollback' => 0, 'watchuploads' => 1, 'watchrollback-expiry' => 'infinite', 'watchstar-expiry' => 'infinite', 'wlenhancedfilters-disable' => 0, 'wllimit' => 250, ], 'ConditionalUserOptions' => [ ], 'HiddenPrefs' => [ ], 'UserJsPrefLimit' => 100, 'InvalidUsernameCharacters' => '@:>=', 'UserrightsInterwikiDelimiter' => '@', 'SecureLogin' => false, 'AuthenticationTokenVersion' => null, 'SessionProviders' => [ 'MediaWiki\\Session\\CookieSessionProvider' => [ 'class' => 'MediaWiki\\Session\\CookieSessionProvider', 'args' => [ [ 'priority' => 30, ], ], 'services' => [ 'JwtCodec', 'UrlUtils', ], ], 'MediaWiki\\Session\\BotPasswordSessionProvider' => [ 'class' => 'MediaWiki\\Session\\BotPasswordSessionProvider', 'args' => [ [ 'priority' => 75, ], ], 'services' => [ 'GrantsInfo', ], ], ], 'AutoCreateTempUser' => [ 'known' => false, 'enabled' => false, 'actions' => [ 'edit', ], 'genPattern' => '~$1', 'matchPattern' => null, 'reservedPattern' => '~$1', 'serialProvider' => [ 'type' => 'local', 'useYear' => true, ], 'serialMapping' => [ 'type' => 'readable-numeric', ], 'expireAfterDays' => 90, 'notifyBeforeExpirationDays' => 10, ], 'AutoblockExemptions' => [ ], 'AutoblockExpiry' => 86400, 'BlockAllowsUTEdit' => true, 'BlockCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 19, ], 'BlockDisablesLogin' => false, 'EnableMultiBlocks' => false, 'WhitelistRead' => false, 'WhitelistReadRegexp' => false, 'EmailConfirmToEdit' => false, 'HideIdentifiableRedirects' => true, 'GroupPermissions' => [ '*' => [ 'createaccount' => true, 'autocreateaccount' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'viewmyprivateinfo' => true, 'editmyprivateinfo' => true, 'editmyoptions' => true, ], 'user' => [ 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'movefile' => true, 'read' => true, 'edit' => true, 'createpage' => true, 'createtalk' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'minoredit' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, 'editmyuserjsredirect' => true, 'sendemail' => true, 'applychangetags' => true, 'changetags' => true, 'viewmywatchlist' => true, 'editmywatchlist' => true, 'createwithcontentmodel' => true, 'logout' => true, ], 'autoconfirmed' => [ 'autoconfirmed' => true, 'editsemiprotected' => true, ], 'bot' => [ 'bot' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'nominornewtalk' => true, 'autopatrol' => true, 'suppressredirect' => true, 'apihighlimits' => true, ], 'sysop' => [ 'block' => true, 'createaccount' => true, 'createpreviouslyrenamedaccount' => true, 'delete' => true, 'bigdelete' => true, 'deletedhistory' => true, 'deletedtext' => true, 'undelete' => true, 'editcontentmodel' => true, 'editinterface' => true, 'editsitejson' => true, 'edituserjson' => true, 'import' => true, 'importupload' => true, 'move' => true, 'move-subpages' => true, 'move-rootuserpages' => true, 'move-categorypages' => true, 'patrol' => true, 'autopatrol' => true, 'protect' => true, 'editprotected' => true, 'rollback' => true, 'upload' => true, 'reupload' => true, 'reupload-shared' => true, 'unwatchedpages' => true, 'autoconfirmed' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'blockemail' => true, 'markbotedits' => true, 'apihighlimits' => true, 'browsearchive' => true, 'noratelimit' => true, 'movefile' => true, 'unblockself' => true, 'suppressredirect' => true, 'mergehistory' => true, 'managechangetags' => true, 'deletechangetags' => true, ], 'interface-admin' => [ 'editinterface' => true, 'editsitecss' => true, 'editsitejson' => true, 'editsitejs' => true, 'editusercss' => true, 'edituserjson' => true, 'edituserjs' => true, ], 'bureaucrat' => [ 'userrights' => true, 'noratelimit' => true, 'renameuser' => true, ], 'suppress' => [ 'hideuser' => true, 'suppressrevision' => true, 'viewsuppressed' => true, 'suppressionlog' => true, 'deleterevision' => true, 'deletelogentry' => true, ], ], 'PrivilegedGroups' => [ 'bureaucrat', 'interface-admin', 'suppress', 'sysop', ], 'RevokePermissions' => [ ], 'GroupInheritsPermissions' => [ ], 'ImplicitGroups' => [ '*', 'user', 'autoconfirmed', ], 'GroupsAddToSelf' => [ ], 'GroupsRemoveFromSelf' => [ ], 'RestrictedGroups' => [ ], 'UserRequirementsPrivateConditions' => [ ], 'RestrictionTypes' => [ 'create', 'edit', 'move', 'upload', ], 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop', ], 'CascadingRestrictionLevels' => [ 'sysop', ], 'SemiprotectedRestrictionLevels' => [ 'autoconfirmed', ], 'NamespaceProtection' => [ ], 'RestrictUserPageEditing' => false, 'NonincludableNamespaces' => [ ], 'AutoConfirmAge' => 0, 'AutoConfirmCount' => 0, 'Autopromote' => [ 'autoconfirmed' => [ '&', [ 1, null, ], [ 2, null, ], ], ], 'AutopromoteOnce' => [ 'onEdit' => [ ], ], 'AutopromoteOnceLogInRC' => true, 'AutopromoteOnceRCExcludedGroups' => [ ], 'AddGroups' => [ ], 'RemoveGroups' => [ ], 'AvailableRights' => [ ], 'ImplicitRights' => [ ], 'DeleteRevisionsLimit' => 0, 'DeleteRevisionsBatchSize' => 1000, 'HideUserContribLimit' => 1000, 'AccountCreationThrottle' => [ [ 'count' => 0, 'seconds' => 86400, ], ], 'TempAccountCreationThrottle' => [ [ 'count' => 1, 'seconds' => 600, ], [ 'count' => 6, 'seconds' => 86400, ], ], 'TempAccountNameAcquisitionThrottle' => [ [ 'count' => 60, 'seconds' => 86400, ], ], 'SpamRegex' => [ ], 'SummarySpamRegex' => [ ], 'EnableDnsBlacklist' => false, 'DnsBlacklistUrls' => [ ], 'ProxyList' => [ ], 'ProxyWhitelist' => [ ], 'SoftBlockRanges' => [ ], 'ApplyIpBlocksToXff' => false, 'RateLimits' => [ 'edit' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], 'user' => [ 90, 60, ], ], 'move' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], 'upload' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'rollback' => [ 'user' => [ 10, 60, ], 'newbie' => [ 5, 120, ], ], 'mailpassword' => [ 'ip' => [ 5, 3600, ], ], 'sendemail' => [ 'ip' => [ 5, 86400, ], 'newbie' => [ 5, 86400, ], 'user' => [ 20, 86400, ], ], 'changeemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'confirmemail' => [ 'ip-all' => [ 10, 3600, ], 'user' => [ 4, 86400, ], ], 'purge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'linkpurge' => [ 'ip' => [ 30, 60, ], 'user' => [ 30, 60, ], ], 'renderfile' => [ 'ip' => [ 700, 30, ], 'user' => [ 700, 30, ], ], 'renderfile-nonstandard' => [ 'ip' => [ 70, 30, ], 'user' => [ 70, 30, ], ], 'stashedit' => [ 'ip' => [ 30, 60, ], 'newbie' => [ 30, 60, ], ], 'stashbasehtml' => [ 'ip' => [ 5, 60, ], 'newbie' => [ 5, 60, ], ], 'changetags' => [ 'ip' => [ 8, 60, ], 'newbie' => [ 8, 60, ], ], 'editcontentmodel' => [ 'newbie' => [ 2, 120, ], 'user' => [ 8, 60, ], ], ], 'RateLimitsExcludedIPs' => [ ], 'PutIPinRC' => true, 'QueryPageDefaultLimit' => 50, 'ExternalQuerySources' => [ ], 'PasswordAttemptThrottle' => [ [ 'count' => 5, 'seconds' => 300, ], [ 'count' => 150, 'seconds' => 172800, ], ], 'GrantPermissions' => [ 'basic' => [ 'autocreateaccount' => true, 'autoconfirmed' => true, 'autopatrol' => true, 'editsemiprotected' => true, 'ipblock-exempt' => true, 'nominornewtalk' => true, 'patrolmarks' => true, 'read' => true, 'unwatchedpages' => true, ], 'highvolume' => [ 'bot' => true, 'apihighlimits' => true, 'noratelimit' => true, 'markbotedits' => true, ], 'import' => [ 'import' => true, 'importupload' => true, ], 'editpage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'pagelang' => true, ], 'editprotected' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, ], 'editmycssjs' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editmyusercss' => true, 'editmyuserjson' => true, 'editmyuserjs' => true, ], 'editmyoptions' => [ 'editmyoptions' => true, 'editmyuserjson' => true, ], 'editinterface' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, ], 'editsiteconfig' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editinterface' => true, 'edituserjson' => true, 'editsitejson' => true, 'editusercss' => true, 'edituserjs' => true, 'editsitecss' => true, 'editsitejs' => true, ], 'createeditmovepage' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'createpage' => true, 'createtalk' => true, 'delete-redirect' => true, 'move' => true, 'move-rootuserpages' => true, 'move-subpages' => true, 'move-categorypages' => true, 'suppressredirect' => true, ], 'uploadfile' => [ 'upload' => true, 'reupload-own' => true, ], 'uploadeditmovefile' => [ 'upload' => true, 'reupload-own' => true, 'reupload' => true, 'reupload-shared' => true, 'upload_by_url' => true, 'movefile' => true, 'suppressredirect' => true, ], 'patrol' => [ 'patrol' => true, ], 'rollback' => [ 'rollback' => true, ], 'blockusers' => [ 'block' => true, 'blockemail' => true, ], 'viewdeleted' => [ 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, ], 'viewrestrictedlogs' => [ 'suppressionlog' => true, ], 'delete' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'browsearchive' => true, 'deletedhistory' => true, 'deletedtext' => true, 'delete' => true, 'bigdelete' => true, 'deletelogentry' => true, 'deleterevision' => true, 'undelete' => true, ], 'oversight' => [ 'suppressrevision' => true, 'viewsuppressed' => true, ], 'protect' => [ 'edit' => true, 'minoredit' => true, 'applychangetags' => true, 'changetags' => true, 'editcontentmodel' => true, 'createwithcontentmodel' => true, 'editprotected' => true, 'protect' => true, ], 'viewmywatchlist' => [ 'viewmywatchlist' => true, ], 'editmywatchlist' => [ 'editmywatchlist' => true, ], 'sendemail' => [ 'sendemail' => true, ], 'createaccount' => [ 'createaccount' => true, ], 'privateinfo' => [ 'viewmyprivateinfo' => true, ], 'mergehistory' => [ 'mergehistory' => true, ], 'managesessions' => [ 'logout' => true, ], ], 'GrantPermissionGroups' => [ 'basic' => 'hidden', 'editpage' => 'page-interaction', 'createeditmovepage' => 'page-interaction', 'editprotected' => 'page-interaction', 'patrol' => 'page-interaction', 'uploadfile' => 'file-interaction', 'uploadeditmovefile' => 'file-interaction', 'sendemail' => 'email', 'viewmywatchlist' => 'watchlist-interaction', 'editmywatchlist' => 'watchlist-interaction', 'editmycssjs' => 'customization', 'editmyoptions' => 'customization', 'editinterface' => 'administration', 'editsiteconfig' => 'administration', 'rollback' => 'administration', 'blockusers' => 'administration', 'delete' => 'administration', 'viewdeleted' => 'administration', 'viewrestrictedlogs' => 'administration', 'protect' => 'administration', 'oversight' => 'administration', 'createaccount' => 'administration', 'mergehistory' => 'administration', 'import' => 'administration', 'highvolume' => 'high-volume', 'privateinfo' => 'private-information', 'managesessions' => 'private-information', ], 'GrantRiskGroups' => [ 'basic' => 'low', 'editpage' => 'low', 'createeditmovepage' => 'low', 'editprotected' => 'vandalism', 'patrol' => 'low', 'uploadfile' => 'low', 'uploadeditmovefile' => 'low', 'sendemail' => 'security', 'viewmywatchlist' => 'low', 'editmywatchlist' => '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', 'managesessions' => 'low', ], 'EnableBotPasswords' => true, 'BotPasswordsCluster' => false, 'BotPasswordsDatabase' => false, 'BotPasswordsLimit' => 100, 'SecretKey' => false, 'JwtPrivateKey' => false, 'JwtPublicKey' => false, 'AllowUserJs' => false, 'ReauthenticateForActions' => [ 'edituserjs' => 'edituserjscss', 'editusercss' => 'edituserjscss', 'editsitejs' => 'editsitejscss', 'editsitecss' => 'editsitejscss', ], 'AllowUserCss' => false, 'AllowUserCssPrefs' => true, 'UseSiteJs' => true, 'UseSiteCss' => true, 'BreakFrames' => false, 'EditPageFrameOptions' => 'DENY', 'ApiFrameOptions' => 'DENY', 'CSPHeader' => false, 'CSPReportOnlyHeader' => false, 'CSPUseReportURIDirective' => false, 'CSPFalsePositiveUrls' => [ 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'https: 'chrome-extension' => true, ], 'AllowCrossOrigin' => false, 'RestAllowCrossOriginCookieAuth' => false, 'SessionSecret' => false, 'CookieExpiration' => 2592000, 'ExtendedLoginCookieExpiration' => 15552000, 'SessionCookieJwtExpiration' => 14400, 'CookieDomain' => '', 'CookiePath' => '/', 'CookieSecure' => 'detect', 'CookiePrefix' => false, 'CookieHttpOnly' => true, 'CookieSameSite' => null, 'CacheVaryCookies' => [ ], 'SessionName' => false, 'CookieSetOnAutoblock' => true, 'CookieSetOnIpBlock' => true, 'DebugLogFile' => '', 'DebugLogPrefix' => '', 'DebugRedirects' => false, 'DebugRawPage' => false, 'DebugComments' => false, 'DebugDumpSql' => false, 'TrxProfilerLimits' => [ 'GET' => [ 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'POST-nonwrite' => [ 'writes' => 0, 'readQueryTime' => 5, 'readQueryRows' => 10000, ], 'PostSend-GET' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 10000, 'maxAffected' => 1000, 'masterConns' => 0, 'writes' => 0, ], 'PostSend-POST' => [ 'readQueryTime' => 5, 'writeQueryTime' => 1, 'readQueryRows' => 100000, 'maxAffected' => 1000, ], 'JobRunner' => [ 'readQueryTime' => 30, 'writeQueryTime' => 5, 'readQueryRows' => 100000, 'maxAffected' => 500, ], 'Maintenance' => [ 'writeQueryTime' => 5, 'maxAffected' => 1000, ], ], 'DebugLogGroups' => [ ], 'MWLoggerDefaultSpi' => [ 'class' => 'MediaWiki\\Logger\\LegacySpi', ], 'ShowDebug' => false, 'SpecialVersionShowHooks' => false, 'ShowExceptionDetails' => false, 'LogExceptionBacktrace' => true, 'PropagateErrors' => true, 'ShowHostnames' => false, 'OverrideHostname' => false, 'DevelopmentWarnings' => false, 'DeprecationReleaseLimit' => false, 'Profiler' => [ ], 'StatsdServer' => false, 'StatsdMetricPrefix' => 'MediaWiki', 'StatsTarget' => null, 'StatsFormat' => null, 'StatsPrefix' => 'mediawiki', 'OpenTelemetryConfig' => null, 'PageInfoTransclusionLimit' => 50, 'EnableJavaScriptTest' => false, 'DebugToolbar' => false, 'ApiClientErrorSampleRate' => 1.0, 'DisableTextSearch' => false, 'AdvancedSearchHighlighting' => false, 'SearchHighlightBoundaries' => '[\\p{Z}\\p{P}\\p{C}]', 'OpenSearchTemplates' => [ 'application/x-suggestions+json' => false, 'application/x-suggestions+xml' => false, ], 'OpenSearchDefaultLimit' => 10, 'OpenSearchDescriptionLength' => 100, 'SearchSuggestCacheExpiry' => 1200, 'DisableSearchUpdate' => false, 'NamespacesToBeSearchedDefault' => [ true, ], 'DisableInternalSearch' => false, 'SearchForwardUrl' => null, 'SitemapNamespaces' => false, 'SitemapNamespacesPriorities' => false, 'SitemapApiConfig' => [ ], 'SpecialSearchFormOptions' => [ ], 'SearchMatchRedirectPreference' => false, 'SearchRunSuggestedQuery' => true, 'Diff3' => '/usr/bin/diff3', 'Diff' => '/usr/bin/diff', 'PreviewOnOpenNamespaces' => [ 14 => true, ], 'UniversalEditButton' => true, 'UseAutomaticEditSummaries' => true, 'CommandLineDarkBg' => false, 'ReadOnly' => null, 'ReadOnlyWatchedItemStore' => false, 'ReadOnlyFile' => false, 'UpgradeKey' => false, 'GitBin' => '/usr/bin/git', 'GitRepositoryViewers' => [ 'https: 'ssh: 'https: 'git@github\\.com:(.*?)(\\.git)?' => 'https: ], 'InstallerInitialPages' => [ [ 'titlemsg' => 'mainpage', 'text' => '{{subst:int:mainpagetext}}{{subst:int:mainpagedocfooter}}', ], ], 'RCMaxAge' => 7776000, 'WatchersMaxAge' => 15552000, 'UnwatchedPageSecret' => 1, 'RCFilterByAge' => false, 'RCLinkLimits' => [ 50, 100, 250, 500, ], 'RCLinkDays' => [ 1, 3, 7, 14, 30, ], 'RCFeeds' => [ ], 'RCWatchCategoryMembership' => false, 'UseRCPatrol' => true, 'StructuredChangeFiltersLiveUpdatePollingRate' => 3, 'UseNPPatrol' => true, 'UseFilePatrol' => true, 'Feed' => true, 'FeedLimit' => 50, 'FeedCacheTimeout' => 60, 'FeedDiffCutoff' => 32768, 'OverrideSiteFeed' => [ ], 'FeedClasses' => [ 'rss' => 'MediaWiki\\Feed\\RSSFeed', 'atom' => 'MediaWiki\\Feed\\AtomFeed', ], 'AdvertisedFeedTypes' => [ 'atom', ], 'RCShowWatchingUsers' => false, 'RCShowChangedSize' => true, 'RCChangedSizeThreshold' => 500, 'ShowUpdatedMarker' => true, 'DisableAnonTalk' => false, 'UseTagFilter' => true, 'SoftwareTags' => [ 'mw-contentmodelchange' => true, 'mw-new-redirect' => true, 'mw-removed-redirect' => true, 'mw-changed-redirect-target' => true, 'mw-blank' => true, 'mw-replace' => true, 'mw-recreated' => true, 'mw-rollback' => true, 'mw-undo' => true, 'mw-manual-revert' => true, 'mw-reverted' => true, 'mw-server-side-upload' => true, 'mw-ipblock-appeal' => true, 'mw-edited-other-users-js' => true, 'mw-edited-other-users-css' => true, ], 'RestrictedTagViewRights' => [ ], 'UnwatchedPageThreshold' => false, 'RecentChangesFlags' => [ 'newpage' => [ 'letter' => 'newpageletter', 'title' => 'recentchanges-label-newpage', 'legend' => 'recentchanges-legend-newpage', 'grouping' => 'any', ], 'minor' => [ 'letter' => 'minoreditletter', 'title' => 'recentchanges-label-minor', 'legend' => 'recentchanges-legend-minor', 'class' => 'minoredit', 'grouping' => 'all', ], 'bot' => [ 'letter' => 'boteditletter', 'title' => 'recentchanges-label-bot', 'legend' => 'recentchanges-legend-bot', 'class' => 'botedit', 'grouping' => 'all', ], 'unpatrolled' => [ 'letter' => 'unpatrolledletter', 'title' => 'recentchanges-label-unpatrolled', 'legend' => 'recentchanges-legend-unpatrolled', 'grouping' => 'any', ], ], 'WatchlistExpiry' => false, 'EnableWatchstarPopover' => false, 'EnableWatchlistLabels' => false, 'WatchlistLabelsMaxPerUser' => 100, 'WatchlistPurgeRate' => 0.1, 'WatchlistExpiryMaxDuration' => '1 year', 'EnableChangesListQueryPartitioning' => false, 'RightsPage' => null, 'RightsUrl' => null, 'RightsText' => null, 'RightsIcon' => null, 'UseCopyrightUpload' => false, 'MaxCredits' => 0, 'ShowCreditsIfMax' => true, 'ImportSources' => [ ], 'ImportTargetNamespace' => null, 'ExportAllowHistory' => true, 'ExportMaxHistory' => 0, 'ExportAllowListContributors' => false, 'ExportMaxLinkDepth' => 0, 'ExportFromNamespaces' => false, 'ExportAllowAll' => false, 'ExportPagelistLimit' => 5000, 'XmlDumpSchemaVersion' => '0.11', 'WikiFarmSettingsDirectory' => null, 'WikiFarmSettingsExtension' => 'yaml', 'ExtensionFunctions' => [ ], 'ExtensionMessagesFiles' => [ ], 'MessagesDirs' => [ ], 'TranslationAliasesDirs' => [ ], 'ExtensionEntryPointListFiles' => [ ], 'EnableParserLimitReporting' => true, 'ValidSkinNames' => [ ], 'SpecialPages' => [ ], 'ExtensionCredits' => [ ], 'Hooks' => [ ], 'ServiceWiringFiles' => [ ], 'JobClasses' => [ 'deletePage' => 'MediaWiki\\Page\\DeletePageJob', 'refreshLinks' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'deleteLinks' => 'MediaWiki\\Page\\DeleteLinksJob', 'htmlCacheUpdate' => 'MediaWiki\\JobQueue\\Jobs\\HTMLCacheUpdateJob', 'sendMail' => [ 'class' => 'MediaWiki\\Mail\\EmaillingJob', 'services' => [ 'Emailer', ], ], 'enotifNotify' => [ 'class' => 'MediaWiki\\RecentChanges\\RecentChangeNotifyJob', 'services' => [ 'RecentChangeLookup', ], ], 'fixDoubleRedirect' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\DoubleRedirectJob', 'services' => [ 'RevisionLookup', 'MagicWordFactory', 'WikiPageFactory', ], 'needsPage' => true, ], 'AssembleUploadChunks' => 'MediaWiki\\JobQueue\\Jobs\\AssembleUploadChunksJob', 'PublishStashedFile' => 'MediaWiki\\JobQueue\\Jobs\\PublishStashedFileJob', 'ThumbnailRender' => 'MediaWiki\\JobQueue\\Jobs\\ThumbnailRenderJob', 'UploadFromUrl' => 'MediaWiki\\JobQueue\\Jobs\\UploadFromUrlJob', 'recentChangesUpdate' => 'MediaWiki\\RecentChanges\\RecentChangesUpdateJob', 'refreshLinksPrioritized' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'refreshLinksDynamic' => 'MediaWiki\\JobQueue\\Jobs\\RefreshLinksJob', 'activityUpdateJob' => 'MediaWiki\\Watchlist\\ActivityUpdateJob', 'categoryMembershipChange' => [ 'class' => 'MediaWiki\\RecentChanges\\CategoryMembershipChangeJob', 'services' => [ 'RecentChangeFactory', ], ], 'CategoryCountUpdateJob' => [ 'class' => 'MediaWiki\\JobQueue\\Jobs\\CategoryCountUpdateJob', 'services' => [ 'ConnectionProvider', 'NamespaceInfo', ], ], 'clearUserWatchlist' => 'MediaWiki\\Watchlist\\ClearUserWatchlistJob', 'watchlistExpiry' => [ 'class' => 'MediaWiki\\Watchlist\\WatchlistExpiryJob', 'needsPage' => false, ], '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', 'renameUserTable' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], 'renameUserDerived' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserDerivedJob', 'services' => [ 'RenameUserFactory', 'UserFactory', ], ], 'renameUser' => [ 'class' => 'MediaWiki\\RenameUser\\Job\\RenameUserTableJob', 'services' => [ 'MainConfig', 'DBLoadBalancerFactory', ], ], ], 'JobTypesExcludedFromDefaultQueue' => [ 'AssembleUploadChunks', 'PublishStashedFile', 'UploadFromUrl', ], 'JobBackoffThrottling' => [ ], 'JobTypeConf' => [ 'default' => [ 'class' => 'MediaWiki\\JobQueue\\JobQueueDB', 'order' => 'random', 'claimTTL' => 3600, ], ], 'JobQueueIncludeInMaxLagFactor' => false, 'SpecialPageCacheUpdates' => [ 'Statistics' => [ 'MediaWiki\\Deferred\\SiteStatsUpdate', 'cacheUpdate', ], ], 'PagePropLinkInvalidations' => [ 'hiddencat' => 'categorylinks', ], 'CategoryMagicGallery' => true, 'CategoryPagingLimit' => 200, 'CategoryCollation' => 'uppercase', 'TempCategoryCollations' => [ ], 'SortedCategories' => false, 'TrackingCategories' => [ ], 'LogTypes' => [ '', 'block', 'protect', 'rights', 'delete', 'upload', 'move', 'import', 'interwiki', 'patrol', 'merge', 'suppress', 'tag', 'managetags', 'contentmodel', 'renameuser', ], 'LogRestrictions' => [ 'suppress' => 'suppressionlog', ], 'FilterLogTypes' => [ 'patrol' => true, 'tag' => true, 'newusers' => false, ], 'LogNames' => [ '' => 'all-logs-page', 'block' => 'blocklogpage', 'protect' => 'protectlogpage', 'rights' => 'rightslog', 'delete' => 'dellogpage', 'upload' => 'uploadlogpage', 'move' => 'movelogpage', 'import' => 'importlogpage', 'patrol' => 'patrol-log-page', 'merge' => 'mergelog', 'suppress' => 'suppressionlog', ], 'LogHeaders' => [ '' => 'alllogstext', 'block' => 'blocklogtext', 'delete' => 'dellogpagetext', 'import' => 'importlogpagetext', 'merge' => 'mergelogpagetext', 'move' => 'movelogpagetext', 'patrol' => 'patrol-log-header', 'protect' => 'protectlogtext', 'rights' => 'rightslogtext', 'suppress' => 'suppressionlogtext', 'upload' => 'uploadlogpagetext', ], 'LogActions' => [ ], 'LogActionsHandlers' => [ 'block/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'block/unblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'contentmodel/change' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'contentmodel/new' => 'MediaWiki\\Logging\\ContentModelLogFormatter', 'delete/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/delete_redir2' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/restore' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'delete/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'import/interwiki' => 'MediaWiki\\Logging\\ImportLogFormatter', 'import/upload' => 'MediaWiki\\Logging\\ImportLogFormatter', 'interwiki/iw_add' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_delete' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'interwiki/iw_edit' => 'MediaWiki\\Logging\\InterwikiLogFormatter', 'managetags/activate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/create' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/deactivate' => 'MediaWiki\\Logging\\LogFormatter', 'managetags/delete' => 'MediaWiki\\Logging\\LogFormatter', 'merge/merge' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'merge/merge-into' => [ 'class' => 'MediaWiki\\Logging\\MergeLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'move/move_redir' => [ 'class' => 'MediaWiki\\Logging\\MoveLogFormatter', 'services' => [ 'TitleParser', ], ], 'patrol/patrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'patrol/autopatrol' => 'MediaWiki\\Logging\\PatrolLogFormatter', 'protect/modify' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/move_prot' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/protect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'protect/unprotect' => [ 'class' => 'MediaWiki\\Logging\\ProtectLogFormatter', 'services' => [ 'TitleParser', ], ], 'renameuser/renameuser' => [ 'class' => 'MediaWiki\\Logging\\RenameuserLogFormatter', 'services' => [ 'TitleParser', ], ], 'rights/autopromote' => 'MediaWiki\\Logging\\RightsLogFormatter', 'rights/rights' => 'MediaWiki\\Logging\\RightsLogFormatter', 'suppress/block' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/delete' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/event' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'suppress/reblock' => [ 'class' => 'MediaWiki\\Logging\\BlockLogFormatter', 'services' => [ 'TitleParser', 'NamespaceInfo', ], ], 'suppress/revision' => 'MediaWiki\\Logging\\DeleteLogFormatter', 'tag/update' => 'MediaWiki\\Logging\\TagLogFormatter', 'upload/overwrite' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/revert' => 'MediaWiki\\Logging\\UploadLogFormatter', 'upload/upload' => 'MediaWiki\\Logging\\UploadLogFormatter', ], 'ActionFilteredLogs' => [ 'block' => [ 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], 'unblock' => [ 'unblock', ], ], 'contentmodel' => [ 'change' => [ 'change', ], 'new' => [ 'new', ], ], 'delete' => [ 'delete' => [ 'delete', ], 'delete_redir' => [ 'delete_redir', 'delete_redir2', ], 'restore' => [ 'restore', ], 'event' => [ 'event', ], 'revision' => [ 'revision', ], ], 'import' => [ 'interwiki' => [ 'interwiki', ], 'upload' => [ 'upload', ], ], 'managetags' => [ 'create' => [ 'create', ], 'delete' => [ 'delete', ], 'activate' => [ 'activate', ], 'deactivate' => [ 'deactivate', ], ], 'move' => [ 'move' => [ 'move', ], 'move_redir' => [ 'move_redir', ], ], 'newusers' => [ 'create' => [ 'create', 'newusers', ], 'create2' => [ 'create2', ], 'autocreate' => [ 'autocreate', ], 'byemail' => [ 'byemail', ], ], 'protect' => [ 'protect' => [ 'protect', ], 'modify' => [ 'modify', ], 'unprotect' => [ 'unprotect', ], 'move_prot' => [ 'move_prot', ], ], 'rights' => [ 'rights' => [ 'rights', ], 'autopromote' => [ 'autopromote', ], ], 'suppress' => [ 'event' => [ 'event', ], 'revision' => [ 'revision', ], 'delete' => [ 'delete', ], 'block' => [ 'block', ], 'reblock' => [ 'reblock', ], ], 'upload' => [ 'upload' => [ 'upload', ], 'overwrite' => [ 'overwrite', ], 'revert' => [ 'revert', ], ], ], 'NewUserLog' => true, 'PageCreationLog' => true, 'AllowSpecialInclusion' => true, 'DisableQueryPageUpdate' => false, 'CountCategorizedImagesAsUsed' => false, 'MaxRedirectLinksRetrieved' => 500, 'RangeContributionsCIDRLimit' => [ 'IPv4' => 16, 'IPv6' => 32, ], 'Actions' => [ ], 'DefaultRobotPolicy' => 'index,follow', 'NamespaceRobotPolicies' => [ ], 'ArticleRobotPolicies' => [ ], 'ExemptFromUserRobotsControl' => null, 'DebugAPI' => false, 'APIModules' => [ ], 'APIFormatModules' => [ ], 'APIMetaModules' => [ ], 'APIPropModules' => [ ], 'APIListModules' => [ ], 'APIMaxDBRows' => 5000, 'APIMaxResultSize' => 8388608, 'APIMaxUncachedDiffs' => 1, 'APIMaxLagThreshold' => 7, 'APICacheHelpTimeout' => 3600, 'APIUselessQueryPages' => [ 'MIMEsearch', 'LinkSearch', ], 'AjaxLicensePreview' => true, 'CrossSiteAJAXdomains' => [ ], 'CrossSiteAJAXdomainExceptions' => [ ], 'AllowedCorsHeaders' => [ 'Accept', 'Accept-Language', 'Content-Language', 'Content-Type', 'Accept-Encoding', 'DNT', 'Origin', 'User-Agent', 'Api-User-Agent', 'Promise-Non-Write-API-Action', 'Access-Control-Max-Age', 'Authorization', ], 'RestAPIAdditionalRouteFiles' => [ ], 'RestLocalModuleTestBaseUrl' => null, 'RestModuleOverrides' => [ ], 'RestExternalModules' => [ ], 'RestTermsOfServiceUrl' => null, '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, 'HTTPUserAgentContact' => false, 'AsyncHTTPTimeout' => 25, 'HTTPProxy' => '', 'LocalVirtualHosts' => [ ], 'LocalHTTPProxy' => false, 'AllowExternalReqID' => false, 'GenerateReqIDFormat' => 'rand24', 'JobRunRate' => 1, 'RunJobsAsync' => false, 'UpdateRowsPerJob' => 300, 'UpdateRowsPerQuery' => 100, 'RedirectOnLogin' => 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' => [ ], 'UseLeximorph' => false, 'UsePostprocCacheLegacy' => false, 'UsePostprocCacheParsoid' => true, 'ParserOptionsLogUnsafeSampleRate' => 0, 'ReturnExperimentalPFragmentTypes' => [ ], 'UseParsoidLinksUpdate' => true, 'UseParsoidMessages' => true, 'UseParsoidParser' => false, 'SiteLookup' => [ ], ], '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', 'SharedUploadDBschema' => [ 'string', 'null', ], 'CacheSharedUploads' => 'boolean', 'ForeignUploadTargets' => 'array', 'UploadDialog' => 'object', 'FileBackends' => 'object', 'LockManagers' => 'array', 'DefaultLockManager' => [ 'string', 'null', ], 'CopyUploadsDomains' => 'array', 'CopyUploadTimeout' => [ 'boolean', 'integer', ], 'SharedThumbnailScriptPath' => [ 'string', 'boolean', ], 'HashedUploadDirectory' => 'boolean', 'CSPUploadEntryPoint' => 'boolean', 'FileExtensions' => 'array', 'ProhibitedFileExtensions' => 'array', 'MimeTypeExclusions' => 'array', 'TrustedMediaFormats' => 'array', 'MediaHandlers' => 'object', 'NativeImageLazyLoading' => 'boolean', 'ParserTestMediaHandlers' => 'object', 'MaxInterlacingAreas' => 'object', 'SVGConverters' => 'object', 'SVGNativeRendering' => [ 'string', 'boolean', ], 'MaxImageArea' => [ 'string', 'integer', 'boolean', ], 'WebPThumbnailType' => 'array', 'TiffThumbnailType' => 'array', 'GenerateThumbnailOnParse' => 'boolean', 'EnableAutoRotation' => [ 'boolean', 'null', ], 'Antivirus' => [ 'string', 'null', ], 'AntivirusSetup' => 'object', 'MimeDetectorCommand' => [ 'string', 'null', ], 'XMLMimeTypes' => 'object', 'ImageLimits' => 'array', 'ThumbLimits' => 'array', 'ThumbnailNamespaces' => 'array', 'ThumbnailSteps' => [ 'array', 'null', ], 'ThumbnailBuckets' => [ 'array', 'null', ], 'UploadThumbnailRenderMap' => 'object', 'GalleryOptions' => 'object', 'DjvuDump' => [ 'string', 'null', ], 'DjvuRenderer' => [ 'string', 'null', ], 'DjvuTxt' => [ 'string', 'null', ], 'DjvuPostProcessor' => [ 'string', 'null', ], 'SMTP' => [ 'boolean', 'object', ], 'EnotifFromEditor' => 'boolean', 'EmailConfirmationBanner' => 'boolean', 'EnotifRevealEditorAddress' => 'boolean', 'UsersNotifiedOnAllChanges' => 'object', 'DBmwschema' => [ 'string', 'null', ], 'SharedTables' => 'array', 'DBservers' => [ 'boolean', 'array', ], 'LBFactoryConf' => 'object', 'LocalDatabases' => 'array', 'VirtualDomainsMapping' => 'object', 'RemoteVirtualDomainsMapping' => 'object', 'FileSchemaMigrationStage' => 'integer', 'ExternalLinksDomainGaps' => 'object', 'ContentHandlers' => 'object', 'NamespaceContentModels' => 'object', 'TextModelsToParse' => 'array', 'ExternalStores' => 'array', 'ExternalServers' => 'object', 'DefaultExternalStore' => [ 'array', 'boolean', ], 'RevisionCacheExpiry' => 'integer', 'PageLanguageUseDB' => 'boolean', 'DiffEngine' => [ 'string', 'null', ], 'ExternalDiffEngine' => [ 'string', 'boolean', ], 'Wikidiff2Options' => 'object', 'RequestTimeLimit' => [ 'integer', 'null', ], 'CriticalSectionTimeLimit' => 'number', 'PoolCounterConf' => [ 'object', 'null', ], 'PoolCountClientConf' => 'object', 'MaxUserDBWriteDuration' => [ 'integer', 'boolean', ], 'MaxJobDBWriteDuration' => [ 'integer', 'boolean', ], 'MultiShardSiteStats' => 'boolean', 'ObjectCaches' => 'object', 'WANObjectCache' => 'object', 'MicroStashType' => [ 'string', 'integer', ], 'ParsoidCacheConfig' => 'object', 'ParsoidSelectiveUpdateSampleRate' => 'integer', 'SplitParsoidParserCache' => 'boolean', 'ParserCacheFilterConfig' => 'object', 'ChronologyProtectorSecret' => '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', 'PageShareSkinsEnabled' => 'array', 'InterwikiLogoOverride' => 'array', 'ResourceModules' => 'object', 'ResourceModuleSkinStyles' => 'object', 'ResourceLoaderSources' => 'object', 'ResourceLoaderMaxage' => 'object', 'ResourceLoaderMaxQueryLength' => [ 'integer', 'boolean', ], 'CanonicalNamespaceNames' => 'object', 'ExtraNamespaces' => 'object', 'ExtraGenderNamespaces' => 'object', 'NamespaceAliases' => 'object', 'CapitalLinkOverrides' => 'object', 'NamespacesWithSubpages' => 'object', 'NamespacesWithoutAutoSummaries' => 'array', 'ContentNamespaces' => 'array', 'ShortPagesNamespaceExclusions' => 'array', 'ExtraSignatureNamespaces' => 'array', 'InvalidRedirectTargets' => 'array', 'LocalInterwikis' => 'array', 'InterwikiCache' => [ 'boolean', 'object', ], 'SiteTypes' => 'object', 'UrlProtocols' => 'array', 'TidyConfig' => 'object', 'ParsoidSettings' => 'object', 'ParsoidExperimentalParserFunctionOutput' => 'boolean', 'NoFollowNsExceptions' => 'array', 'NoFollowDomainExceptions' => 'array', 'ExternalLinksIgnoreDomains' => 'array', 'EnableMagicLinks' => 'object', 'ManualRevertSearchRadius' => 'integer', 'RevertedTagMaxDepth' => 'integer', 'CentralIdLookupProviders' => 'object', 'CentralIdLookupProvider' => 'string', 'UserRegistrationProviders' => 'object', 'PasswordPolicy' => 'object', 'AuthManagerConfig' => [ 'object', 'null', ], 'AuthManagerAutoConfig' => 'object', 'RememberMe' => 'string', 'ReauthenticateTime' => 'object', 'ChangeCredentialsBlacklist' => 'array', 'RemoveCredentialsBlacklist' => 'array', 'PasswordConfig' => 'object', 'PasswordResetRoutes' => 'object', 'SignatureAllowedLintErrors' => 'array', 'ReservedUsernames' => 'array', 'DefaultUserOptions' => 'object', 'ConditionalUserOptions' => 'object', 'HiddenPrefs' => 'array', 'UserJsPrefLimit' => 'integer', 'AuthenticationTokenVersion' => [ 'string', 'null', ], 'SessionProviders' => 'object', 'AutoCreateTempUser' => 'object', 'AutoblockExemptions' => 'array', 'BlockCIDRLimit' => 'object', 'EnableMultiBlocks' => 'boolean', 'GroupPermissions' => 'object', 'PrivilegedGroups' => 'array', 'RevokePermissions' => 'object', 'GroupInheritsPermissions' => 'object', 'ImplicitGroups' => 'array', 'GroupsAddToSelf' => 'object', 'GroupsRemoveFromSelf' => 'object', 'RestrictedGroups' => 'object', 'UserRequirementsPrivateConditions' => 'array', 'RestrictionTypes' => 'array', 'RestrictionLevels' => 'array', 'CascadingRestrictionLevels' => 'array', 'SemiprotectedRestrictionLevels' => 'array', 'NamespaceProtection' => 'object', 'RestrictUserPageEditing' => 'boolean', 'NonincludableNamespaces' => 'object', 'Autopromote' => 'object', 'AutopromoteOnce' => 'object', 'AutopromoteOnceRCExcludedGroups' => 'array', 'AddGroups' => 'object', 'RemoveGroups' => 'object', 'AvailableRights' => 'array', 'ImplicitRights' => 'array', 'AccountCreationThrottle' => [ 'integer', 'array', ], 'TempAccountCreationThrottle' => 'array', 'TempAccountNameAcquisitionThrottle' => 'array', 'SpamRegex' => 'array', 'SummarySpamRegex' => 'array', 'DnsBlacklistUrls' => 'array', 'ProxyList' => [ 'string', 'array', ], 'ProxyWhitelist' => 'array', 'SoftBlockRanges' => 'array', 'RateLimits' => 'object', 'RateLimitsExcludedIPs' => 'array', 'ExternalQuerySources' => 'object', 'PasswordAttemptThrottle' => 'array', 'GrantPermissions' => 'object', 'GrantPermissionGroups' => 'object', 'GrantRiskGroups' => 'object', 'EnableBotPasswords' => 'boolean', 'BotPasswordsCluster' => [ 'string', 'boolean', ], 'BotPasswordsDatabase' => [ 'string', 'boolean', ], 'BotPasswordsLimit' => 'integer', 'ReauthenticateForActions' => 'object', 'CSPHeader' => [ 'boolean', 'object', ], 'CSPReportOnlyHeader' => [ 'boolean', 'object', ], 'CSPUseReportURIDirective' => [ 'boolean', 'object', ], 'CSPFalsePositiveUrls' => 'object', 'AllowCrossOrigin' => 'boolean', 'RestAllowCrossOriginCookieAuth' => 'boolean', 'CookieSameSite' => [ 'string', 'null', ], 'CacheVaryCookies' => 'array', 'TrxProfilerLimits' => 'object', 'DebugLogGroups' => 'object', 'MWLoggerDefaultSpi' => 'object', 'Profiler' => 'object', 'StatsTarget' => [ 'string', 'null', ], 'StatsFormat' => [ 'string', 'null', ], 'StatsPrefix' => 'string', 'OpenTelemetryConfig' => [ 'object', 'null', ], 'OpenSearchTemplates' => 'object', 'NamespacesToBeSearchedDefault' => 'object', 'SitemapNamespaces' => [ 'boolean', 'array', ], 'SitemapNamespacesPriorities' => [ 'boolean', 'object', ], 'SitemapApiConfig' => 'object', 'SpecialSearchFormOptions' => 'object', 'SearchMatchRedirectPreference' => 'boolean', 'SearchRunSuggestedQuery' => 'boolean', 'PreviewOnOpenNamespaces' => 'object', 'ReadOnlyWatchedItemStore' => 'boolean', 'GitRepositoryViewers' => 'object', 'InstallerInitialPages' => 'array', 'RCLinkLimits' => 'array', 'RCLinkDays' => 'array', 'RCFeeds' => 'object', 'OverrideSiteFeed' => 'object', 'FeedClasses' => 'object', 'AdvertisedFeedTypes' => 'array', 'SoftwareTags' => 'object', 'RestrictedTagViewRights' => 'object', 'RecentChangesFlags' => 'object', 'WatchlistExpiry' => 'boolean', 'EnableWatchstarPopover' => 'boolean', 'EnableWatchlistLabels' => 'boolean', 'WatchlistLabelsMaxPerUser' => 'integer', 'WatchlistPurgeRate' => 'number', 'WatchlistExpiryMaxDuration' => [ 'string', 'null', ], 'EnableChangesListQueryPartitioning' => 'boolean', 'ImportSources' => 'object', 'ExtensionFunctions' => 'array', 'ExtensionMessagesFiles' => 'object', 'MessagesDirs' => 'object', 'TranslationAliasesDirs' => 'object', 'ExtensionEntryPointListFiles' => 'object', 'ValidSkinNames' => 'object', 'SpecialPages' => 'object', 'ExtensionCredits' => 'object', 'Hooks' => 'object', 'ServiceWiringFiles' => 'array', 'JobClasses' => 'object', 'JobTypesExcludedFromDefaultQueue' => 'array', 'JobBackoffThrottling' => 'object', 'JobTypeConf' => 'object', 'SpecialPageCacheUpdates' => 'object', 'PagePropLinkInvalidations' => 'object', 'TempCategoryCollations' => 'array', 'SortedCategories' => 'boolean', 'TrackingCategories' => 'array', 'LogTypes' => 'array', 'LogRestrictions' => 'object', 'FilterLogTypes' => 'object', 'LogNames' => 'object', 'LogHeaders' => 'object', 'LogActions' => 'object', 'LogActionsHandlers' => 'object', 'ActionFilteredLogs' => 'object', 'RangeContributionsCIDRLimit' => 'object', 'Actions' => 'object', 'NamespaceRobotPolicies' => 'object', 'ArticleRobotPolicies' => 'object', 'ExemptFromUserRobotsControl' => [ 'array', 'null', ], 'APIModules' => 'object', 'APIFormatModules' => 'object', 'APIMetaModules' => 'object', 'APIPropModules' => 'object', 'APIListModules' => 'object', 'APIUselessQueryPages' => 'array', 'CrossSiteAJAXdomains' => 'object', 'CrossSiteAJAXdomainExceptions' => 'object', 'AllowedCorsHeaders' => 'array', 'RestAPIAdditionalRouteFiles' => 'array', 'RestLocalModuleTestBaseUrl' => [ 'string', 'null', ], 'RestModuleOverrides' => 'object', 'RestExternalModules' => 'object', 'RestTermsOfServiceUrl' => [ 'string', 'null', ], 'ShellRestrictionMethod' => [ 'string', 'boolean', ], 'ShellboxUrls' => 'object', 'ShellboxSecretKey' => [ 'string', 'null', ], 'ShellboxShell' => [ 'string', 'null', ], 'HTTPTimeout' => 'number', 'HTTPConnectTimeout' => 'number', 'HTTPMaxTimeout' => 'number', 'HTTPMaxConnectTimeout' => 'number', 'HTTPUserAgentContact' => [ 'string', 'boolean', ], 'LocalVirtualHosts' => 'object', 'LocalHTTPProxy' => [ 'string', 'boolean', ], 'GenerateReqIDFormat' => 'string', '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', 'UseLeximorph' => 'boolean', 'UsePostprocCacheLegacy' => 'boolean', 'UsePostprocCacheParsoid' => 'boolean', 'ParserOptionsLogUnsafeSampleRate' => 'integer', 'ReturnExperimentalPFragmentTypes' => 'array', 'UseParsoidLinksUpdate' => [ 'boolean', 'null', ], 'UseParsoidMessages' => [ 'boolean', 'null', ], 'UseParsoidParser' => 'boolean', 'SiteLookup' => 'object', ], 'mergeStrategy' => [ 'WebPThumbnailType' => 'replace', 'TiffThumbnailType' => 'replace', 'LBFactoryConf' => 'replace', 'InterwikiCache' => 'replace', 'PasswordPolicy' => 'array_replace_recursive', 'AuthManagerAutoConfig' => 'array_plus_2d', 'GroupPermissions' => 'array_plus_2d', 'RevokePermissions' => 'array_plus_2d', 'AddGroups' => 'array_merge_recursive', 'RemoveGroups' => 'array_merge_recursive', 'RateLimits' => 'array_plus_2d', 'GrantPermissions' => 'array_plus_2d', 'MWLoggerDefaultSpi' => 'replace', 'Profiler' => 'replace', 'Hooks' => 'array_merge_recursive', 'RestModuleOverrides' => 'array_replace_recursive', 'RestExternalModules' => 'array_replace_recursive', ], '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', ], ], ], ], ], 'RawHtmlMessages' => [ 'items' => [ 'type' => 'string', ], ], 'InterwikiLogoOverride' => [ 'items' => [ 'type' => 'string', ], ], 'LegalTitleChars' => [ 'deprecated' => 'since 1.41; use Extension:TitleBlacklist to customize', ], 'ReauthenticateTime' => [ 'additionalProperties' => [ 'type' => [ 'integer', 'array', ], ], ], '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', ], 'skipRedirects' => [ 'type' => 'bool', ], ], ], 'SoftwareTags' => [ 'additionalProperties' => [ 'type' => 'boolean', ], ], 'UseCopyrightUpload' => [ 'deprecated' => 'since 1.47 This feature is being removed.', ], 'JobBackoffThrottling' => [ 'additionalProperties' => [ 'type' => 'number', ], ], 'JobTypeConf' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'class' => [ 'type' => 'string', ], 'order' => [ 'type' => 'string', ], 'claimTTL' => [ 'type' => 'integer', ], ], ], ], 'TrackingCategories' => [ 'deprecated' => 'since 1.25 Extensions should now register tracking categories using the new extension registration system.', ], 'RangeContributionsCIDRLimit' => [ 'additionalProperties' => [ 'type' => 'integer', ], ], 'RestModuleOverrides' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'availability' => [ 'type' => 'string', ], 'groups' => [ 'type' => 'array', ], ], ], ], 'RestExternalModules' => [ 'additionalProperties' => [ 'type' => 'object', 'properties' => [ 'info' => [ 'type' => 'object', 'properties' => [ 'version' => [ 'type' => 'string', ], 'title' => [ 'type' => 'string', ], 'x-i18n-title' => [ 'type' => 'string', ], 'description' => [ 'type' => 'string', ], 'x-i18n-description' => [ 'type' => 'string', ], ], 'required' => [ 'version', ], ], 'base' => [ 'type' => 'string', 'format' => 'uri', ], 'spec' => [ 'type' => 'string', 'format' => 'uri', ], ], 'required' => [ 'info', 'base', 'spec', ], ], ], 'ShellboxUrls' => [ 'additionalProperties' => [ 'type' => [ 'string', 'boolean', 'null', ], ], ], ], 'obsolete-config' => [ 'MangleFlashPolicy' => 'Since 1.39; no longer has any effect.', 'EnableOpenSearchSuggest' => 'Since 1.35, no longer used', 'AutoloadAttemptLowercase' => 'Since 1.40; no longer has any effect.', ],]
Represents the target of a wiki link.
Interface for objects (potentially) representing an editable wiki page.
This interface represents the authority associated with the current execution context,...
Definition Authority.php:23
Interface for database access objects.
$source