MediaWiki master
GlobalFunctions.php
Go to the documentation of this file.
1<?php
29use Wikimedia\RequestTimeout\RequestTimeout;
30use Wikimedia\Timestamp\ConvertibleTimestamp;
31use Wikimedia\Timestamp\TimestampFormat as TS;
32
43function wfLoadExtension( $ext, $path = null ) {
44 if ( !$path ) {
46 $path = "$wgExtensionDirectory/$ext/extension.json";
47 }
48 ExtensionRegistry::getInstance()->queue( $path );
49}
50
64function wfLoadExtensions( array $exts ) {
66 $registry = ExtensionRegistry::getInstance();
67 foreach ( $exts as $ext ) {
68 $registry->queue( "$wgExtensionDirectory/$ext/extension.json" );
69 }
70}
71
80function wfLoadSkin( $skin, $path = null ) {
81 if ( !$path ) {
82 global $wgStyleDirectory;
83 $path = "$wgStyleDirectory/$skin/skin.json";
84 }
85 ExtensionRegistry::getInstance()->queue( $path );
86}
87
95function wfLoadSkins( array $skins ) {
96 global $wgStyleDirectory;
97 $registry = ExtensionRegistry::getInstance();
98 foreach ( $skins as $skin ) {
99 $registry->queue( "$wgStyleDirectory/$skin/skin.json" );
100 }
101}
102
113function wfArrayInsertAfter( array $array, array $insert, $after ) {
114 return ArrayUtils::insertAfter( $array, $insert, $after );
115}
116
125function wfObjectToArray( $objOrArray, $recursive = true ) {
126 $array = [];
127 if ( is_object( $objOrArray ) ) {
128 $objOrArray = get_object_vars( $objOrArray );
129 }
130 foreach ( $objOrArray as $key => $value ) {
131 if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) {
132 $value = wfObjectToArray( $value );
133 }
134
135 $array[$key] = $value;
136 }
137
138 return $array;
139}
140
151function wfRandom() {
152 // The maximum random value is "only" 2^31-1, so get two random
153 // values to reduce the chance of dupes
154 $max = mt_getrandmax() + 1;
155 $rand = number_format( ( mt_rand() * $max + mt_rand() ) / $max / $max, 12, '.', '' );
156 return $rand;
157}
158
169function wfRandomString( $length = 32 ) {
170 $str = '';
171 for ( $n = 0; $n < $length; $n += 7 ) {
172 $str .= sprintf( '%07x', mt_rand() & 0xfffffff );
173 }
174 return substr( $str, 0, $length );
175}
176
204function wfUrlencode( $s ) {
205 static $needle;
206
207 if ( $s === null ) {
208 // Reset $needle for testing.
209 $needle = null;
210 return '';
211 }
212
213 if ( $needle === null ) {
214 $needle = [ '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F', '%7E' ];
215 if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) ||
216 !str_contains( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' )
217 ) {
218 $needle[] = '%3A';
219 }
220 }
221
222 $s = urlencode( $s );
223 $s = str_ireplace(
224 $needle,
225 [ ';', '@', '$', '!', '*', '(', ')', ',', '/', '~', ':' ],
226 $s
227 );
228
229 return $s;
230}
231
242function wfArrayToCgi( $array1, $array2 = null, $prefix = '' ) {
243 if ( $array2 !== null ) {
244 $array1 += $array2;
245 }
246
247 $cgi = '';
248 foreach ( $array1 as $key => $value ) {
249 if ( $value !== null && $value !== false ) {
250 if ( $cgi != '' ) {
251 $cgi .= '&';
252 }
253 if ( $prefix !== '' ) {
254 $key = $prefix . "[$key]";
255 }
256 if ( is_array( $value ) ) {
257 $firstTime = true;
258 foreach ( $value as $k => $v ) {
259 $cgi .= $firstTime ? '' : '&';
260 if ( is_array( $v ) ) {
261 $cgi .= wfArrayToCgi( $v, null, $key . "[$k]" );
262 } else {
263 $cgi .= urlencode( $key . "[$k]" ) . '=' . urlencode( $v );
264 }
265 $firstTime = false;
266 }
267 } else {
268 if ( is_object( $value ) ) {
269 $value = $value->__toString();
270 }
271 $cgi .= urlencode( $key ) . '=' . urlencode( $value );
272 }
273 }
274 }
275 return $cgi;
276}
277
287function wfCgiToArray( $query ) {
288 if ( isset( $query[0] ) && $query[0] == '?' ) {
289 $query = substr( $query, 1 );
290 }
291 $bits = explode( '&', $query );
292 $ret = [];
293 foreach ( $bits as $bit ) {
294 if ( $bit === '' ) {
295 continue;
296 }
297 if ( !str_contains( $bit, '=' ) ) {
298 // Pieces like &qwerty become 'qwerty' => '' (at least this is what php does)
299 $key = $bit;
300 $value = '';
301 } else {
302 [ $key, $value ] = explode( '=', $bit );
303 }
304 $key = urldecode( $key );
305 $value = urldecode( $value );
306 if ( str_contains( $key, '[' ) ) {
307 $keys = array_reverse( explode( '[', $key ) );
308 $key = array_pop( $keys );
309 $temp = $value;
310 foreach ( $keys as $k ) {
311 $k = substr( $k, 0, -1 );
312 $temp = [ $k => $temp ];
313 }
314 if ( isset( $ret[$key] ) && is_array( $ret[$key] ) ) {
315 $ret[$key] = array_merge( $ret[$key], $temp );
316 } else {
317 $ret[$key] = $temp;
318 }
319 } else {
320 $ret[$key] = $value;
321 }
322 }
323 return $ret;
324}
325
334function wfAppendQuery( $url, $query ) {
335 if ( is_array( $query ) ) {
336 $query = wfArrayToCgi( $query );
337 }
338 if ( $query != '' ) {
339 // Remove the fragment, if there is one
340 $fragment = false;
341 $hashPos = strpos( $url, '#' );
342 if ( $hashPos !== false ) {
343 $fragment = substr( $url, $hashPos );
344 $url = substr( $url, 0, $hashPos );
345 }
346
347 // Add parameter
348 if ( !str_contains( $url, '?' ) ) {
349 $url .= '?';
350 } else {
351 $url .= '&';
352 }
353 $url .= $query;
354
355 // Put the fragment back
356 if ( $fragment !== false ) {
357 $url .= $fragment;
358 }
359 }
360 return $url;
361}
362
369 wfDeprecated( __FUNCTION__, '1.43' );
372
373 if ( MediaWikiServices::hasInstance() ) {
374 $services = MediaWikiServices::getInstance();
375 if ( $services->hasService( 'UrlUtils' ) ) {
376 return $services->getUrlUtils();
377 }
378 }
379
380 return new UrlUtils( [
381 // UrlUtils throws if the relevant $wg(|Canonical|Internal) variable is null, but the old
382 // implementations implicitly converted it to an empty string (presumably by mistake).
383 // Preserve the old behavior for compatibility.
384 UrlUtils::SERVER => $wgServer ?? '',
385 UrlUtils::CANONICAL_SERVER => $wgCanonicalServer ?? '',
386 UrlUtils::INTERNAL_SERVER => $wgInternalServer ?? '',
387 UrlUtils::FALLBACK_PROTOCOL => $wgRequest ? $wgRequest->getProtocol()
388 : WebRequest::detectProtocol(),
389 UrlUtils::HTTPS_PORT => $wgHttpsPort,
390 UrlUtils::VALID_PROTOCOLS => $wgUrlProtocols,
391 ] );
392}
393
414function wfDebug( $text, $dest = 'all', array $context = [] ) {
416
417 if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
418 return;
419 }
420
421 $text = trim( $text );
422
423 if ( $wgDebugLogPrefix !== '' ) {
424 $context['prefix'] = $wgDebugLogPrefix;
425 }
426 $context['private'] = ( $dest === false || $dest === 'private' );
427
428 $logger = LoggerFactory::getInstance( 'wfDebug' );
429 $logger->debug( $text, $context );
430}
431
437 static $cache;
438 if ( $cache !== null ) {
439 return $cache;
440 }
441 // Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet
442 // phpcs:ignore MediaWiki.Usage.SuperGlobalsUsage.SuperGlobals
443 if ( ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' )
444 || MW_ENTRY_POINT === 'load'
445 ) {
446 $cache = true;
447 } else {
448 $cache = false;
449 }
450 return $cache;
451}
452
478function wfDebugLog(
479 $logGroup, $text, $dest = 'all', array $context = []
480) {
481 $text = trim( $text );
482
483 $logger = LoggerFactory::getInstance( $logGroup );
484 $context['private'] = ( $dest === false || $dest === 'private' );
485 $logger->info( $text, $context );
486}
487
496function wfLogDBError( $text, array $context = [] ) {
497 $logger = LoggerFactory::getInstance( 'wfLogDBError' );
498 $logger->error( trim( $text ), $context );
499}
500
517function wfDeprecated( $function, $version = false, $component = false, $callerOffset = 2 ) {
518 if ( !is_string( $version ) && $version !== false ) {
519 throw new InvalidArgumentException(
520 "MediaWiki version must either be a string or false. " .
521 "Example valid version: '1.33'"
522 );
523 }
524
525 MWDebug::deprecated( $function, $version, $component, $callerOffset + 1 );
526}
527
548function wfDeprecatedMsg( $msg, $version = false, $component = false, $callerOffset = 2 ) {
549 MWDebug::deprecatedMsg( $msg, $version, $component,
550 $callerOffset === false ? false : $callerOffset + 1 );
551}
552
563function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
564 MWDebug::warning( $msg, $callerOffset + 1, $level, 'auto' );
565}
566
576function wfLogWarning( $msg, $callerOffset = 1, $level = E_USER_WARNING ) {
577 MWDebug::warning( $msg, $callerOffset + 1, $level, 'production' );
578}
579
602function wfMessage( $key, ...$params ) {
603 if ( is_array( $key ) ) {
604 // Fallback keys are not allowed in message specifiers
605 $message = wfMessageFallback( ...$key );
606 } else {
607 $message = Message::newFromSpecifier( $key );
608 }
609
610 // We call Message::params() to reduce code duplication
611 if ( $params ) {
612 $message->params( ...$params );
613 }
614
615 return $message;
616}
617
630function wfMessageFallback( ...$keys ) {
631 return Message::newFallbackSequence( ...$keys );
632}
633
642function wfMsgReplaceArgs( $message, $args ) {
643 # Fix windows line-endings
644 # Some messages are split with explode("\n", $msg)
645 $message = str_replace( "\r", '', $message );
646
647 // Replace arguments
648 if ( is_array( $args ) && $args ) {
649 if ( is_array( $args[0] ) ) {
650 $args = array_values( $args[0] );
651 }
652 $replacementKeys = [];
653 foreach ( $args as $n => $param ) {
654 $replacementKeys['$' . ( $n + 1 )] = $param;
655 }
656 $message = strtr( $message, $replacementKeys );
657 }
658
659 return $message;
660}
661
670function wfHostname() {
671 // Hostname overriding
672 global $wgOverrideHostname;
673 if ( $wgOverrideHostname !== false ) {
674 return $wgOverrideHostname;
675 }
676
677 return php_uname( 'n' ) ?: 'unknown';
678}
679
690function wfDebugBacktrace( $limit = 0 ) {
691 static $disabled = null;
692
693 if ( $disabled === null ) {
694 $disabled = !function_exists( 'debug_backtrace' );
695 if ( $disabled ) {
696 wfDebug( "debug_backtrace() is disabled" );
697 }
698 }
699 if ( $disabled ) {
700 return [];
701 }
702
703 if ( $limit ) {
704 return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit + 1 ), 1 );
705 } else {
706 return array_slice( debug_backtrace(), 1 );
707 }
708}
709
718function wfBacktrace( $raw = null ) {
719 $raw ??= MW_ENTRY_POINT === 'cli';
720 if ( $raw ) {
721 $frameFormat = "%s line %s calls %s()\n";
722 $traceFormat = "%s";
723 } else {
724 $frameFormat = "<li>%s line %s calls %s()</li>\n";
725 $traceFormat = "<ul>\n%s</ul>\n";
726 }
727
728 $frames = array_map( static function ( $frame ) use ( $frameFormat ) {
729 $file = !empty( $frame['file'] ) ? basename( $frame['file'] ) : '-';
730 $line = $frame['line'] ?? '-';
731 $call = $frame['function'];
732 if ( !empty( $frame['class'] ) ) {
733 $call = $frame['class'] . $frame['type'] . $call;
734 }
735 return sprintf( $frameFormat, $file, $line, $call );
736 }, wfDebugBacktrace() );
737
738 return sprintf( $traceFormat, implode( '', $frames ) );
739}
740
751function wfGetCaller( $level = 2 ) {
752 $backtrace = wfDebugBacktrace( $level + 1 );
753 if ( isset( $backtrace[$level] ) ) {
754 return wfFormatStackFrame( $backtrace[$level] );
755 } else {
756 return 'unknown';
757 }
758}
759
767function wfGetAllCallers( $limit = 3 ) {
768 $limit = $limit ? $limit + 1 : 0;
769 // Strip the own "wfGetAllCallers" from the list
770 $trace = array_reverse( array_slice( wfDebugBacktrace( $limit ), 1 ) );
771 return implode( '/', array_map( wfFormatStackFrame( ... ), $trace ) );
772}
773
786function wfFormatStackFrame( $frame ) {
787 if ( !isset( $frame['function'] ) ) {
788 return 'NO_FUNCTION_GIVEN';
789 }
790 return isset( $frame['class'] ) && isset( $frame['type'] ) ?
791 $frame['class'] . $frame['type'] . $frame['function'] :
792 $frame['function'];
793}
794
804function wfClientAcceptsGzip( $force = false ) {
805 static $result = null;
806 if ( $result === null || $force ) {
807 $result = false;
808 if ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) {
809 # @todo FIXME: We may want to disallow some broken browsers
810 $m = [];
811 if ( preg_match(
812 '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/',
813 $_SERVER['HTTP_ACCEPT_ENCODING'],
814 $m
815 )
816 ) {
817 if ( isset( $m[2] ) && ( $m[1] == 'q' ) && ( $m[2] == 0 ) ) {
818 return $result;
819 }
820 wfDebug( "wfClientAcceptsGzip: client accepts gzip." );
821 $result = true;
822 }
823 }
824 }
825 return $result;
826}
827
838function wfEscapeWikiText( $input ): string {
839 global $wgEnableMagicLinks;
840 static $repl = null, $repl2 = null, $repl3 = null, $repl4 = null;
841 if ( $repl === null || defined( 'MW_PHPUNIT_TEST' ) ) {
842 // Tests depend upon being able to change $wgEnableMagicLinks, so don't cache
843 // in those situations
844 $repl = [
845 '"' => '&#34;', '&' => '&#38;', "'" => '&#39;', '<' => '&#60;',
846 '=' => '&#61;', '>' => '&#62;', '[' => '&#91;', ']' => '&#93;',
847 '{' => '&#123;', '|' => '&#124;', '}' => '&#125;',
848 ';' => '&#59;', // a token inside language converter brackets
849 '!!' => '&#33;!', // a token inside table context
850 "\n!" => "\n&#33;", "\r!" => "\r&#33;", // a token inside table context
851 "\n#" => "\n&#35;", "\r#" => "\r&#35;",
852 "\n*" => "\n&#42;", "\r*" => "\r&#42;",
853 "\n:" => "\n&#58;", "\r:" => "\r&#58;",
854 "\n " => "\n&#32;", "\r " => "\r&#32;",
855 "\n\n" => "\n&#10;", "\r\n" => "&#13;\n",
856 "\n\r" => "\n&#13;", "\r\r" => "\r&#13;",
857 "\n\t" => "\n&#9;", "\r\t" => "\r&#9;", // "\n\t\n" is treated like "\n\n"
858 "\n----" => "\n&#45;---", "\r----" => "\r&#45;---",
859 '__' => '_&#95;', '://' => '&#58;//',
860 // Japanese magic words start w/ wide underscore
861 '_' => '&#xFF3F;',
862 '~~~' => '~~&#126;', // protect from PST, just to be safe(r)
863 ];
864
865 $magicLinks = array_keys( array_filter( $wgEnableMagicLinks ) );
866 // We have to catch everything "\s" matches in PCRE
867 foreach ( $magicLinks as $magic ) {
868 $repl["$magic "] = "$magic&#32;";
869 $repl["$magic\t"] = "$magic&#9;";
870 $repl["$magic\r"] = "$magic&#13;";
871 $repl["$magic\n"] = "$magic&#10;";
872 $repl["$magic\f"] = "$magic&#12;";
873 }
874 // Additionally escape the following characters at the beginning of the
875 // string, in case they merge to form tokens when spliced into a
876 // string. Tokens like -{ {{ [[ {| etc are already escaped because
877 // the second character is escaped above, but the following tokens
878 // are handled here: |+ |- __FOO__ ~~~
879 // (Only single-byte characters can go here; multibyte characters
880 // like 'wide underscore' must go into $repl above.)
881 $repl3 = [
882 '+' => '&#43;', '-' => '&#45;', '_' => '&#95;', '~' => '&#126;',
883 ];
884 // Similarly, protect the following characters at the end of the
885 // string, which could turn form the start of `__FOO__` or `~~~~`
886 // A trailing newline could also form the unintended start of a
887 // paragraph break if it is glued to a newline in the following
888 // context. Again, only single-byte characters can be protected
889 // here; 'wide underscore' is protected by $repl above.
890 $repl4 = [
891 '_' => '&#95;', '~' => '&#126;',
892 "\n" => "&#10;", "\r" => "&#13;",
893 "\t" => "&#9;", // "\n\t\n" is treated like "\n\n"
894 ];
895
896 // And handle protocols that don't use "://"
897 global $wgUrlProtocols;
898 $repl2 = [];
899 foreach ( $wgUrlProtocols as $prot ) {
900 if ( substr( $prot, -1 ) === ':' ) {
901 $repl2[] = preg_quote( substr( $prot, 0, -1 ), '/' );
902 }
903 }
904 $repl2 = $repl2 ? '/\b(' . implode( '|', $repl2 ) . '):/i' : '/^(?!)/';
905 }
906 // Tell phan that $repl2, $repl3 and $repl4 will also be non-null here
907 '@phan-var string $repl2';
908 '@phan-var string $repl3';
909 '@phan-var string $repl4';
910 // This will also stringify input in case it's not a string
911 $text = substr( strtr( "\n$input", $repl ), 1 );
912 if ( $text === '' ) {
913 return $text;
914 }
915 $first = strtr( $text[0], $repl3 ); // protect first character
916 if ( strlen( $text ) > 1 ) {
917 $text = $first . substr( $text, 1, -1 ) .
918 strtr( substr( $text, -1 ), $repl4 ); // protect last character
919 } else {
920 // special case for single-character strings
921 $text = strtr( $first, $repl4 ); // protect last character
922 }
923 $text = preg_replace( $repl2, '$1&#58;', $text );
924 return $text;
925}
926
937function wfSetVar( &$dest, $source, $force = false ) {
938 $temp = $dest;
939 if ( $source !== null || $force ) {
940 $dest = $source;
941 }
942 return $temp;
943}
944
954function wfSetBit( &$dest, $bit, $state = true ) {
955 $temp = (bool)( $dest & $bit );
956 if ( $state !== null ) {
957 if ( $state ) {
958 $dest |= $bit;
959 } else {
960 $dest &= ~$bit;
961 }
962 }
963 return $temp;
964}
965
972function wfVarDump( $var ) {
973 global $wgOut;
974 $s = str_replace( "\n", "<br />\n", var_export( $var, true ) . "\n" );
975 if ( headers_sent() || $wgOut === null || !is_object( $wgOut ) ) {
976 print $s;
977 } else {
978 $wgOut->addHTML( $s );
979 }
980}
981
989function wfHttpError( $code, $label, $desc ) {
990 global $wgOut;
991 HttpStatus::header( $code );
992 if ( $wgOut ) {
993 $wgOut->disable();
994 $wgOut->sendCacheControl();
995 }
996
997 \MediaWiki\Request\HeaderCallback::warnIfHeadersSent();
998 header( 'Content-type: text/html; charset=utf-8' );
999 ContentSecurityPolicy::sendRestrictiveHeader();
1000 ob_start();
1001 print '<!DOCTYPE html>' .
1002 '<html><head><title>' .
1003 htmlspecialchars( $label ) .
1004 '</title><meta name="color-scheme" content="light dark" /></head><body><h1>' .
1005 htmlspecialchars( $label ) .
1006 '</h1><p>' .
1007 nl2br( htmlspecialchars( $desc ) ) .
1008 "</p></body></html>\n";
1009 header( 'Content-Length: ' . ob_get_length() );
1010 ob_end_flush();
1011}
1012
1033function wfResetOutputBuffers( $resetGzipEncoding = true ) {
1034 // phpcs:ignore Generic.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
1035 while ( $status = ob_get_status() ) {
1036 if ( isset( $status['flags'] ) ) {
1037 $flags = PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_REMOVABLE;
1038 $deleteable = ( $status['flags'] & $flags ) === $flags;
1039 } elseif ( isset( $status['del'] ) ) {
1040 $deleteable = $status['del'];
1041 } else {
1042 // Guess that any PHP-internal setting can't be removed.
1043 $deleteable = $status['type'] !== 0; /* PHP_OUTPUT_HANDLER_INTERNAL */
1044 }
1045 if ( !$deleteable ) {
1046 // Give up, and hope the result doesn't break
1047 // output behavior.
1048 break;
1049 }
1050 if ( $status['name'] === 'MediaWikiIntegrationTestCase::wfResetOutputBuffersBarrier' ) {
1051 // Unit testing barrier to prevent this function from breaking PHPUnit.
1052 break;
1053 }
1054 if ( !ob_end_clean() ) {
1055 // Could not remove output buffer handler; abort now
1056 // to avoid getting in some kind of infinite loop.
1057 break;
1058 }
1059 if ( $resetGzipEncoding && $status['name'] == 'ob_gzhandler' ) {
1060 // Reset the 'Content-Encoding' field set by this handler
1061 // so we can start fresh.
1062 header_remove( 'Content-Encoding' );
1063 break;
1064 }
1065 }
1066}
1067
1078function wfTimestamp( $outputtype = TS::UNIX, $ts = 0 ) {
1079 $ret = ConvertibleTimestamp::convert( $outputtype, $ts );
1080 if ( $ret === false ) {
1081 if ( $outputtype instanceof TS ) {
1082 $outputtype = $outputtype->name;
1083 }
1084 wfDebug( "wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts" );
1085 }
1086 return $ret;
1087}
1088
1097function wfTimestampOrNull( $outputtype = TS::UNIX, $ts = null ) {
1098 if ( $ts === null ) {
1099 return null;
1100 } else {
1101 return wfTimestamp( $outputtype, $ts );
1102 }
1103}
1104
1110function wfTimestampNow() {
1111 return ConvertibleTimestamp::now( TS::MW );
1112}
1113
1125function wfTempDir() {
1126 global $wgTmpDirectory;
1127
1128 if ( $wgTmpDirectory !== false ) {
1129 return $wgTmpDirectory;
1130 }
1131
1132 return TempFSFile::getUsableTempDirectory();
1133}
1134
1143function wfMkdirParents( $dir, $mode = null, $caller = null ) {
1144 global $wgDirectoryMode;
1145
1146 if ( FileBackend::isStoragePath( $dir ) ) {
1147 throw new LogicException( __FUNCTION__ . " given storage path '$dir'." );
1148 }
1149 if ( $caller !== null ) {
1150 wfDebug( "$caller: called wfMkdirParents($dir)" );
1151 }
1152 if ( strval( $dir ) === '' ) {
1153 return true;
1154 }
1155
1156 $dir = str_replace( [ '\\', '/' ], DIRECTORY_SEPARATOR, $dir );
1157 $mode ??= $wgDirectoryMode;
1158
1159 // Turn off the normal warning, we're doing our own below
1160 // PHP doesn't include the path in its warning message, so we add our own to aid in diagnosis.
1161 //
1162 // Repeat existence check if creation failed so that we silently recover in case of
1163 // a race condition where another request created it since the first check.
1164 //
1165 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1166 $ok = is_dir( $dir ) || @mkdir( $dir, $mode, true ) || is_dir( $dir );
1167 if ( !$ok ) {
1168 trigger_error( sprintf( "failed to mkdir \"%s\" mode 0%o", $dir, $mode ), E_USER_WARNING );
1169 }
1170
1171 return $ok;
1172}
1173
1179function wfRecursiveRemoveDir( $dir ) {
1180 // taken from https://www.php.net/manual/en/function.rmdir.php#98622
1181 if ( is_dir( $dir ) ) {
1182 $objects = scandir( $dir );
1183 foreach ( $objects as $object ) {
1184 if ( $object != "." && $object != ".." ) {
1185 if ( filetype( $dir . '/' . $object ) == "dir" ) {
1186 wfRecursiveRemoveDir( $dir . '/' . $object );
1187 } else {
1188 unlink( $dir . '/' . $object );
1189 }
1190 }
1191 }
1192 rmdir( $dir );
1193 }
1194}
1195
1202function wfPercent( $nr, int $acc = 2, bool $round = true ) {
1203 $accForFormat = $acc >= 0 ? $acc : 0;
1204 $ret = sprintf( "%.{$accForFormat}f", $nr );
1205 return $round ? round( (float)$ret, $acc ) . '%' : "$ret%";
1206}
1207
1231function wfIniGetBool( $setting ) {
1232 return wfStringToBool( ini_get( $setting ) );
1233}
1234
1247function wfStringToBool( $val ) {
1248 $val = strtolower( $val );
1249 // 'on' and 'true' can't have whitespace around them, but '1' can.
1250 return $val == 'on'
1251 || $val == 'true'
1252 || $val == 'yes'
1253 || preg_match( "/^\s*[+-]?0*[1-9]/", $val ); // approx C atoi() function
1254}
1255
1269function wfEscapeShellArg( ...$args ) {
1270 return Shell::escape( ...$args );
1271}
1272
1297function wfShellExec( $cmd, &$retval = null, $environ = [],
1298 $limits = [], $options = []
1299) {
1300 if ( Shell::isDisabled() ) {
1301 $retval = 1;
1302 // Backwards compatibility be upon us...
1303 return 'Unable to run external programs, proc_open() is disabled.';
1304 }
1305
1306 if ( is_array( $cmd ) ) {
1307 $cmd = Shell::escape( $cmd );
1308 }
1309
1310 $includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr'];
1311 $profileMethod = $options['profileMethod'] ?? wfGetCaller();
1312
1313 try {
1314 $result = Shell::command( [] )
1315 ->unsafeParams( (array)$cmd )
1316 ->environment( $environ )
1317 ->limits( $limits )
1318 ->includeStderr( $includeStderr )
1319 ->profileMethod( $profileMethod )
1320 // For b/c
1321 ->restrict( Shell::RESTRICT_NONE )
1322 ->execute();
1323 } catch ( ProcOpenError ) {
1324 $retval = -1;
1325 return '';
1326 }
1327
1328 $retval = $result->getExitCode();
1329
1330 return $result->getStdout();
1331}
1332
1350function wfShellExecWithStderr( $cmd, &$retval = null, $environ = [], $limits = [] ) {
1351 return wfShellExec( $cmd, $retval, $environ, $limits,
1352 [ 'duplicateStderr' => true, 'profileMethod' => wfGetCaller() ] );
1353}
1354
1370function wfShellWikiCmd( $script, array $parameters = [], array $options = [] ) {
1371 global $wgPhpCli;
1372 // Give site config file a chance to run the script in a wrapper.
1373 // The caller may likely want to call wfBasename() on $script.
1374 ( new HookRunner( MediaWikiServices::getInstance()->getHookContainer() ) )
1375 ->onWfShellWikiCmd( $script, $parameters, $options );
1376 $cmd = [ $options['php'] ?? $wgPhpCli ];
1377 if ( isset( $options['wrapper'] ) ) {
1378 $cmd[] = $options['wrapper'];
1379 }
1380 $cmd[] = $script;
1381 // Escape each parameter for shell
1382 return Shell::escape( array_merge( $cmd, $parameters ) );
1383}
1384
1401function wfMerge(
1402 string $old,
1403 string $mine,
1404 string $yours,
1405 ?string &$simplisticMergeAttempt,
1406 ?string &$mergeLeftovers = null
1407): bool {
1408 global $wgDiff3;
1409
1410 # This check may also protect against code injection in
1411 # case of broken installations.
1412 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1413 $haveDiff3 = $wgDiff3 && @file_exists( $wgDiff3 );
1414
1415 if ( !$haveDiff3 ) {
1416 wfDebug( "diff3 not found" );
1417 return false;
1418 }
1419
1420 # Make temporary files
1421 $td = wfTempDir();
1422 $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
1423 $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' );
1424 $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' );
1425
1426 # NOTE: diff3 issues a warning to stderr if any of the files does not end with
1427 # a newline character. To avoid this, we normalize the trailing whitespace before
1428 # creating the diff.
1429
1430 fwrite( $oldtextFile, rtrim( $old ) . "\n" );
1431 fclose( $oldtextFile );
1432 fwrite( $mytextFile, rtrim( $mine ) . "\n" );
1433 fclose( $mytextFile );
1434 fwrite( $yourtextFile, rtrim( $yours ) . "\n" );
1435 fclose( $yourtextFile );
1436
1437 # Check for a conflict
1438 $cmd = Shell::escape( $wgDiff3, '--text', '--overlap-only', $mytextName,
1439 $oldtextName, $yourtextName );
1440 $handle = popen( $cmd, 'r' );
1441
1442 $mergeLeftovers = '';
1443 do {
1444 $data = fread( $handle, 8192 );
1445 if ( $data === false || $data === '' ) {
1446 break;
1447 }
1448 $mergeLeftovers .= $data;
1449 } while ( true );
1450 pclose( $handle );
1451
1452 $conflict = $mergeLeftovers !== '';
1453
1454 # Merge differences automatically where possible, preferring "my" text for conflicts.
1455 $cmd = Shell::escape( $wgDiff3, '--text', '--ed', '--merge', $mytextName,
1456 $oldtextName, $yourtextName );
1457 $handle = popen( $cmd, 'r' );
1458 $simplisticMergeAttempt = '';
1459 do {
1460 $data = fread( $handle, 8192 );
1461 if ( $data === false || $data === '' ) {
1462 break;
1463 }
1464 $simplisticMergeAttempt .= $data;
1465 } while ( true );
1466 pclose( $handle );
1467 unlink( $mytextName );
1468 unlink( $oldtextName );
1469 unlink( $yourtextName );
1470
1471 if ( $simplisticMergeAttempt === '' && $old !== '' && !$conflict ) {
1472 wfDebug( "Unexpected null result from diff3. Command: $cmd" );
1473 $conflict = true;
1474 }
1475 return !$conflict;
1476}
1477
1490function wfBaseName( $path, $suffix = '' ) {
1491 if ( $suffix == '' ) {
1492 $encSuffix = '';
1493 } else {
1494 $encSuffix = '(?:' . preg_quote( $suffix, '#' ) . ')?';
1495 }
1496
1497 $matches = [];
1498 if ( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) {
1499 return $matches[1];
1500 } else {
1501 return '';
1502 }
1503}
1504
1514function wfRelativePath( $path, $from ) {
1515 // Normalize mixed input on Windows...
1516 $path = str_replace( '/', DIRECTORY_SEPARATOR, $path );
1517 $from = str_replace( '/', DIRECTORY_SEPARATOR, $from );
1518
1519 // Trim trailing slashes -- fix for drive root
1520 $path = rtrim( $path, DIRECTORY_SEPARATOR );
1521 $from = rtrim( $from, DIRECTORY_SEPARATOR );
1522
1523 $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) );
1524 $against = explode( DIRECTORY_SEPARATOR, $from );
1525
1526 if ( $pieces[0] !== $against[0] ) {
1527 // Non-matching Windows drive letters?
1528 // Return a full path.
1529 return $path;
1530 }
1531
1532 // Trim off common prefix
1533 while ( count( $pieces ) && count( $against )
1534 && $pieces[0] == $against[0] ) {
1535 array_shift( $pieces );
1536 array_shift( $against );
1537 }
1538
1539 // relative dots to bump us to the parent
1540 while ( count( $against ) ) {
1541 array_unshift( $pieces, '..' );
1542 array_shift( $against );
1543 }
1544
1545 $pieces[] = wfBaseName( $path );
1546
1547 return implode( DIRECTORY_SEPARATOR, $pieces );
1548}
1549
1559function wfScript( $script = 'index' ) {
1561 if ( $script === 'index' ) {
1562 return $wgScript;
1563 } elseif ( $script === 'load' ) {
1564 return $wgLoadScript;
1565 } else {
1566 return "{$wgScriptPath}/{$script}.php";
1567 }
1568}
1569
1577function wfBoolToStr( $value ) {
1578 return $value ? 'true' : 'false';
1579}
1580
1586function wfGetNull() {
1587 return wfIsWindows() ? 'NUL' : '/dev/null';
1588}
1589
1599 global $wgIllegalFileChars;
1600 $illegalFileChars = $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : '';
1601 $name = preg_replace(
1602 "/[^" . Title::legalChars() . "]" . $illegalFileChars . "/",
1603 '-',
1604 $name
1605 );
1606 // $wgIllegalFileChars may not include '/' and '\', so we still need to do this
1607 $name = wfBaseName( $name );
1608 return $name;
1609}
1610
1617function wfMemoryLimit( $newLimit ) {
1618 $oldLimit = wfShorthandToInteger( ini_get( 'memory_limit' ) );
1619 // If the INI config is already unlimited, there is nothing larger
1620 if ( $oldLimit != -1 ) {
1621 $newLimit = wfShorthandToInteger( (string)$newLimit );
1622 if ( $newLimit == -1 ) {
1623 wfDebug( "Removing PHP's memory limit" );
1624 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1625 @ini_set( 'memory_limit', $newLimit );
1626 } elseif ( $newLimit > $oldLimit ) {
1627 wfDebug( "Raising PHP's memory limit to $newLimit bytes" );
1628 // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged
1629 @ini_set( 'memory_limit', $newLimit );
1630 }
1631 }
1632}
1633
1642
1643 $timeout = RequestTimeout::singleton();
1644 $timeLimit = $timeout->getWallTimeLimit();
1645 if ( $timeLimit !== INF ) {
1646 // RequestTimeout library is active
1647 if ( $wgTransactionalTimeLimit > $timeLimit ) {
1648 $timeout->setWallTimeLimit( $wgTransactionalTimeLimit );
1649 }
1650 } else {
1651 // Fallback case, likely $wgRequestTimeLimit === null
1652 $timeLimit = (int)ini_get( 'max_execution_time' );
1653 // Note that CLI scripts use 0
1654 if ( $timeLimit > 0 && $wgTransactionalTimeLimit > $timeLimit ) {
1655 $timeout->setWallTimeLimit( $wgTransactionalTimeLimit );
1656 }
1657 }
1658 ignore_user_abort( true ); // ignore client disconnects
1659
1660 return $timeLimit;
1661}
1662
1670function wfShorthandToInteger( ?string $string = '', int $default = -1 ): int {
1671 $string = trim( $string ?? '' );
1672 if ( $string === '' ) {
1673 return $default;
1674 }
1675 $last = substr( $string, -1 );
1676 $val = intval( $string );
1677 switch ( $last ) {
1678 case 'g':
1679 case 'G':
1680 $val *= 1024;
1681 // break intentionally missing
1682 case 'm':
1683 case 'M':
1684 $val *= 1024;
1685 // break intentionally missing
1686 case 'k':
1687 case 'K':
1688 $val *= 1024;
1689 }
1690
1691 return $val;
1692}
1693
1701function wfIsInfinity( $str ) {
1702 // The INFINITY_VALS are hardcoded elsewhere in MediaWiki (e.g. mediawiki.special.block.js).
1703 return in_array( $str, ExpiryDef::INFINITY_VALS );
1704}
1705
1720function wfThumbIsStandard( File $file, array $params ) {
1722
1723 $multipliers = [ 1 ];
1724 if ( $wgResponsiveImages ) {
1725 // These available sizes are hardcoded currently elsewhere in MediaWiki.
1726 // @see Linker::processResponsiveImages
1727 $multipliers[] = 2;
1728 }
1729
1730 $handler = $file->getHandler();
1731 if ( !$handler || !isset( $params['width'] ) ) {
1732 return false;
1733 }
1734
1735 $basicParams = [];
1736 if ( isset( $params['page'] ) ) {
1737 $basicParams['page'] = $params['page'];
1738 }
1739
1740 $thumbLimits = [];
1741 $imageLimits = [];
1742 // Expand limits to account for multipliers
1743 foreach ( $multipliers as $multiplier ) {
1744 $thumbLimits = array_merge( $thumbLimits, array_map(
1745 static function ( $width ) use ( $multiplier ) {
1746 return round( $width * $multiplier );
1747 }, $wgThumbLimits )
1748 );
1749 $imageLimits = array_merge( $imageLimits, array_map(
1750 static function ( $pair ) use ( $multiplier ) {
1751 return [
1752 round( $pair[0] * $multiplier ),
1753 round( $pair[1] * $multiplier ),
1754 ];
1755 }, $wgImageLimits )
1756 );
1757 }
1758
1759 // Check if the width matches one of $wgThumbLimits
1760 if ( in_array( $params['width'], $thumbLimits ) ) {
1761 $normalParams = $basicParams + [ 'width' => $params['width'] ];
1762 // Append any default values to the map (e.g. "lossy", "lossless", ...)
1763 $handler->normaliseParams( $file, $normalParams );
1764 } else {
1765 // If not, then check if the width matches one of $wgImageLimits
1766 $match = false;
1767 foreach ( $imageLimits as $pair ) {
1768 $normalParams = $basicParams + [ 'width' => $pair[0], 'height' => $pair[1] ];
1769 // Decide whether the thumbnail should be scaled on width or height.
1770 // Also append any default values to the map (e.g. "lossy", "lossless", ...)
1771 $handler->normaliseParams( $file, $normalParams );
1772 // Check if this standard thumbnail size maps to the given width
1773 if ( $normalParams['width'] == $params['width'] ) {
1774 $match = true;
1775 break;
1776 }
1777 }
1778 if ( !$match ) {
1779 return false; // not standard for description pages
1780 }
1781 }
1782
1783 // Check that the given values for non-page, non-width, params are just defaults
1784 foreach ( $params as $key => $value ) {
1785 if ( !isset( $normalParams[$key] ) || $normalParams[$key] != $value ) {
1786 return false;
1787 }
1788 }
1789
1790 return true;
1791}
1792
1806function wfArrayPlus2d( array $baseArray, array $newValues ) {
1807 return ArrayUtils::arrayPlus2d( $baseArray, $newValues );
1808}
wfIsWindows()
Check if the operating system is Windows.
wfThumbIsStandard(File $file, array $params)
Returns true if these thumbnail parameters match one that MediaWiki requests from file description pa...
wfVarDump( $var)
A wrapper around the PHP function var_export().
wfTimestampOrNull( $outputtype=TS::UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfRandom()
Get a random decimal value in the domain of [0, 1), in a way not likely to give duplicate values for ...
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness,...
wfTempDir()
Tries to get the system directory for temporary files.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.
wfBaseName( $path, $suffix='')
Return the final portion of a pathname.
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfClientAcceptsGzip( $force=false)
Whether the client accept gzip encoding.
wfEscapeShellArg(... $args)
Locale-independent version of escapeshellarg()
wfLogDBError( $text, array $context=[])
Log for database errors.
wfLoadSkins(array $skins)
Load multiple skins at once.
wfEscapeWikiText( $input)
Escapes the given text so that it may be output using addWikiText() without any linking,...
wfRecursiveRemoveDir( $dir)
Remove a directory and all its content.
wfLoadExtension( $ext, $path=null)
Load an extension.
wfMemoryLimit( $newLimit)
Raise PHP's memory limit (if needed).
wfSetBit(&$dest, $bit, $state=true)
As for wfSetVar except setting a bit.
wfIniGetBool( $setting)
Safety wrapper around ini_get() for boolean settings.
wfShorthandToInteger(?string $string='', int $default=-1)
Converts shorthand byte notation to integer form.
wfBacktrace( $raw=null)
Get a debug backtrace as a string.
wfGetCaller( $level=2)
Get the name of the function which called this function wfGetCaller( 1 ) is the function with the wfG...
wfDeprecatedMsg( $msg, $version=false, $component=false, $callerOffset=2)
Log a deprecation warning with arbitrary message text.
wfGetUrlUtils()
wfShellExec( $cmd, &$retval=null, $environ=[], $limits=[], $options=[])
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
wfIsDebugRawPage()
Returns true if debug logging should be suppressed if $wgDebugRawPage = false.
wfHostname()
Get host name of the current machine, for use in error reporting.
wfShellWikiCmd( $script, array $parameters=[], array $options=[])
Generate a shell-escaped command line string to run a MediaWiki cli script.
wfPercent( $nr, int $acc=2, bool $round=true)
wfSetVar(&$dest, $source, $force=false)
Sets dest to source and returns the original value of dest If source is NULL, it just returns the val...
wfShellExecWithStderr( $cmd, &$retval=null, $environ=[], $limits=[])
Execute a shell command, returning both stdout and stderr.
wfGetNull()
Get a platform-independent path to the null file, e.g.
wfRelativePath( $path, $from)
Generate a relative path name to the given file.
wfHttpError( $code, $label, $desc)
Provide a simple HTTP error.
wfMessageFallback(... $keys)
This function accepts multiple message keys and returns a message instance for the first message whic...
wfMerge(string $old, string $mine, string $yours, ?string &$simplisticMergeAttempt, ?string &$mergeLeftovers=null)
wfMerge attempts to merge differences between three texts.
wfGetAllCallers( $limit=3)
Return a string consisting of callers in the stack.
wfArrayPlus2d(array $baseArray, array $newValues)
Merges two (possibly) 2 dimensional arrays into the target array ($baseArray).
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfTransactionalTimeLimit()
Raise the request time limit to $wgTransactionalTimeLimit.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
wfObjectToArray( $objOrArray, $recursive=true)
Recursively converts the parameter (an object) to an array with the same data.
wfLoadSkin( $skin, $path=null)
Load a skin.
wfMsgReplaceArgs( $message, $args)
Replace message parameter keys on the given formatted output.
wfStringToBool( $val)
Convert string value to boolean, when the following are interpreted as true:
wfTimestamp( $outputtype=TS::UNIX, $ts=0)
Get a timestamp string in one of various formats.
wfDebugBacktrace( $limit=0)
Safety wrapper for debug_backtrace().
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfStripIllegalFilenameChars( $name)
Replace all invalid characters with '-'.
wfFormatStackFrame( $frame)
Return a string representation of frame.
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e....
wfScript( $script='index')
Get the URL path to a MediaWiki entry point.
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
wfIsInfinity( $str)
Determine input string is represents as infinity.
wfMkdirParents( $dir, $mode=null, $caller=null)
Make directory, and make all parent directories if they don't exist.
wfLoadExtensions(array $exts)
Load multiple extensions at once.
wfBoolToStr( $value)
Convenience function converts boolean values into "true" or "false" (string) values.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Logs a warning that a deprecated feature was used.
wfArrayInsertAfter(array $array, array $insert, $after)
Insert an array into another array after the specified key.
wfResetOutputBuffers( $resetGzipEncoding=true)
Clear away any user-level output buffers, discarding contents.
global $wgRequest
Definition Setup.php:433
if(MW_ENTRY_POINT==='index') if(!defined( 'MW_NO_SESSION') &&MW_ENTRY_POINT !=='cli' $wgOut
Definition Setup.php:550
const MW_ENTRY_POINT
Definition api.php:21
Debug toolbar.
Definition MWDebug.php:35
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition File.php:80
getHandler(?Language $lang=null)
Get a MediaHandler instance for this file.
Definition File.php:1608
This class provides an implementation of the core hook interfaces, forwarding hook calls to HookConta...
Create PSR-3 logger objects.
Service locator for MediaWiki core services.
The Message class deals with fetching and processing of interface message into a variety of formats.
Definition Message.php:144
Load JSON files, and uses a Processor to extract information.
Handle sending Content-Security-Policy headers.
The WebRequest class encapsulates getting at data passed in the URL or via a POSTed form,...
Executes shell commands.
Definition Shell.php:32
Represents a title within MediaWiki.
Definition Title.php:69
A service to expand, parse, and otherwise manipulate URLs.
Definition UrlUtils.php:16
A collection of static methods to play with arrays.
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).
Value object representing a message parameter with one of the types from {.
Type definition for expiry timestamps.
Definition ExpiryDef.php:18
$wgScript
Config variable stub for the Script setting, for use by phpdoc and IDEs.
$wgInternalServer
Config variable stub for the InternalServer setting, for use by phpdoc and IDEs.
$wgThumbLimits
Config variable stub for the ThumbLimits setting, for use by phpdoc and IDEs.
$wgDebugLogPrefix
Config variable stub for the DebugLogPrefix setting, for use by phpdoc and IDEs.
$wgPhpCli
Config variable stub for the PhpCli setting, for use by phpdoc and IDEs.
$wgOverrideHostname
Config variable stub for the OverrideHostname setting, for use by phpdoc and IDEs.
$wgImageLimits
Config variable stub for the ImageLimits setting, for use by phpdoc and IDEs.
$wgTmpDirectory
Config variable stub for the TmpDirectory setting, for use by phpdoc and IDEs.
$wgStyleDirectory
Config variable stub for the StyleDirectory setting, for use by phpdoc and IDEs.
$wgTransactionalTimeLimit
Config variable stub for the TransactionalTimeLimit setting, for use by phpdoc and IDEs.
$wgIllegalFileChars
Config variable stub for the IllegalFileChars setting, for use by phpdoc and IDEs.
$wgDirectoryMode
Config variable stub for the DirectoryMode setting, for use by phpdoc and IDEs.
$wgDiff3
Config variable stub for the Diff3 setting, for use by phpdoc and IDEs.
$wgUrlProtocols
Config variable stub for the UrlProtocols setting, for use by phpdoc and IDEs.
$wgResponsiveImages
Config variable stub for the ResponsiveImages setting, for use by phpdoc and IDEs.
$wgDebugRawPage
Config variable stub for the DebugRawPage setting, for use by phpdoc and IDEs.
$wgEnableMagicLinks
Config variable stub for the EnableMagicLinks setting, for use by phpdoc and IDEs.
$wgScriptPath
Config variable stub for the ScriptPath setting, for use by phpdoc and IDEs.
$wgExtensionDirectory
Config variable stub for the ExtensionDirectory setting, for use by phpdoc and IDEs.
$wgLoadScript
Config variable stub for the LoadScript setting, for use by phpdoc and IDEs.
$wgCanonicalServer
Config variable stub for the CanonicalServer setting, for use by phpdoc and IDEs.
$wgServer
Config variable stub for the Server setting, for use by phpdoc and IDEs.
$wgHttpsPort
Config variable stub for the HttpsPort setting, for use by phpdoc and IDEs.
$source