23 if ( !defined(
'MEDIAWIKI' ) ) {
24 die(
"This file is part of MediaWiki, it is not a valid entry point" );
34 use Wikimedia\AtEase\AtEase;
35 use Wikimedia\WrappedString;
50 $path =
"$wgExtensionDirectory/$ext/extension.json";
71 foreach ( $exts as
$ext ) {
72 $registry->queue(
"$wgExtensionDirectory/$ext/extension.json" );
87 $path =
"$wgStyleDirectory/$skin/skin.json";
102 foreach ( $skins as $skin ) {
103 $registry->queue(
"$wgStyleDirectory/$skin/skin.json" );
114 return array_udiff( $a, $b,
'wfArrayDiff2_cmp' );
123 if ( is_string( $a ) && is_string( $b ) ) {
124 return strcmp( $a, $b );
125 } elseif ( count( $a ) !== count( $b ) ) {
126 return count( $a ) <=> count( $b );
130 while ( key( $a ) !==
null && key( $b ) !==
null ) {
131 $valueA = current( $a );
132 $valueB = current( $b );
133 $cmp = strcmp( $valueA, $valueB );
154 if ( is_null( $changed ) ) {
155 throw new MWException(
'GlobalFunctions::wfAppendToArrayIfNotDefault got null' );
157 if ( $default[$key] !== $value ) {
158 $changed[$key] = $value;
183 foreach (
$args as $errors ) {
184 foreach ( $errors as $params ) {
185 $originalParams = $params;
188 $params = array_merge( [ $msg->getKey() ], $msg->getParams() );
190 # @todo FIXME: Sometimes get nested arrays for $params,
191 # which leads to E_NOTICEs
192 $spec = implode(
"\t", $params );
193 $out[$spec] = $originalParams;
196 return array_values( $out );
209 $keys = array_keys( $array );
210 $offsetByKey = array_flip(
$keys );
212 $offset = $offsetByKey[$after];
215 $before = array_slice( $array, 0, $offset + 1,
true );
216 $after = array_slice( $array, $offset + 1, count( $array ) - $offset,
true );
218 $output = $before + $insert + $after;
232 if ( is_object( $objOrArray ) ) {
233 $objOrArray = get_object_vars( $objOrArray );
235 foreach ( $objOrArray as $key => $value ) {
236 if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) {
240 $array[$key] = $value;
259 $max = mt_getrandmax() + 1;
260 $rand = number_format( ( mt_rand() * $max + mt_rand() ) / $max / $max, 12,
'.',
'' );
276 for ( $n = 0; $n < $length; $n += 7 ) {
277 $str .= sprintf(
'%07x', mt_rand() & 0xfffffff );
279 return substr( $str, 0, $length );
312 if ( is_null(
$s ) ) {
318 if ( is_null( $needle ) ) {
319 $needle = [
'%3B',
'%40',
'%24',
'%21',
'%2A',
'%28',
'%29',
'%2C',
'%2F',
'%7E' ];
320 if ( !isset( $_SERVER[
'SERVER_SOFTWARE'] ) ||
321 ( strpos( $_SERVER[
'SERVER_SOFTWARE'],
'Microsoft-IIS/7' ) ===
false )
327 $s = urlencode(
$s );
330 [
';',
'@',
'$',
'!',
'*',
'(',
')',
',',
'/',
'~',
':' ],
348 if ( !is_null( $array2 ) ) {
349 $array1 = $array1 + $array2;
353 foreach ( $array1 as $key => $value ) {
354 if ( !is_null( $value ) && $value !==
false ) {
358 if ( $prefix !==
'' ) {
359 $key = $prefix .
"[$key]";
361 if ( is_array( $value ) ) {
363 foreach ( $value as $k => $v ) {
364 $cgi .= $firstTime ?
'' :
'&';
365 if ( is_array( $v ) ) {
368 $cgi .= urlencode( $key .
"[$k]" ) .
'=' . urlencode( $v );
373 if ( is_object( $value ) ) {
374 $value = $value->__toString();
376 $cgi .= urlencode( $key ) .
'=' . urlencode( $value );
393 if ( isset( $query[0] ) && $query[0] ==
'?' ) {
394 $query = substr( $query, 1 );
396 $bits = explode(
'&', $query );
398 foreach ( $bits as $bit ) {
402 if ( strpos( $bit,
'=' ) ===
false ) {
407 list( $key, $value ) = explode(
'=', $bit );
409 $key = urldecode( $key );
410 $value = urldecode( $value );
411 if ( strpos( $key,
'[' ) !==
false ) {
412 $keys = array_reverse( explode(
'[', $key ) );
413 $key = array_pop(
$keys );
415 foreach (
$keys as $k ) {
416 $k = substr( $k, 0, -1 );
417 $temp = [ $k => $temp ];
419 if ( isset( $ret[$key] ) ) {
420 $ret[$key] = array_merge( $ret[$key], $temp );
440 if ( is_array( $query ) ) {
443 if ( $query !=
'' ) {
446 $hashPos = strpos( $url,
'#' );
447 if ( $hashPos !==
false ) {
448 $fragment = substr( $url, $hashPos );
449 $url = substr( $url, 0, $hashPos );
453 if ( strpos( $url,
'?' ) ===
false ) {
461 if ( $fragment !==
false ) {
502 $defaultProto =
$wgRequest->getProtocol() .
'://';
508 $serverHasProto = $bits && $bits[
'scheme'] !=
'';
511 if ( $serverHasProto ) {
512 $defaultProto = $bits[
'scheme'] .
'://';
521 $defaultProtoWithoutSlashes = $defaultProto !==
null ? substr( $defaultProto, 0, -2 ) :
'';
523 if ( substr( $url, 0, 2 ) ==
'//' ) {
524 $url = $defaultProtoWithoutSlashes . $url;
525 } elseif ( substr( $url, 0, 1 ) ==
'/' ) {
528 if ( $serverHasProto ) {
529 $url = $serverUrl . $url;
534 if ( isset( $bits[
'port'] ) ) {
535 throw new Exception(
'A protocol-relative $wgServer may not contain a port number' );
537 $url = $defaultProtoWithoutSlashes . $serverUrl .
':' .
$wgHttpsPort . $url;
539 $url = $defaultProtoWithoutSlashes . $serverUrl . $url;
546 if ( $bits && isset( $bits[
'path'] ) ) {
552 } elseif ( substr( $url, 0, 1 ) !=
'/' ) {
553 # URL is a relative path
557 # Expanded URL is not valid.
571 return substr( $url, 0, -1 );
590 if ( isset( $urlParts[
'delimiter'] ) ) {
591 if ( isset( $urlParts[
'scheme'] ) ) {
592 $result .= $urlParts[
'scheme'];
595 $result .= $urlParts[
'delimiter'];
598 if ( isset( $urlParts[
'host'] ) ) {
599 if ( isset( $urlParts[
'user'] ) ) {
600 $result .= $urlParts[
'user'];
601 if ( isset( $urlParts[
'pass'] ) ) {
602 $result .=
':' . $urlParts[
'pass'];
607 $result .= $urlParts[
'host'];
609 if ( isset( $urlParts[
'port'] ) ) {
610 $result .=
':' . $urlParts[
'port'];
614 if ( isset( $urlParts[
'path'] ) ) {
615 $result .= $urlParts[
'path'];
618 if ( isset( $urlParts[
'query'] ) ) {
619 $result .=
'?' . $urlParts[
'query'];
622 if ( isset( $urlParts[
'fragment'] ) ) {
623 $result .=
'#' . $urlParts[
'fragment'];
644 $inputLength = strlen( $urlPath );
646 while ( $inputOffset < $inputLength ) {
647 $prefixLengthOne = substr( $urlPath, $inputOffset, 1 );
648 $prefixLengthTwo = substr( $urlPath, $inputOffset, 2 );
649 $prefixLengthThree = substr( $urlPath, $inputOffset, 3 );
650 $prefixLengthFour = substr( $urlPath, $inputOffset, 4 );
653 if ( $prefixLengthTwo ==
'./' ) {
654 # Step A, remove leading "./"
656 } elseif ( $prefixLengthThree ==
'../' ) {
657 # Step A, remove leading "../"
659 } elseif ( ( $prefixLengthTwo ==
'/.' ) && ( $inputOffset + 2 == $inputLength ) ) {
660 # Step B, replace leading "/.$" with "/"
662 $urlPath[$inputOffset] =
'/';
663 } elseif ( $prefixLengthThree ==
'/./' ) {
664 # Step B, replace leading "/./" with "/"
666 } elseif ( $prefixLengthThree ==
'/..' && ( $inputOffset + 3 == $inputLength ) ) {
667 # Step C, replace leading "/..$" with "/" and
668 # remove last path component in output
670 $urlPath[$inputOffset] =
'/';
672 } elseif ( $prefixLengthFour ==
'/../' ) {
673 # Step C, replace leading "/../" with "/" and
674 # remove last path component in output
677 } elseif ( ( $prefixLengthOne ==
'.' ) && ( $inputOffset + 1 == $inputLength ) ) {
678 # Step D, remove "^.$"
680 } elseif ( ( $prefixLengthTwo ==
'..' ) && ( $inputOffset + 2 == $inputLength ) ) {
681 # Step D, remove "^..$"
684 # Step E, move leading path segment to output
685 if ( $prefixLengthOne ==
'/' ) {
686 $slashPos = strpos( $urlPath,
'/', $inputOffset + 1 );
688 $slashPos = strpos( $urlPath,
'/', $inputOffset );
690 if ( $slashPos ===
false ) {
691 $output .= substr( $urlPath, $inputOffset );
692 $inputOffset = $inputLength;
694 $output .= substr( $urlPath, $inputOffset, $slashPos - $inputOffset );
695 $inputOffset += $slashPos - $inputOffset;
700 $slashPos = strrpos( $output,
'/' );
701 if ( $slashPos ===
false ) {
704 $output = substr( $output, 0, $slashPos );
723 static $withProtRel =
null, $withoutProtRel =
null;
724 $cachedValue = $includeProtocolRelative ? $withProtRel : $withoutProtRel;
725 if ( !is_null( $cachedValue ) ) {
735 if ( $includeProtocolRelative || $protocol !==
'//' ) {
736 $protocols[] = preg_quote( $protocol,
'/' );
740 $retval = implode(
'|', $protocols );
750 if ( $includeProtocolRelative ) {
751 $withProtRel = $retval;
753 $withoutProtRel = $retval;
799 $wasRelative = substr( $url, 0, 2 ) ==
'//';
800 if ( $wasRelative ) {
803 AtEase::suppressWarnings();
804 $bits = parse_url( $url );
805 AtEase::restoreWarnings();
808 if ( !$bits || !isset( $bits[
'scheme'] ) ) {
813 $bits[
'scheme'] = strtolower( $bits[
'scheme'] );
817 $bits[
'delimiter'] =
'://';
819 $bits[
'delimiter'] =
':';
822 if ( isset( $bits[
'path'] ) ) {
823 $bits[
'host'] = $bits[
'path'];
831 if ( !isset( $bits[
'host'] ) ) {
835 if ( isset( $bits[
'path'] ) ) {
837 if ( substr( $bits[
'path'], 0, 1 ) !==
'/' ) {
838 $bits[
'path'] =
'/' . $bits[
'path'];
846 if ( $wasRelative ) {
847 $bits[
'scheme'] =
'';
848 $bits[
'delimiter'] =
'//';
864 return preg_replace_callback(
865 '/((?:%[89A-F][0-9A-F])+)/i',
881 if ( is_array( $bits ) && isset( $bits[
'host'] ) ) {
882 $host =
'.' . $bits[
'host'];
883 foreach ( (array)$domains as $domain ) {
884 $domain =
'.' . $domain;
885 if ( substr( $host, -strlen( $domain ) ) === $domain ) {
921 $text = trim( $text );
924 $context[
'seconds_elapsed'] = sprintf(
926 microtime(
true ) - $_SERVER[
'REQUEST_TIME_FLOAT']
930 ( memory_get_usage(
true ) / ( 1024 * 1024 ) )
937 $context[
'private'] = ( $dest ===
false || $dest ===
'private' );
939 $logger = LoggerFactory::getInstance(
'wfDebug' );
954 if ( ( isset( $_GET[
'action'] ) && $_GET[
'action'] ==
'raw' )
956 isset( $_SERVER[
'SCRIPT_NAME'] )
957 && substr( $_SERVER[
'SCRIPT_NAME'], -8 ) ==
'load.php'
973 $mem = memory_get_usage();
975 $mem = floor( $mem / 1024 ) .
' KiB';
979 wfDebug(
"Memory usage: $mem\n" );
1008 $logGroup, $text, $dest =
'all', array
$context = []
1010 $text = trim( $text );
1012 $logger = LoggerFactory::getInstance( $logGroup );
1013 $context[
'private'] = ( $dest ===
false || $dest ===
'private' );
1026 $logger = LoggerFactory::getInstance(
'wfLogDBError' );
1027 $logger->error( trim( $text ),
$context );
1044 function wfDeprecated( $function, $version =
false, $component =
false, $callerOffset = 2 ) {
1045 if ( is_string( $version ) || is_bool( $version ) ) {
1048 throw new Exception(
1049 "MediaWiki version must either be a string or a boolean. " .
1050 "Example valid version: '1.33'"
1065 function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
1078 function wfLogWarning( $msg, $callerOffset = 1, $level = E_USER_WARNING ) {
1094 $profiler->logData();
1098 MediaWikiServices::getInstance()->getStatsdDataFactory(),
1117 $ctx = [
'elapsed' => $request->getElapsedTime() ];
1118 if ( !empty( $_SERVER[
'HTTP_X_FORWARDED_FOR'] ) ) {
1119 $ctx[
'forwarded_for'] = $_SERVER[
'HTTP_X_FORWARDED_FOR'];
1121 if ( !empty( $_SERVER[
'HTTP_CLIENT_IP'] ) ) {
1122 $ctx[
'client_ip'] = $_SERVER[
'HTTP_CLIENT_IP'];
1124 if ( !empty( $_SERVER[
'HTTP_FROM'] ) ) {
1125 $ctx[
'from'] = $_SERVER[
'HTTP_FROM'];
1127 if ( isset( $ctx[
'forwarded_for'] ) ||
1128 isset( $ctx[
'client_ip'] ) ||
1129 isset( $ctx[
'from'] ) ) {
1130 $ctx[
'proxy'] = $_SERVER[
'REMOTE_ADDR'];
1137 $ctx[
'anon'] = $user->isItemLoaded(
'id' ) && $user->isAnon();
1142 $ctx[
'url'] = urldecode( $request->getRequestURL() );
1143 }
catch ( Exception $ignored ) {
1147 $ctx[
'output'] = $profiler->getOutput();
1149 $log = LoggerFactory::getInstance(
'profileoutput' );
1150 $log->info(
"Elapsed: {elapsed}; URL: <{url}>\n{output}", $ctx );
1161 $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
1162 $stats->updateCount( $key, $count );
1171 return MediaWikiServices::getInstance()->getReadOnlyMode()
1184 return MediaWikiServices::getInstance()->getReadOnlyMode()
1195 return MediaWikiServices::getInstance()->getConfiguredReadOnlyMode()
1215 # Identify which language to get or create a language object for.
1216 # Using is_object here due to Stub objects.
1217 if ( is_object( $langcode ) ) {
1218 # Great, we already have the object (hopefully)!
1224 # $langcode is the language code of the wikis content language object.
1225 # or it is a boolean and value is true
1226 return MediaWikiServices::getInstance()->getContentLanguage();
1230 if ( $langcode ===
false || $langcode ===
$wgLang->getCode() ) {
1231 # $langcode is the language code of user language object.
1232 # or it was a boolean and value is false
1237 if ( in_array( $langcode, $validCodes ) ) {
1238 # $langcode corresponds to a valid language.
1242 # $langcode is a string, but not a valid language code; use content language.
1243 wfDebug(
"Invalid language code passed to wfGetLangObj, falling back to content language.\n" );
1244 return MediaWikiServices::getInstance()->getContentLanguage();
1264 $message =
new Message( $key );
1268 $message->params( ...$params );
1299 # Fix windows line-endings
1300 # Some messages are split with explode("\n", $msg)
1301 $message = str_replace(
"\r",
'', $message );
1305 if ( is_array(
$args[0] ) ) {
1308 $replacementKeys = [];
1309 foreach (
$args as $n => $param ) {
1310 $replacementKeys[
'$' . ( $n + 1 )] = $param;
1312 $message = strtr( $message, $replacementKeys );
1333 return php_uname(
'n' ) ?:
'unknown';
1349 $elapsed = ( microtime(
true ) - $_SERVER[
'REQUEST_TIME_FLOAT'] );
1351 $responseTime = round( $elapsed * 1000 );
1352 $reportVars = [
'wgBackendResponseTime' => $responseTime ];
1370 static $disabled =
null;
1372 if ( is_null( $disabled ) ) {
1373 $disabled = !function_exists(
'debug_backtrace' );
1375 wfDebug(
"debug_backtrace() is disabled\n" );
1383 return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit + 1 ), 1 );
1385 return array_slice( debug_backtrace(), 1 );
1400 if ( $raw ===
null ) {
1405 $frameFormat =
"%s line %s calls %s()\n";
1406 $traceFormat =
"%s";
1408 $frameFormat =
"<li>%s line %s calls %s()</li>\n";
1409 $traceFormat =
"<ul>\n%s</ul>\n";
1412 $frames = array_map(
function ( $frame ) use ( $frameFormat ) {
1413 $file = !empty( $frame[
'file'] ) ? basename( $frame[
'file'] ) :
'-';
1414 $line = $frame[
'line'] ??
'-';
1415 $call = $frame[
'function'];
1416 if ( !empty( $frame[
'class'] ) ) {
1417 $call = $frame[
'class'] . $frame[
'type'] . $call;
1419 return sprintf( $frameFormat,
$file,
$line, $call );
1422 return sprintf( $traceFormat, implode(
'', $frames ) );
1436 if ( isset( $backtrace[$level] ) ) {
1452 if ( !$limit || $limit > count( $trace ) - 1 ) {
1453 $limit = count( $trace ) - 1;
1455 $trace = array_slice( $trace, -$limit - 1, $limit );
1456 return implode(
'/', array_map(
'wfFormatStackFrame', $trace ) );
1466 if ( !isset( $frame[
'function'] ) ) {
1467 return 'NO_FUNCTION_GIVEN';
1469 return isset( $frame[
'class'] ) && isset( $frame[
'type'] ) ?
1470 $frame[
'class'] . $frame[
'type'] . $frame[
'function'] :
1484 return wfMessage(
'showingresults' )->numParams( $limit, $offset + 1 )->parse();
1497 static $result =
null;
1498 if ( $result ===
null || $force ) {
1500 if ( isset( $_SERVER[
'HTTP_ACCEPT_ENCODING'] ) ) {
1501 # @todo FIXME: We may want to blacklist some broken browsers
1504 '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/',
1505 $_SERVER[
'HTTP_ACCEPT_ENCODING'],
1509 if ( isset( $m[2] ) && ( $m[1] ==
'q' ) && ( $m[2] == 0 ) ) {
1513 wfDebug(
"wfClientAcceptsGzip: client accepts gzip.\n" );
1533 static $repl =
null, $repl2 =
null;
1534 if ( $repl ===
null || defined(
'MW_PARSER_TEST' ) || defined(
'MW_PHPUNIT_TEST' ) ) {
1538 '"' =>
'"',
'&' =>
'&',
"'" =>
''',
'<' =>
'<',
1539 '=' =>
'=',
'>' =>
'>',
'[' =>
'[',
']' =>
']',
1540 '{' =>
'{',
'|' =>
'|',
'}' =>
'}',
';' =>
';',
1541 "\n#" =>
"\n#",
"\r#" =>
"\r#",
1542 "\n*" =>
"\n*",
"\r*" =>
"\r*",
1543 "\n:" =>
"\n:",
"\r:" =>
"\r:",
1544 "\n " =>
"\n ",
"\r " =>
"\r ",
1545 "\n\n" =>
"\n ",
"\r\n" =>
" \n",
1546 "\n\r" =>
"\n ",
"\r\r" =>
"\r ",
1547 "\n\t" =>
"\n	",
"\r\t" =>
"\r	",
1548 "\n----" =>
"\n----",
"\r----" =>
"\r----",
1549 '__' =>
'__',
'://' =>
'://',
1554 foreach ( $magicLinks as $magic ) {
1555 $repl[
"$magic "] =
"$magic ";
1556 $repl[
"$magic\t"] =
"$magic	";
1557 $repl[
"$magic\r"] =
"$magic ";
1558 $repl[
"$magic\n"] =
"$magic ";
1559 $repl[
"$magic\f"] =
"$magic";
1566 if ( substr( $prot, -1 ) ===
':' ) {
1567 $repl2[] = preg_quote( substr( $prot, 0, -1 ),
'/' );
1570 $repl2 = $repl2 ?
'/\b(' . implode(
'|', $repl2 ) .
'):/i' :
'/^(?!)/';
1572 $text = substr( strtr(
"\n$text", $repl ), 1 );
1573 $text = preg_replace( $repl2,
'$1:', $text );
1589 if ( !is_null(
$source ) || $force ) {
1605 $temp = (bool)( $dest & $bit );
1606 if ( !is_null( $state ) ) {
1624 $s = str_replace(
"\n",
"<br />\n", var_export( $var,
true ) .
"\n" );
1625 if ( headers_sent() || !isset(
$wgOut ) || !is_object(
$wgOut ) ) {
1644 $wgOut->sendCacheControl();
1648 header(
'Content-type: text/html; charset=utf-8' );
1649 print '<!DOCTYPE html>' .
1650 '<html><head><title>' .
1651 htmlspecialchars( $label ) .
1652 '</title></head><body><h1>' .
1653 htmlspecialchars( $label ) .
1655 nl2br( htmlspecialchars( $desc ) ) .
1656 "</p></body></html>\n";
1677 if ( $resetGzipEncoding ) {
1683 while ( $status = ob_get_status() ) {
1684 if ( isset( $status[
'flags'] ) ) {
1685 $flags = PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_REMOVABLE;
1686 $deleteable = ( $status[
'flags'] & $flags ) === $flags;
1687 } elseif ( isset( $status[
'del'] ) ) {
1688 $deleteable = $status[
'del'];
1691 $deleteable = $status[
'type'] !== 0;
1693 if ( !$deleteable ) {
1698 if ( $status[
'name'] ===
'MediaWikiTestCase::wfResetOutputBuffersBarrier' ) {
1702 if ( !ob_end_clean() ) {
1707 if ( $resetGzipEncoding && $status[
'name'] ==
'ob_gzhandler' ) {
1710 header_remove(
'Content-Encoding' );
1741 # No arg means accept anything (per HTTP spec)
1743 return [ $def => 1.0 ];
1748 $parts = explode(
',', $accept );
1750 foreach ( $parts as $part ) {
1751 # @todo FIXME: Doesn't deal with params like 'text/html; level=1'
1752 $values = explode(
';', trim( $part ) );
1754 if ( count( $values ) == 1 ) {
1755 $prefs[$values[0]] = 1.0;
1756 } elseif ( preg_match(
'/q\s*=\s*(\d*\.\d+)/', $values[1], $match ) ) {
1757 $prefs[$values[0]] = floatval( $match[1] );
1777 if ( array_key_exists(
$type, $avail ) ) {
1780 $mainType = explode(
'/',
$type )[0];
1781 if ( array_key_exists(
"$mainType/*", $avail ) ) {
1782 return "$mainType/*";
1783 } elseif ( array_key_exists(
'*/*', $avail ) ) {
1808 foreach ( array_keys( $sprefs ) as
$type ) {
1809 $subType = explode(
'/',
$type )[1];
1810 if ( $subType !=
'*' ) {
1813 $combine[
$type] = $sprefs[
$type] * $cprefs[$ckey];
1818 foreach ( array_keys( $cprefs ) as
$type ) {
1819 $subType = explode(
'/',
$type )[1];
1820 if ( $subType !=
'*' && !array_key_exists(
$type, $sprefs ) ) {
1823 $combine[
$type] = $sprefs[$skey] * $cprefs[
$type];
1831 foreach ( array_keys( $combine ) as
$type ) {
1832 if ( $combine[
$type] > $bestq ) {
1834 $bestq = $combine[
$type];
1850 $ret = MWTimestamp::convert( $outputtype, $ts );
1851 if ( $ret ===
false ) {
1852 wfDebug(
"wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n" );
1866 if ( is_null( $ts ) ) {
1879 return MWTimestamp::now( TS_MW );
1888 static $isWindows =
null;
1889 if ( $isWindows ===
null ) {
1890 $isWindows = strtoupper( substr( PHP_OS, 0, 3 ) ) ===
'WIN';
1913 return PHP_SAPI ===
'cli' || PHP_SAPI ===
'phpdbg';
1950 throw new MWException( __FUNCTION__ .
" given storage path '$dir'." );
1953 if ( !is_null( $caller ) ) {
1954 wfDebug(
"$caller: called wfMkdirParents($dir)\n" );
1957 if ( strval( $dir ) ===
'' || is_dir( $dir ) ) {
1961 $dir = str_replace( [
'\\',
'/' ], DIRECTORY_SEPARATOR, $dir );
1963 if ( is_null( $mode ) ) {
1968 AtEase::suppressWarnings();
1969 $ok = mkdir( $dir, $mode,
true );
1970 AtEase::restoreWarnings();
1974 if ( is_dir( $dir ) ) {
1979 wfLogWarning( sprintf(
"failed to mkdir \"%s\" mode 0%o", $dir, $mode ) );
1990 wfDebug( __FUNCTION__ .
"( $dir )\n" );
1992 if ( is_dir( $dir ) ) {
1993 $objects = scandir( $dir );
1994 foreach ( $objects as $object ) {
1995 if ( $object !=
"." && $object !=
".." ) {
1996 if ( filetype( $dir .
'/' . $object ) ==
"dir" ) {
1999 unlink( $dir .
'/' . $object );
2015 $ret = sprintf(
"%.${acc}f", $nr );
2016 return $round ? round( (
float)$ret, $acc ) .
'%' :
"$ret%";
2059 $val = strtolower( $val );
2064 || preg_match(
"/^\s*[+-]?0*[1-9]/", $val );
2080 return Shell::escape( ...
$args );
2108 $limits = [], $options = []
2110 if ( Shell::isDisabled() ) {
2113 return 'Unable to run external programs, proc_open() is disabled.';
2116 if ( is_array( $cmd ) ) {
2117 $cmd = Shell::escape( $cmd );
2120 $includeStderr = isset( $options[
'duplicateStderr'] ) && $options[
'duplicateStderr'];
2121 $profileMethod = $options[
'profileMethod'] ??
wfGetCaller();
2124 $result = Shell::command( [] )
2125 ->unsafeParams( (array)$cmd )
2126 ->environment( $environ )
2128 ->includeStderr( $includeStderr )
2129 ->profileMethod( $profileMethod )
2131 ->restrict( Shell::RESTRICT_NONE )
2138 $retval = $result->getExitCode();
2140 return $result->getStdout();
2161 return wfShellExec( $cmd, $retval, $environ, $limits,
2162 [
'duplicateStderr' =>
true,
'profileMethod' =>
wfGetCaller() ] );
2184 Hooks::run(
'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
2185 $cmd = [ $options[
'php'] ??
$wgPhpCli ];
2186 if ( isset( $options[
'wrapper'] ) ) {
2187 $cmd[] = $options[
'wrapper'];
2191 return Shell::escape( array_merge( $cmd, $parameters ) );
2205 function wfMerge( $old, $mine, $yours, &$result, &$mergeAttemptResult =
null ) {
2208 # This check may also protect against code injection in
2209 # case of broken installations.
2210 AtEase::suppressWarnings();
2212 AtEase::restoreWarnings();
2214 if ( !$haveDiff3 ) {
2215 wfDebug(
"diff3 not found\n" );
2219 # Make temporary files
2221 $oldtextFile = fopen( $oldtextName = tempnam( $td,
'merge-old-' ),
'w' );
2222 $mytextFile = fopen( $mytextName = tempnam( $td,
'merge-mine-' ),
'w' );
2223 $yourtextFile = fopen( $yourtextName = tempnam( $td,
'merge-your-' ),
'w' );
2225 # NOTE: diff3 issues a warning to stderr if any of the files does not end with
2226 # a newline character. To avoid this, we normalize the trailing whitespace before
2227 # creating the diff.
2229 fwrite( $oldtextFile, rtrim( $old ) .
"\n" );
2230 fclose( $oldtextFile );
2231 fwrite( $mytextFile, rtrim( $mine ) .
"\n" );
2232 fclose( $mytextFile );
2233 fwrite( $yourtextFile, rtrim( $yours ) .
"\n" );
2234 fclose( $yourtextFile );
2236 # Check for a conflict
2237 $cmd = Shell::escape(
$wgDiff3,
'-a',
'--overlap-only', $mytextName,
2238 $oldtextName, $yourtextName );
2239 $handle = popen( $cmd,
'r' );
2241 $mergeAttemptResult =
'';
2243 $data = fread( $handle, 8192 );
2244 if ( strlen( $data ) == 0 ) {
2247 $mergeAttemptResult .= $data;
2251 $conflict = $mergeAttemptResult !==
'';
2254 $cmd = Shell::escape(
$wgDiff3,
'-a',
'-e',
'--merge', $mytextName,
2255 $oldtextName, $yourtextName );
2256 $handle = popen( $cmd,
'r' );
2259 $data = fread( $handle, 8192 );
2260 if ( strlen( $data ) == 0 ) {
2266 unlink( $mytextName );
2267 unlink( $oldtextName );
2268 unlink( $yourtextName );
2270 if ( $result ===
'' && $old !==
'' && !$conflict ) {
2271 wfDebug(
"Unexpected null result from diff3. Command: $cmd\n" );
2288 function wfDiff( $before, $after, $params =
'-u' ) {
2289 if ( $before == $after ) {
2294 AtEase::suppressWarnings();
2296 AtEase::restoreWarnings();
2298 # This check may also protect against code injection in
2299 # case of broken installations.
2301 wfDebug(
"diff executable not found\n" );
2302 $diffs =
new Diff( explode(
"\n", $before ), explode(
"\n", $after ) );
2304 return $format->format( $diffs );
2307 # Make temporary files
2309 $oldtextFile = fopen( $oldtextName = tempnam( $td,
'merge-old-' ),
'w' );
2310 $newtextFile = fopen( $newtextName = tempnam( $td,
'merge-your-' ),
'w' );
2312 fwrite( $oldtextFile, $before );
2313 fclose( $oldtextFile );
2314 fwrite( $newtextFile, $after );
2315 fclose( $newtextFile );
2318 $cmd =
"$wgDiff " . $params .
' ' . Shell::escape( $oldtextName, $newtextName );
2320 $h = popen( $cmd,
'r' );
2322 unlink( $oldtextName );
2323 unlink( $newtextName );
2324 throw new Exception( __METHOD__ .
'(): popen() failed' );
2330 $data = fread( $h, 8192 );
2331 if ( strlen( $data ) == 0 ) {
2339 unlink( $oldtextName );
2340 unlink( $newtextName );
2343 $diff_lines = explode(
"\n", $diff );
2344 if ( isset( $diff_lines[0] ) && strpos( $diff_lines[0],
'---' ) === 0 ) {
2345 unset( $diff_lines[0] );
2347 if ( isset( $diff_lines[1] ) && strpos( $diff_lines[1],
'+++' ) === 0 ) {
2348 unset( $diff_lines[1] );
2351 $diff = implode(
"\n", $diff_lines );
2369 if ( $suffix ==
'' ) {
2372 $encSuffix =
'(?:' . preg_quote( $suffix,
'#' ) .
')?';
2376 if ( preg_match(
"#([^/\\\\]*?){$encSuffix}[/\\\\]*$#",
$path,
$matches ) ) {
2394 $path = str_replace(
'/', DIRECTORY_SEPARATOR,
$path );
2395 $from = str_replace(
'/', DIRECTORY_SEPARATOR, $from );
2399 $from = rtrim( $from, DIRECTORY_SEPARATOR );
2401 $pieces = explode( DIRECTORY_SEPARATOR, dirname(
$path ) );
2402 $against = explode( DIRECTORY_SEPARATOR, $from );
2404 if ( $pieces[0] !== $against[0] ) {
2411 while ( count( $pieces ) && count( $against )
2412 && $pieces[0] == $against[0] ) {
2413 array_shift( $pieces );
2414 array_shift( $against );
2418 while ( count( $against ) ) {
2419 array_unshift( $pieces,
'..' );
2420 array_shift( $against );
2425 return implode( DIRECTORY_SEPARATOR, $pieces );
2441 session_id( $sessionId );
2444 $session = SessionManager::getGlobalSession();
2445 $session->persist();
2447 if ( session_id() !== $session->getId() ) {
2448 session_id( $session->getId() );
2450 AtEase::quietCall(
'session_start' );
2462 $file =
"$IP/serialized/$name";
2463 if ( file_exists(
$file ) ) {
2494 $keyspace = $prefix ?
"$db-$prefix" : $db;
2524 return "$wgDBname-$wgDBprefix";
2555 function wfGetDB( $db, $groups = [], $wiki =
false ) {
2556 return wfGetLB( $wiki )->getMaintenanceConnectionRef( $db, $groups, $wiki );
2569 if ( $wiki ===
false ) {
2570 return MediaWikiServices::getInstance()->getDBLoadBalancer();
2572 $factory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
2573 return $factory->getMainLB( $wiki );
2585 return MediaWikiServices::getInstance()->getRepoGroup()->findFile(
$title, $options );
2597 return MediaWikiServices::getInstance()->getRepoGroup()->getLocalRepo()->newFile(
$title );
2624 if ( $script ===
'index' ) {
2626 } elseif ( $script ===
'load' ) {
2629 return "{$wgScriptPath}/{$script}.php";
2639 if ( isset( $_SERVER[
'SCRIPT_NAME'] ) ) {
2650 return $_SERVER[
'SCRIPT_NAME'];
2652 return $_SERVER[
'URL'];
2664 return $value ?
'true' :
'false';
2699 $ifWritesSince =
null, $wiki =
false, $cluster =
false, $timeout =
null
2701 $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
2703 if ( $cluster ===
'*' ) {
2706 } elseif ( $wiki ===
false ) {
2707 $domain = $lbFactory->getLocalDomainID();
2713 'domain' => $domain,
2714 'cluster' => $cluster,
2716 'ifWritesSince' => ( $ifWritesSince > 1e9 ) ? $ifWritesSince :
null
2718 if ( $timeout !==
null ) {
2719 $opts[
'timeout'] = $timeout;
2722 return $lbFactory->waitForReplication( $opts );
2736 $name = preg_replace(
2754 if ( $oldLimit != -1 ) {
2756 if ( $newLimit == -1 ) {
2757 wfDebug(
"Removing PHP's memory limit\n" );
2758 Wikimedia\suppressWarnings();
2759 ini_set(
'memory_limit', $newLimit );
2760 Wikimedia\restoreWarnings();
2761 } elseif ( $newLimit > $oldLimit ) {
2762 wfDebug(
"Raising PHP's memory limit to $newLimit bytes\n" );
2763 Wikimedia\suppressWarnings();
2764 ini_set(
'memory_limit', $newLimit );
2765 Wikimedia\restoreWarnings();
2779 $timeLimit = (int)ini_get(
'max_execution_time' );
2785 ignore_user_abort(
true );
2798 $string = trim( $string );
2799 if ( $string ===
'' ) {
2802 $last = $string[strlen( $string ) - 1];
2803 $val = intval( $string );
2867 if ( $length !==
false ) {
2868 $realLen = strlen( $data );
2869 if ( $realLen < $length ) {
2870 throw new MWException(
"Tried to use wfUnpack on a "
2871 .
"string of length $realLen, but needed one "
2872 .
"of at least length $length."
2877 Wikimedia\suppressWarnings();
2878 $result = unpack( $format, $data );
2879 Wikimedia\restoreWarnings();
2881 if ( $result ===
false ) {
2883 throw new MWException(
"unpack could not unpack binary data" );
2905 $services = MediaWikiServices::getInstance();
2906 if ( $blacklist !==
null ) {
2907 wfDeprecated( __METHOD__ .
' with $blacklist parameter',
'1.34' );
2909 function () use ( $blacklist ) {
2912 $services->getLocalServerObjectCache(),
2913 $services->getRepoGroup(),
2914 $services->getTitleParser()
2915 ) )->isBadFile( $name, $contextTitle ?:
null );
2917 return $services->getBadFileLookup()->isBadFile( $name, $contextTitle ?:
null );
2929 Hooks::run(
'CanIPUseHTTPS', [ $ip, &$canDo ] );
2930 return (
bool)$canDo;
2942 $infinityValues = [
'infinite',
'indefinite',
'infinity',
'never' ];
2943 return in_array( $str, $infinityValues );
2963 $multipliers = [ 1 ];
2967 $multipliers[] = 1.5;
2971 $handler =
$file->getHandler();
2972 if ( !$handler || !isset( $params[
'width'] ) ) {
2977 if ( isset( $params[
'page'] ) ) {
2978 $basicParams[
'page'] = $params[
'page'];
2984 foreach ( $multipliers as $multiplier ) {
2985 $thumbLimits = array_merge( $thumbLimits, array_map(
2986 function ( $width ) use ( $multiplier ) {
2987 return round( $width * $multiplier );
2990 $imageLimits = array_merge( $imageLimits, array_map(
2991 function ( $pair ) use ( $multiplier ) {
2993 round( $pair[0] * $multiplier ),
2994 round( $pair[1] * $multiplier ),
3001 if ( in_array( $params[
'width'], $thumbLimits ) ) {
3002 $normalParams = $basicParams + [
'width' => $params[
'width'] ];
3004 $handler->normaliseParams(
$file, $normalParams );
3008 foreach ( $imageLimits as $pair ) {
3009 $normalParams = $basicParams + [
'width' => $pair[0],
'height' => $pair[1] ];
3012 $handler->normaliseParams(
$file, $normalParams );
3014 if ( $normalParams[
'width'] == $params[
'width'] ) {
3025 foreach ( $params as $key => $value ) {
3026 if ( !isset( $normalParams[$key] ) || $normalParams[$key] != $value ) {
3048 foreach ( $baseArray as $name => &$groupVal ) {
3049 if ( isset( $newValues[$name] ) ) {
3050 $groupVal += $newValues[$name];
3054 $baseArray += $newValues;
3068 if ( !function_exists(
'getrusage' ) ) {
3070 } elseif ( defined(
'HHVM_VERSION' ) && PHP_OS ===
'Linux' ) {
3071 return getrusage( 2 );
3073 return getrusage( 0 );