MediaWiki  master
GlobalFunctions.php
Go to the documentation of this file.
1 <?php
23 if ( !defined( 'MEDIAWIKI' ) ) {
24  die( "This file is part of MediaWiki, it is not a valid entry point" );
25 }
26 
34 
45 function wfLoadExtension( $ext, $path = null ) {
46  if ( !$path ) {
47  global $wgExtensionDirectory;
48  $path = "$wgExtensionDirectory/$ext/extension.json";
49  }
51 }
52 
66 function wfLoadExtensions( array $exts ) {
67  global $wgExtensionDirectory;
68  $registry = ExtensionRegistry::getInstance();
69  foreach ( $exts as $ext ) {
70  $registry->queue( "$wgExtensionDirectory/$ext/extension.json" );
71  }
72 }
73 
82 function wfLoadSkin( $skin, $path = null ) {
83  if ( !$path ) {
84  global $wgStyleDirectory;
85  $path = "$wgStyleDirectory/$skin/skin.json";
86  }
88 }
89 
97 function wfLoadSkins( array $skins ) {
98  global $wgStyleDirectory;
99  $registry = ExtensionRegistry::getInstance();
100  foreach ( $skins as $skin ) {
101  $registry->queue( "$wgStyleDirectory/$skin/skin.json" );
102  }
103 }
104 
111 function wfArrayDiff2( $a, $b ) {
112  return array_udiff( $a, $b, 'wfArrayDiff2_cmp' );
113 }
114 
120 function wfArrayDiff2_cmp( $a, $b ) {
121  if ( is_string( $a ) && is_string( $b ) ) {
122  return strcmp( $a, $b );
123  } elseif ( count( $a ) !== count( $b ) ) {
124  return count( $a ) <=> count( $b );
125  } else {
126  reset( $a );
127  reset( $b );
128  while ( key( $a ) !== null && key( $b ) !== null ) {
129  $valueA = current( $a );
130  $valueB = current( $b );
131  $cmp = strcmp( $valueA, $valueB );
132  if ( $cmp !== 0 ) {
133  return $cmp;
134  }
135  next( $a );
136  next( $b );
137  }
138  return 0;
139  }
140 }
141 
150 function wfArrayFilter( array $arr, callable $callback ) {
151  return array_filter( $arr, $callback, ARRAY_FILTER_USE_BOTH );
152 }
153 
162 function wfArrayFilterByKey( array $arr, callable $callback ) {
163  return array_filter( $arr, $callback, ARRAY_FILTER_USE_KEY );
164 }
165 
175 function wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed ) {
176  if ( is_null( $changed ) ) {
177  throw new MWException( 'GlobalFunctions::wfAppendToArrayIfNotDefault got null' );
178  }
179  if ( $default[$key] !== $value ) {
180  $changed[$key] = $value;
181  }
182 }
183 
203 function wfMergeErrorArrays( ...$args ) {
204  $out = [];
205  foreach ( $args as $errors ) {
206  foreach ( $errors as $params ) {
207  $originalParams = $params;
208  if ( $params[0] instanceof MessageSpecifier ) {
209  $msg = $params[0];
210  $params = array_merge( [ $msg->getKey() ], $msg->getParams() );
211  }
212  # @todo FIXME: Sometimes get nested arrays for $params,
213  # which leads to E_NOTICEs
214  $spec = implode( "\t", $params );
215  $out[$spec] = $originalParams;
216  }
217  }
218  return array_values( $out );
219 }
220 
229 function wfArrayInsertAfter( array $array, array $insert, $after ) {
230  // Find the offset of the element to insert after.
231  $keys = array_keys( $array );
232  $offsetByKey = array_flip( $keys );
233 
234  $offset = $offsetByKey[$after];
235 
236  // Insert at the specified offset
237  $before = array_slice( $array, 0, $offset + 1, true );
238  $after = array_slice( $array, $offset + 1, count( $array ) - $offset, true );
239 
240  $output = $before + $insert + $after;
241 
242  return $output;
243 }
244 
252 function wfObjectToArray( $objOrArray, $recursive = true ) {
253  $array = [];
254  if ( is_object( $objOrArray ) ) {
255  $objOrArray = get_object_vars( $objOrArray );
256  }
257  foreach ( $objOrArray as $key => $value ) {
258  if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) {
260  }
261 
262  $array[$key] = $value;
263  }
264 
265  return $array;
266 }
267 
278 function wfRandom() {
279  // The maximum random value is "only" 2^31-1, so get two random
280  // values to reduce the chance of dupes
281  $max = mt_getrandmax() + 1;
282  $rand = number_format( ( mt_rand() * $max + mt_rand() ) / $max / $max, 12, '.', '' );
283  return $rand;
284 }
285 
296 function wfRandomString( $length = 32 ) {
297  $str = '';
298  for ( $n = 0; $n < $length; $n += 7 ) {
299  $str .= sprintf( '%07x', mt_rand() & 0xfffffff );
300  }
301  return substr( $str, 0, $length );
302 }
303 
331 function wfUrlencode( $s ) {
332  static $needle;
333 
334  if ( is_null( $s ) ) {
335  $needle = null;
336  return '';
337  }
338 
339  if ( is_null( $needle ) ) {
340  $needle = [ '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F', '%7E' ];
341  if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) ||
342  ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false )
343  ) {
344  $needle[] = '%3A';
345  }
346  }
347 
348  $s = urlencode( $s );
349  $s = str_ireplace(
350  $needle,
351  [ ';', '@', '$', '!', '*', '(', ')', ',', '/', '~', ':' ],
352  $s
353  );
354 
355  return $s;
356 }
357 
368 function wfArrayToCgi( $array1, $array2 = null, $prefix = '' ) {
369  if ( !is_null( $array2 ) ) {
370  $array1 = $array1 + $array2;
371  }
372 
373  $cgi = '';
374  foreach ( $array1 as $key => $value ) {
375  if ( !is_null( $value ) && $value !== false ) {
376  if ( $cgi != '' ) {
377  $cgi .= '&';
378  }
379  if ( $prefix !== '' ) {
380  $key = $prefix . "[$key]";
381  }
382  if ( is_array( $value ) ) {
383  $firstTime = true;
384  foreach ( $value as $k => $v ) {
385  $cgi .= $firstTime ? '' : '&';
386  if ( is_array( $v ) ) {
387  $cgi .= wfArrayToCgi( $v, null, $key . "[$k]" );
388  } else {
389  $cgi .= urlencode( $key . "[$k]" ) . '=' . urlencode( $v );
390  }
391  $firstTime = false;
392  }
393  } else {
394  if ( is_object( $value ) ) {
395  $value = $value->__toString();
396  }
397  $cgi .= urlencode( $key ) . '=' . urlencode( $value );
398  }
399  }
400  }
401  return $cgi;
402 }
403 
413 function wfCgiToArray( $query ) {
414  if ( isset( $query[0] ) && $query[0] == '?' ) {
415  $query = substr( $query, 1 );
416  }
417  $bits = explode( '&', $query );
418  $ret = [];
419  foreach ( $bits as $bit ) {
420  if ( $bit === '' ) {
421  continue;
422  }
423  if ( strpos( $bit, '=' ) === false ) {
424  // Pieces like &qwerty become 'qwerty' => '' (at least this is what php does)
425  $key = $bit;
426  $value = '';
427  } else {
428  list( $key, $value ) = explode( '=', $bit );
429  }
430  $key = urldecode( $key );
431  $value = urldecode( $value );
432  if ( strpos( $key, '[' ) !== false ) {
433  $keys = array_reverse( explode( '[', $key ) );
434  $key = array_pop( $keys );
435  $temp = $value;
436  foreach ( $keys as $k ) {
437  $k = substr( $k, 0, -1 );
438  $temp = [ $k => $temp ];
439  }
440  if ( isset( $ret[$key] ) ) {
441  $ret[$key] = array_merge( $ret[$key], $temp );
442  } else {
443  $ret[$key] = $temp;
444  }
445  } else {
446  $ret[$key] = $value;
447  }
448  }
449  return $ret;
450 }
451 
460 function wfAppendQuery( $url, $query ) {
461  if ( is_array( $query ) ) {
463  }
464  if ( $query != '' ) {
465  // Remove the fragment, if there is one
466  $fragment = false;
467  $hashPos = strpos( $url, '#' );
468  if ( $hashPos !== false ) {
469  $fragment = substr( $url, $hashPos );
470  $url = substr( $url, 0, $hashPos );
471  }
472 
473  // Add parameter
474  if ( strpos( $url, '?' ) === false ) {
475  $url .= '?';
476  } else {
477  $url .= '&';
478  }
479  $url .= $query;
480 
481  // Put the fragment back
482  if ( $fragment !== false ) {
483  $url .= $fragment;
484  }
485  }
486  return $url;
487 }
488 
512 function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) {
514  $wgHttpsPort;
515  if ( $defaultProto === PROTO_CANONICAL ) {
516  $serverUrl = $wgCanonicalServer;
517  } elseif ( $defaultProto === PROTO_INTERNAL && $wgInternalServer !== false ) {
518  // Make $wgInternalServer fall back to $wgServer if not set
519  $serverUrl = $wgInternalServer;
520  } else {
521  $serverUrl = $wgServer;
522  if ( $defaultProto === PROTO_CURRENT ) {
523  $defaultProto = $wgRequest->getProtocol() . '://';
524  }
525  }
526 
527  // Analyze $serverUrl to obtain its protocol
528  $bits = wfParseUrl( $serverUrl );
529  $serverHasProto = $bits && $bits['scheme'] != '';
530 
531  if ( $defaultProto === PROTO_CANONICAL || $defaultProto === PROTO_INTERNAL ) {
532  if ( $serverHasProto ) {
533  $defaultProto = $bits['scheme'] . '://';
534  } else {
535  // $wgCanonicalServer or $wgInternalServer doesn't have a protocol.
536  // This really isn't supposed to happen. Fall back to HTTP in this
537  // ridiculous case.
538  $defaultProto = PROTO_HTTP;
539  }
540  }
541 
542  $defaultProtoWithoutSlashes = substr( $defaultProto, 0, -2 );
543 
544  if ( substr( $url, 0, 2 ) == '//' ) {
545  $url = $defaultProtoWithoutSlashes . $url;
546  } elseif ( substr( $url, 0, 1 ) == '/' ) {
547  // If $serverUrl is protocol-relative, prepend $defaultProtoWithoutSlashes,
548  // otherwise leave it alone.
549  if ( $serverHasProto ) {
550  $url = $serverUrl . $url;
551  } else {
552  // If an HTTPS URL is synthesized from a protocol-relative $wgServer, allow the
553  // user to override the port number (T67184)
554  if ( $defaultProto === PROTO_HTTPS && $wgHttpsPort != 443 ) {
555  if ( isset( $bits['port'] ) ) {
556  throw new Exception( 'A protocol-relative $wgServer may not contain a port number' );
557  }
558  $url = $defaultProtoWithoutSlashes . $serverUrl . ':' . $wgHttpsPort . $url;
559  } else {
560  $url = $defaultProtoWithoutSlashes . $serverUrl . $url;
561  }
562  }
563  }
564 
565  $bits = wfParseUrl( $url );
566 
567  if ( $bits && isset( $bits['path'] ) ) {
568  $bits['path'] = wfRemoveDotSegments( $bits['path'] );
569  return wfAssembleUrl( $bits );
570  } elseif ( $bits ) {
571  # No path to expand
572  return $url;
573  } elseif ( substr( $url, 0, 1 ) != '/' ) {
574  # URL is a relative path
575  return wfRemoveDotSegments( $url );
576  }
577 
578  # Expanded URL is not valid.
579  return false;
580 }
581 
590 function wfGetServerUrl( $proto ) {
591  $url = wfExpandUrl( '/', $proto );
592  return substr( $url, 0, -1 );
593 }
594 
608 function wfAssembleUrl( $urlParts ) {
609  $result = '';
610 
611  if ( isset( $urlParts['delimiter'] ) ) {
612  if ( isset( $urlParts['scheme'] ) ) {
613  $result .= $urlParts['scheme'];
614  }
615 
616  $result .= $urlParts['delimiter'];
617  }
618 
619  if ( isset( $urlParts['host'] ) ) {
620  if ( isset( $urlParts['user'] ) ) {
621  $result .= $urlParts['user'];
622  if ( isset( $urlParts['pass'] ) ) {
623  $result .= ':' . $urlParts['pass'];
624  }
625  $result .= '@';
626  }
627 
628  $result .= $urlParts['host'];
629 
630  if ( isset( $urlParts['port'] ) ) {
631  $result .= ':' . $urlParts['port'];
632  }
633  }
634 
635  if ( isset( $urlParts['path'] ) ) {
636  $result .= $urlParts['path'];
637  }
638 
639  if ( isset( $urlParts['query'] ) ) {
640  $result .= '?' . $urlParts['query'];
641  }
642 
643  if ( isset( $urlParts['fragment'] ) ) {
644  $result .= '#' . $urlParts['fragment'];
645  }
646 
647  return $result;
648 }
649 
662 function wfRemoveDotSegments( $urlPath ) {
663  $output = '';
664  $inputOffset = 0;
665  $inputLength = strlen( $urlPath );
666 
667  while ( $inputOffset < $inputLength ) {
668  $prefixLengthOne = substr( $urlPath, $inputOffset, 1 );
669  $prefixLengthTwo = substr( $urlPath, $inputOffset, 2 );
670  $prefixLengthThree = substr( $urlPath, $inputOffset, 3 );
671  $prefixLengthFour = substr( $urlPath, $inputOffset, 4 );
672  $trimOutput = false;
673 
674  if ( $prefixLengthTwo == './' ) {
675  # Step A, remove leading "./"
676  $inputOffset += 2;
677  } elseif ( $prefixLengthThree == '../' ) {
678  # Step A, remove leading "../"
679  $inputOffset += 3;
680  } elseif ( ( $prefixLengthTwo == '/.' ) && ( $inputOffset + 2 == $inputLength ) ) {
681  # Step B, replace leading "/.$" with "/"
682  $inputOffset += 1;
683  $urlPath[$inputOffset] = '/';
684  } elseif ( $prefixLengthThree == '/./' ) {
685  # Step B, replace leading "/./" with "/"
686  $inputOffset += 2;
687  } elseif ( $prefixLengthThree == '/..' && ( $inputOffset + 3 == $inputLength ) ) {
688  # Step C, replace leading "/..$" with "/" and
689  # remove last path component in output
690  $inputOffset += 2;
691  $urlPath[$inputOffset] = '/';
692  $trimOutput = true;
693  } elseif ( $prefixLengthFour == '/../' ) {
694  # Step C, replace leading "/../" with "/" and
695  # remove last path component in output
696  $inputOffset += 3;
697  $trimOutput = true;
698  } elseif ( ( $prefixLengthOne == '.' ) && ( $inputOffset + 1 == $inputLength ) ) {
699  # Step D, remove "^.$"
700  $inputOffset += 1;
701  } elseif ( ( $prefixLengthTwo == '..' ) && ( $inputOffset + 2 == $inputLength ) ) {
702  # Step D, remove "^..$"
703  $inputOffset += 2;
704  } else {
705  # Step E, move leading path segment to output
706  if ( $prefixLengthOne == '/' ) {
707  $slashPos = strpos( $urlPath, '/', $inputOffset + 1 );
708  } else {
709  $slashPos = strpos( $urlPath, '/', $inputOffset );
710  }
711  if ( $slashPos === false ) {
712  $output .= substr( $urlPath, $inputOffset );
713  $inputOffset = $inputLength;
714  } else {
715  $output .= substr( $urlPath, $inputOffset, $slashPos - $inputOffset );
716  $inputOffset += $slashPos - $inputOffset;
717  }
718  }
719 
720  if ( $trimOutput ) {
721  $slashPos = strrpos( $output, '/' );
722  if ( $slashPos === false ) {
723  $output = '';
724  } else {
725  $output = substr( $output, 0, $slashPos );
726  }
727  }
728  }
729 
730  return $output;
731 }
732 
740 function wfUrlProtocols( $includeProtocolRelative = true ) {
741  global $wgUrlProtocols;
742 
743  // Cache return values separately based on $includeProtocolRelative
744  static $withProtRel = null, $withoutProtRel = null;
745  $cachedValue = $includeProtocolRelative ? $withProtRel : $withoutProtRel;
746  if ( !is_null( $cachedValue ) ) {
747  return $cachedValue;
748  }
749 
750  // Support old-style $wgUrlProtocols strings, for backwards compatibility
751  // with LocalSettings files from 1.5
752  if ( is_array( $wgUrlProtocols ) ) {
753  $protocols = [];
754  foreach ( $wgUrlProtocols as $protocol ) {
755  // Filter out '//' if !$includeProtocolRelative
756  if ( $includeProtocolRelative || $protocol !== '//' ) {
757  $protocols[] = preg_quote( $protocol, '/' );
758  }
759  }
760 
761  $retval = implode( '|', $protocols );
762  } else {
763  // Ignore $includeProtocolRelative in this case
764  // This case exists for pre-1.6 compatibility, and we can safely assume
765  // that '//' won't appear in a pre-1.6 config because protocol-relative
766  // URLs weren't supported until 1.18
767  $retval = $wgUrlProtocols;
768  }
769 
770  // Cache return value
771  if ( $includeProtocolRelative ) {
772  $withProtRel = $retval;
773  } else {
774  $withoutProtRel = $retval;
775  }
776  return $retval;
777 }
778 
786  return wfUrlProtocols( false );
787 }
788 
814 function wfParseUrl( $url ) {
815  global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
816 
817  // Protocol-relative URLs are handled really badly by parse_url(). It's so
818  // bad that the easiest way to handle them is to just prepend 'http:' and
819  // strip the protocol out later.
820  $wasRelative = substr( $url, 0, 2 ) == '//';
821  if ( $wasRelative ) {
822  $url = "http:$url";
823  }
824  Wikimedia\suppressWarnings();
825  $bits = parse_url( $url );
826  Wikimedia\restoreWarnings();
827  // parse_url() returns an array without scheme for some invalid URLs, e.g.
828  // parse_url("%0Ahttp://example.com") == [ 'host' => '%0Ahttp', 'path' => 'example.com' ]
829  if ( !$bits || !isset( $bits['scheme'] ) ) {
830  return false;
831  }
832 
833  // parse_url() incorrectly handles schemes case-sensitively. Convert it to lowercase.
834  $bits['scheme'] = strtolower( $bits['scheme'] );
835 
836  // most of the protocols are followed by ://, but mailto: and sometimes news: not, check for it
837  if ( in_array( $bits['scheme'] . '://', $wgUrlProtocols ) ) {
838  $bits['delimiter'] = '://';
839  } elseif ( in_array( $bits['scheme'] . ':', $wgUrlProtocols ) ) {
840  $bits['delimiter'] = ':';
841  // parse_url detects for news: and mailto: the host part of an url as path
842  // We have to correct this wrong detection
843  if ( isset( $bits['path'] ) ) {
844  $bits['host'] = $bits['path'];
845  $bits['path'] = '';
846  }
847  } else {
848  return false;
849  }
850 
851  /* Provide an empty host for eg. file:/// urls (see T30627) */
852  if ( !isset( $bits['host'] ) ) {
853  $bits['host'] = '';
854 
855  // See T47069
856  if ( isset( $bits['path'] ) ) {
857  /* parse_url loses the third / for file:///c:/ urls (but not on variants) */
858  if ( substr( $bits['path'], 0, 1 ) !== '/' ) {
859  $bits['path'] = '/' . $bits['path'];
860  }
861  } else {
862  $bits['path'] = '';
863  }
864  }
865 
866  // If the URL was protocol-relative, fix scheme and delimiter
867  if ( $wasRelative ) {
868  $bits['scheme'] = '';
869  $bits['delimiter'] = '//';
870  }
871  return $bits;
872 }
873 
884 function wfExpandIRI( $url ) {
885  return preg_replace_callback(
886  '/((?:%[89A-F][0-9A-F])+)/i',
887  function ( array $matches ) {
888  return urldecode( $matches[1] );
889  },
890  wfExpandUrl( $url )
891  );
892 }
893 
901 function wfMakeUrlIndexes( $url ) {
902  wfDeprecated( __FUNCTION__, '1.33' );
903  return LinkFilter::makeIndexes( $url );
904 }
905 
912 function wfMatchesDomainList( $url, $domains ) {
913  $bits = wfParseUrl( $url );
914  if ( is_array( $bits ) && isset( $bits['host'] ) ) {
915  $host = '.' . $bits['host'];
916  foreach ( (array)$domains as $domain ) {
917  $domain = '.' . $domain;
918  if ( substr( $host, -strlen( $domain ) ) === $domain ) {
919  return true;
920  }
921  }
922  }
923  return false;
924 }
925 
946 function wfDebug( $text, $dest = 'all', array $context = [] ) {
948  global $wgDebugTimestamps;
949 
950  if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
951  return;
952  }
953 
954  $text = trim( $text );
955 
956  if ( $wgDebugTimestamps ) {
957  $context['seconds_elapsed'] = sprintf(
958  '%6.4f',
959  microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT']
960  );
961  $context['memory_used'] = sprintf(
962  '%5.1fM',
963  ( memory_get_usage( true ) / ( 1024 * 1024 ) )
964  );
965  }
966 
967  if ( $wgDebugLogPrefix !== '' ) {
968  $context['prefix'] = $wgDebugLogPrefix;
969  }
970  $context['private'] = ( $dest === false || $dest === 'private' );
971 
972  $logger = LoggerFactory::getInstance( 'wfDebug' );
973  $logger->debug( $text, $context );
974 }
975 
980 function wfIsDebugRawPage() {
981  static $cache;
982  if ( $cache !== null ) {
983  return $cache;
984  }
985  // Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet
986  // phpcs:ignore MediaWiki.Usage.SuperGlobalsUsage.SuperGlobals
987  if ( ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' )
988  || (
989  isset( $_SERVER['SCRIPT_NAME'] )
990  && substr( $_SERVER['SCRIPT_NAME'], -8 ) == 'load.php'
991  )
992  ) {
993  $cache = true;
994  } else {
995  $cache = false;
996  }
997  return $cache;
998 }
999 
1005 function wfDebugMem( $exact = false ) {
1006  $mem = memory_get_usage();
1007  if ( !$exact ) {
1008  $mem = floor( $mem / 1024 ) . ' KiB';
1009  } else {
1010  $mem .= ' B';
1011  }
1012  wfDebug( "Memory usage: $mem\n" );
1013 }
1014 
1040 function wfDebugLog(
1041  $logGroup, $text, $dest = 'all', array $context = []
1042 ) {
1043  $text = trim( $text );
1044 
1045  $logger = LoggerFactory::getInstance( $logGroup );
1046  $context['private'] = ( $dest === false || $dest === 'private' );
1047  $logger->info( $text, $context );
1048 }
1049 
1058 function wfLogDBError( $text, array $context = [] ) {
1059  $logger = LoggerFactory::getInstance( 'wfLogDBError' );
1060  $logger->error( trim( $text ), $context );
1061 }
1062 
1076 function wfDeprecated( $function, $version = false, $component = false, $callerOffset = 2 ) {
1077  MWDebug::deprecated( $function, $version, $component, $callerOffset + 1 );
1078 }
1079 
1090 function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
1091  MWDebug::warning( $msg, $callerOffset + 1, $level, 'auto' );
1092 }
1093 
1103 function wfLogWarning( $msg, $callerOffset = 1, $level = E_USER_WARNING ) {
1104  MWDebug::warning( $msg, $callerOffset + 1, $level, 'production' );
1105 }
1106 
1113 
1115  $request = $context->getRequest();
1116 
1117  $profiler = Profiler::instance();
1118  $profiler->setContext( $context );
1119  $profiler->logData();
1120 
1121  // Send out any buffered statsd metrics as needed
1123  MediaWikiServices::getInstance()->getStatsdDataFactory(),
1124  $context->getConfig()
1125  );
1126 
1127  // Profiling must actually be enabled...
1128  if ( $profiler instanceof ProfilerStub ) {
1129  return;
1130  }
1131 
1132  if ( isset( $wgDebugLogGroups['profileoutput'] )
1133  && $wgDebugLogGroups['profileoutput'] === false
1134  ) {
1135  // Explicitly disabled
1136  return;
1137  }
1138  if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
1139  return;
1140  }
1141 
1142  $ctx = [ 'elapsed' => $request->getElapsedTime() ];
1143  if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
1144  $ctx['forwarded_for'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
1145  }
1146  if ( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
1147  $ctx['client_ip'] = $_SERVER['HTTP_CLIENT_IP'];
1148  }
1149  if ( !empty( $_SERVER['HTTP_FROM'] ) ) {
1150  $ctx['from'] = $_SERVER['HTTP_FROM'];
1151  }
1152  if ( isset( $ctx['forwarded_for'] ) ||
1153  isset( $ctx['client_ip'] ) ||
1154  isset( $ctx['from'] ) ) {
1155  $ctx['proxy'] = $_SERVER['REMOTE_ADDR'];
1156  }
1157 
1158  // Don't load $wgUser at this late stage just for statistics purposes
1159  // @todo FIXME: We can detect some anons even if it is not loaded.
1160  // See User::getId()
1161  $user = $context->getUser();
1162  $ctx['anon'] = $user->isItemLoaded( 'id' ) && $user->isAnon();
1163 
1164  // Command line script uses a FauxRequest object which does not have
1165  // any knowledge about an URL and throw an exception instead.
1166  try {
1167  $ctx['url'] = urldecode( $request->getRequestURL() );
1168  } catch ( Exception $ignored ) {
1169  // no-op
1170  }
1171 
1172  $ctx['output'] = $profiler->getOutput();
1173 
1174  $log = LoggerFactory::getInstance( 'profileoutput' );
1175  $log->info( "Elapsed: {elapsed}; URL: <{url}>\n{output}", $ctx );
1176 }
1177 
1185 function wfIncrStats( $key, $count = 1 ) {
1186  $stats = MediaWikiServices::getInstance()->getStatsdDataFactory();
1187  $stats->updateCount( $key, $count );
1188 }
1189 
1195 function wfReadOnly() {
1196  return MediaWikiServices::getInstance()->getReadOnlyMode()
1197  ->isReadOnly();
1198 }
1199 
1208 function wfReadOnlyReason() {
1209  return MediaWikiServices::getInstance()->getReadOnlyMode()
1210  ->getReason();
1211 }
1212 
1220  return MediaWikiServices::getInstance()->getConfiguredReadOnlyMode()
1221  ->getReason();
1222 }
1223 
1239 function wfGetLangObj( $langcode = false ) {
1240  # Identify which language to get or create a language object for.
1241  # Using is_object here due to Stub objects.
1242  if ( is_object( $langcode ) ) {
1243  # Great, we already have the object (hopefully)!
1244  return $langcode;
1245  }
1246 
1247  global $wgLanguageCode;
1248  if ( $langcode === true || $langcode === $wgLanguageCode ) {
1249  # $langcode is the language code of the wikis content language object.
1250  # or it is a boolean and value is true
1251  return MediaWikiServices::getInstance()->getContentLanguage();
1252  }
1253 
1254  global $wgLang;
1255  if ( $langcode === false || $langcode === $wgLang->getCode() ) {
1256  # $langcode is the language code of user language object.
1257  # or it was a boolean and value is false
1258  return $wgLang;
1259  }
1260 
1261  $validCodes = array_keys( Language::fetchLanguageNames() );
1262  if ( in_array( $langcode, $validCodes ) ) {
1263  # $langcode corresponds to a valid language.
1264  return Language::factory( $langcode );
1265  }
1266 
1267  # $langcode is a string, but not a valid language code; use content language.
1268  wfDebug( "Invalid language code passed to wfGetLangObj, falling back to content language.\n" );
1269  return MediaWikiServices::getInstance()->getContentLanguage();
1270 }
1271 
1288 function wfMessage( $key, ...$params ) {
1289  $message = new Message( $key );
1290 
1291  // We call Message::params() to reduce code duplication
1292  if ( $params ) {
1293  $message->params( ...$params );
1294  }
1295 
1296  return $message;
1297 }
1298 
1311 function wfMessageFallback( ...$keys ) {
1312  return Message::newFallbackSequence( ...$keys );
1313 }
1314 
1323 function wfMsgReplaceArgs( $message, $args ) {
1324  # Fix windows line-endings
1325  # Some messages are split with explode("\n", $msg)
1326  $message = str_replace( "\r", '', $message );
1327 
1328  // Replace arguments
1329  if ( is_array( $args ) && $args ) {
1330  if ( is_array( $args[0] ) ) {
1331  $args = array_values( $args[0] );
1332  }
1333  $replacementKeys = [];
1334  foreach ( $args as $n => $param ) {
1335  $replacementKeys['$' . ( $n + 1 )] = $param;
1336  }
1337  $message = strtr( $message, $replacementKeys );
1338  }
1339 
1340  return $message;
1341 }
1342 
1350 function wfHostname() {
1351  static $host;
1352  if ( is_null( $host ) ) {
1353  # Hostname overriding
1354  global $wgOverrideHostname;
1355  if ( $wgOverrideHostname !== false ) {
1356  # Set static and skip any detection
1357  $host = $wgOverrideHostname;
1358  return $host;
1359  }
1360 
1361  if ( function_exists( 'posix_uname' ) ) {
1362  // This function not present on Windows
1363  $uname = posix_uname();
1364  } else {
1365  $uname = false;
1366  }
1367  if ( is_array( $uname ) && isset( $uname['nodename'] ) ) {
1368  $host = $uname['nodename'];
1369  } elseif ( getenv( 'COMPUTERNAME' ) ) {
1370  # Windows computer name
1371  $host = getenv( 'COMPUTERNAME' );
1372  } else {
1373  # This may be a virtual server.
1374  $host = $_SERVER['SERVER_NAME'];
1375  }
1376  }
1377  return $host;
1378 }
1379 
1390 function wfReportTime( $nonce = null ) {
1391  global $wgShowHostnames;
1392 
1393  $elapsed = ( microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'] );
1394  // seconds to milliseconds
1395  $responseTime = round( $elapsed * 1000 );
1396  $reportVars = [ 'wgBackendResponseTime' => $responseTime ];
1397  if ( $wgShowHostnames ) {
1398  $reportVars['wgHostname'] = wfHostname();
1399  }
1400  return Skin::makeVariablesScript( $reportVars, $nonce );
1401 }
1402 
1413 function wfDebugBacktrace( $limit = 0 ) {
1414  static $disabled = null;
1415 
1416  if ( is_null( $disabled ) ) {
1417  $disabled = !function_exists( 'debug_backtrace' );
1418  if ( $disabled ) {
1419  wfDebug( "debug_backtrace() is disabled\n" );
1420  }
1421  }
1422  if ( $disabled ) {
1423  return [];
1424  }
1425 
1426  if ( $limit ) {
1427  return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit + 1 ), 1 );
1428  } else {
1429  return array_slice( debug_backtrace(), 1 );
1430  }
1431 }
1432 
1441 function wfBacktrace( $raw = null ) {
1442  global $wgCommandLineMode;
1443 
1444  if ( $raw === null ) {
1445  $raw = $wgCommandLineMode;
1446  }
1447 
1448  if ( $raw ) {
1449  $frameFormat = "%s line %s calls %s()\n";
1450  $traceFormat = "%s";
1451  } else {
1452  $frameFormat = "<li>%s line %s calls %s()</li>\n";
1453  $traceFormat = "<ul>\n%s</ul>\n";
1454  }
1455 
1456  $frames = array_map( function ( $frame ) use ( $frameFormat ) {
1457  $file = !empty( $frame['file'] ) ? basename( $frame['file'] ) : '-';
1458  $line = $frame['line'] ?? '-';
1459  $call = $frame['function'];
1460  if ( !empty( $frame['class'] ) ) {
1461  $call = $frame['class'] . $frame['type'] . $call;
1462  }
1463  return sprintf( $frameFormat, $file, $line, $call );
1464  }, wfDebugBacktrace() );
1465 
1466  return sprintf( $traceFormat, implode( '', $frames ) );
1467 }
1468 
1478 function wfGetCaller( $level = 2 ) {
1479  $backtrace = wfDebugBacktrace( $level + 1 );
1480  if ( isset( $backtrace[$level] ) ) {
1481  return wfFormatStackFrame( $backtrace[$level] );
1482  } else {
1483  return 'unknown';
1484  }
1485 }
1486 
1494 function wfGetAllCallers( $limit = 3 ) {
1495  $trace = array_reverse( wfDebugBacktrace() );
1496  if ( !$limit || $limit > count( $trace ) - 1 ) {
1497  $limit = count( $trace ) - 1;
1498  }
1499  $trace = array_slice( $trace, -$limit - 1, $limit );
1500  return implode( '/', array_map( 'wfFormatStackFrame', $trace ) );
1501 }
1502 
1509 function wfFormatStackFrame( $frame ) {
1510  if ( !isset( $frame['function'] ) ) {
1511  return 'NO_FUNCTION_GIVEN';
1512  }
1513  return isset( $frame['class'] ) && isset( $frame['type'] ) ?
1514  $frame['class'] . $frame['type'] . $frame['function'] :
1515  $frame['function'];
1516 }
1517 
1518 /* Some generic result counters, pulled out of SearchEngine */
1519 
1527 function wfShowingResults( $offset, $limit ) {
1528  return wfMessage( 'showingresults' )->numParams( $limit, $offset + 1 )->parse();
1529 }
1530 
1540 function wfClientAcceptsGzip( $force = false ) {
1541  static $result = null;
1542  if ( $result === null || $force ) {
1543  $result = false;
1544  if ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) {
1545  # @todo FIXME: We may want to blacklist some broken browsers
1546  $m = [];
1547  if ( preg_match(
1548  '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/',
1549  $_SERVER['HTTP_ACCEPT_ENCODING'],
1550  $m
1551  )
1552  ) {
1553  if ( isset( $m[2] ) && ( $m[1] == 'q' ) && ( $m[2] == 0 ) ) {
1554  $result = false;
1555  return $result;
1556  }
1557  wfDebug( "wfClientAcceptsGzip: client accepts gzip.\n" );
1558  $result = true;
1559  }
1560  }
1561  }
1562  return $result;
1563 }
1564 
1575 function wfEscapeWikiText( $text ) {
1576  global $wgEnableMagicLinks;
1577  static $repl = null, $repl2 = null;
1578  if ( $repl === null || defined( 'MW_PARSER_TEST' ) || defined( 'MW_PHPUNIT_TEST' ) ) {
1579  // Tests depend upon being able to change $wgEnableMagicLinks, so don't cache
1580  // in those situations
1581  $repl = [
1582  '"' => '&#34;', '&' => '&#38;', "'" => '&#39;', '<' => '&#60;',
1583  '=' => '&#61;', '>' => '&#62;', '[' => '&#91;', ']' => '&#93;',
1584  '{' => '&#123;', '|' => '&#124;', '}' => '&#125;', ';' => '&#59;',
1585  "\n#" => "\n&#35;", "\r#" => "\r&#35;",
1586  "\n*" => "\n&#42;", "\r*" => "\r&#42;",
1587  "\n:" => "\n&#58;", "\r:" => "\r&#58;",
1588  "\n " => "\n&#32;", "\r " => "\r&#32;",
1589  "\n\n" => "\n&#10;", "\r\n" => "&#13;\n",
1590  "\n\r" => "\n&#13;", "\r\r" => "\r&#13;",
1591  "\n\t" => "\n&#9;", "\r\t" => "\r&#9;", // "\n\t\n" is treated like "\n\n"
1592  "\n----" => "\n&#45;---", "\r----" => "\r&#45;---",
1593  '__' => '_&#95;', '://' => '&#58;//',
1594  ];
1595 
1596  $magicLinks = array_keys( array_filter( $wgEnableMagicLinks ) );
1597  // We have to catch everything "\s" matches in PCRE
1598  foreach ( $magicLinks as $magic ) {
1599  $repl["$magic "] = "$magic&#32;";
1600  $repl["$magic\t"] = "$magic&#9;";
1601  $repl["$magic\r"] = "$magic&#13;";
1602  $repl["$magic\n"] = "$magic&#10;";
1603  $repl["$magic\f"] = "$magic&#12;";
1604  }
1605 
1606  // And handle protocols that don't use "://"
1607  global $wgUrlProtocols;
1608  $repl2 = [];
1609  foreach ( $wgUrlProtocols as $prot ) {
1610  if ( substr( $prot, -1 ) === ':' ) {
1611  $repl2[] = preg_quote( substr( $prot, 0, -1 ), '/' );
1612  }
1613  }
1614  $repl2 = $repl2 ? '/\b(' . implode( '|', $repl2 ) . '):/i' : '/^(?!)/';
1615  }
1616  $text = substr( strtr( "\n$text", $repl ), 1 );
1617  $text = preg_replace( $repl2, '$1&#58;', $text );
1618  return $text;
1619 }
1620 
1631 function wfSetVar( &$dest, $source, $force = false ) {
1632  $temp = $dest;
1633  if ( !is_null( $source ) || $force ) {
1634  $dest = $source;
1635  }
1636  return $temp;
1637 }
1638 
1648 function wfSetBit( &$dest, $bit, $state = true ) {
1649  $temp = (bool)( $dest & $bit );
1650  if ( !is_null( $state ) ) {
1651  if ( $state ) {
1652  $dest |= $bit;
1653  } else {
1654  $dest &= ~$bit;
1655  }
1656  }
1657  return $temp;
1658 }
1659 
1666 function wfVarDump( $var ) {
1667  global $wgOut;
1668  $s = str_replace( "\n", "<br />\n", var_export( $var, true ) . "\n" );
1669  if ( headers_sent() || !isset( $wgOut ) || !is_object( $wgOut ) ) {
1670  print $s;
1671  } else {
1672  $wgOut->addHTML( $s );
1673  }
1674 }
1675 
1683 function wfHttpError( $code, $label, $desc ) {
1684  global $wgOut;
1686  if ( $wgOut ) {
1687  $wgOut->disable();
1688  $wgOut->sendCacheControl();
1689  }
1690 
1692  header( 'Content-type: text/html; charset=utf-8' );
1693  print '<!DOCTYPE html>' .
1694  '<html><head><title>' .
1695  htmlspecialchars( $label ) .
1696  '</title></head><body><h1>' .
1697  htmlspecialchars( $label ) .
1698  '</h1><p>' .
1699  nl2br( htmlspecialchars( $desc ) ) .
1700  "</p></body></html>\n";
1701 }
1702 
1720 function wfResetOutputBuffers( $resetGzipEncoding = true ) {
1721  if ( $resetGzipEncoding ) {
1722  // Suppress Content-Encoding and Content-Length
1723  // headers from OutputHandler::handle.
1725  $wgDisableOutputCompression = true;
1726  }
1727  while ( $status = ob_get_status() ) {
1728  if ( isset( $status['flags'] ) ) {
1729  $flags = PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_REMOVABLE;
1730  $deleteable = ( $status['flags'] & $flags ) === $flags;
1731  } elseif ( isset( $status['del'] ) ) {
1732  $deleteable = $status['del'];
1733  } else {
1734  // Guess that any PHP-internal setting can't be removed.
1735  $deleteable = $status['type'] !== 0; /* PHP_OUTPUT_HANDLER_INTERNAL */
1736  }
1737  if ( !$deleteable ) {
1738  // Give up, and hope the result doesn't break
1739  // output behavior.
1740  break;
1741  }
1742  if ( $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier' ) {
1743  // Unit testing barrier to prevent this function from breaking PHPUnit.
1744  break;
1745  }
1746  if ( !ob_end_clean() ) {
1747  // Could not remove output buffer handler; abort now
1748  // to avoid getting in some kind of infinite loop.
1749  break;
1750  }
1751  if ( $resetGzipEncoding ) {
1752  if ( $status['name'] == 'ob_gzhandler' ) {
1753  // Reset the 'Content-Encoding' field set by this handler
1754  // so we can start fresh.
1755  header_remove( 'Content-Encoding' );
1756  break;
1757  }
1758  }
1759  }
1760 }
1761 
1775  wfResetOutputBuffers( false );
1776 }
1777 
1786 function wfAcceptToPrefs( $accept, $def = '*/*' ) {
1787  # No arg means accept anything (per HTTP spec)
1788  if ( !$accept ) {
1789  return [ $def => 1.0 ];
1790  }
1791 
1792  $prefs = [];
1793 
1794  $parts = explode( ',', $accept );
1795 
1796  foreach ( $parts as $part ) {
1797  # @todo FIXME: Doesn't deal with params like 'text/html; level=1'
1798  $values = explode( ';', trim( $part ) );
1799  $match = [];
1800  if ( count( $values ) == 1 ) {
1801  $prefs[$values[0]] = 1.0;
1802  } elseif ( preg_match( '/q\s*=\s*(\d*\.\d+)/', $values[1], $match ) ) {
1803  $prefs[$values[0]] = floatval( $match[1] );
1804  }
1805  }
1806 
1807  return $prefs;
1808 }
1809 
1822 function mimeTypeMatch( $type, $avail ) {
1823  if ( array_key_exists( $type, $avail ) ) {
1824  return $type;
1825  } else {
1826  $mainType = explode( '/', $type )[0];
1827  if ( array_key_exists( "$mainType/*", $avail ) ) {
1828  return "$mainType/*";
1829  } elseif ( array_key_exists( '*/*', $avail ) ) {
1830  return '*/*';
1831  } else {
1832  return null;
1833  }
1834  }
1835 }
1836 
1850 function wfNegotiateType( $cprefs, $sprefs ) {
1851  $combine = [];
1852 
1853  foreach ( array_keys( $sprefs ) as $type ) {
1854  $subType = explode( '/', $type )[1];
1855  if ( $subType != '*' ) {
1856  $ckey = mimeTypeMatch( $type, $cprefs );
1857  if ( $ckey ) {
1858  $combine[$type] = $sprefs[$type] * $cprefs[$ckey];
1859  }
1860  }
1861  }
1862 
1863  foreach ( array_keys( $cprefs ) as $type ) {
1864  $subType = explode( '/', $type )[1];
1865  if ( $subType != '*' && !array_key_exists( $type, $sprefs ) ) {
1866  $skey = mimeTypeMatch( $type, $sprefs );
1867  if ( $skey ) {
1868  $combine[$type] = $sprefs[$skey] * $cprefs[$type];
1869  }
1870  }
1871  }
1872 
1873  $bestq = 0;
1874  $besttype = null;
1875 
1876  foreach ( array_keys( $combine ) as $type ) {
1877  if ( $combine[$type] > $bestq ) {
1878  $besttype = $type;
1879  $bestq = $combine[$type];
1880  }
1881  }
1882 
1883  return $besttype;
1884 }
1885 
1892 function wfSuppressWarnings( $end = false ) {
1893  Wikimedia\suppressWarnings( $end );
1894 }
1895 
1900 function wfRestoreWarnings() {
1901  Wikimedia\restoreWarnings();
1902 }
1903 
1912 function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) {
1913  $ret = MWTimestamp::convert( $outputtype, $ts );
1914  if ( $ret === false ) {
1915  wfDebug( "wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n" );
1916  }
1917  return $ret;
1918 }
1919 
1928 function wfTimestampOrNull( $outputtype = TS_UNIX, $ts = null ) {
1929  if ( is_null( $ts ) ) {
1930  return null;
1931  } else {
1932  return wfTimestamp( $outputtype, $ts );
1933  }
1934 }
1935 
1941 function wfTimestampNow() {
1942  # return NOW
1943  return MWTimestamp::now( TS_MW );
1944 }
1945 
1951 function wfIsWindows() {
1952  static $isWindows = null;
1953  if ( $isWindows === null ) {
1954  $isWindows = strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN';
1955  }
1956  return $isWindows;
1957 }
1958 
1964 function wfIsHHVM() {
1965  return defined( 'HHVM_VERSION' );
1966 }
1967 
1974 function wfIsCLI() {
1975  return PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg';
1976 }
1977 
1989 function wfTempDir() {
1990  global $wgTmpDirectory;
1991 
1992  if ( $wgTmpDirectory !== false ) {
1993  return $wgTmpDirectory;
1994  }
1995 
1997 }
1998 
2008 function wfMkdirParents( $dir, $mode = null, $caller = null ) {
2009  global $wgDirectoryMode;
2010 
2011  if ( FileBackend::isStoragePath( $dir ) ) { // sanity
2012  throw new MWException( __FUNCTION__ . " given storage path '$dir'." );
2013  }
2014 
2015  if ( !is_null( $caller ) ) {
2016  wfDebug( "$caller: called wfMkdirParents($dir)\n" );
2017  }
2018 
2019  if ( strval( $dir ) === '' || is_dir( $dir ) ) {
2020  return true;
2021  }
2022 
2023  $dir = str_replace( [ '\\', '/' ], DIRECTORY_SEPARATOR, $dir );
2024 
2025  if ( is_null( $mode ) ) {
2026  $mode = $wgDirectoryMode;
2027  }
2028 
2029  // Turn off the normal warning, we're doing our own below
2030  Wikimedia\suppressWarnings();
2031  $ok = mkdir( $dir, $mode, true ); // PHP5 <3
2032  Wikimedia\restoreWarnings();
2033 
2034  if ( !$ok ) {
2035  // directory may have been created on another request since we last checked
2036  if ( is_dir( $dir ) ) {
2037  return true;
2038  }
2039 
2040  // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis.
2041  wfLogWarning( sprintf( "failed to mkdir \"%s\" mode 0%o", $dir, $mode ) );
2042  }
2043  return $ok;
2044 }
2045 
2051 function wfRecursiveRemoveDir( $dir ) {
2052  wfDebug( __FUNCTION__ . "( $dir )\n" );
2053  // taken from https://secure.php.net/manual/en/function.rmdir.php#98622
2054  if ( is_dir( $dir ) ) {
2055  $objects = scandir( $dir );
2056  foreach ( $objects as $object ) {
2057  if ( $object != "." && $object != ".." ) {
2058  if ( filetype( $dir . '/' . $object ) == "dir" ) {
2059  wfRecursiveRemoveDir( $dir . '/' . $object );
2060  } else {
2061  unlink( $dir . '/' . $object );
2062  }
2063  }
2064  }
2065  reset( $objects );
2066  rmdir( $dir );
2067  }
2068 }
2069 
2076 function wfPercent( $nr, $acc = 2, $round = true ) {
2077  $ret = sprintf( "%.${acc}f", $nr );
2078  return $round ? round( $ret, $acc ) . '%' : "$ret%";
2079 }
2080 
2104 function wfIniGetBool( $setting ) {
2105  return wfStringToBool( ini_get( $setting ) );
2106 }
2107 
2120 function wfStringToBool( $val ) {
2121  $val = strtolower( $val );
2122  // 'on' and 'true' can't have whitespace around them, but '1' can.
2123  return $val == 'on'
2124  || $val == 'true'
2125  || $val == 'yes'
2126  || preg_match( "/^\s*[+-]?0*[1-9]/", $val ); // approx C atoi() function
2127 }
2128 
2141 function wfEscapeShellArg( ...$args ) {
2142  return Shell::escape( ...$args );
2143 }
2144 
2168 function wfShellExec( $cmd, &$retval = null, $environ = [],
2169  $limits = [], $options = []
2170 ) {
2171  if ( Shell::isDisabled() ) {
2172  $retval = 1;
2173  // Backwards compatibility be upon us...
2174  return 'Unable to run external programs, proc_open() is disabled.';
2175  }
2176 
2177  if ( is_array( $cmd ) ) {
2178  $cmd = Shell::escape( $cmd );
2179  }
2180 
2181  $includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr'];
2182  $profileMethod = $options['profileMethod'] ?? wfGetCaller();
2183 
2184  try {
2185  $result = Shell::command( [] )
2186  ->unsafeParams( (array)$cmd )
2187  ->environment( $environ )
2188  ->limits( $limits )
2189  ->includeStderr( $includeStderr )
2190  ->profileMethod( $profileMethod )
2191  // For b/c
2192  ->restrict( Shell::RESTRICT_NONE )
2193  ->execute();
2194  } catch ( ProcOpenError $ex ) {
2195  $retval = -1;
2196  return '';
2197  }
2198 
2199  $retval = $result->getExitCode();
2200 
2201  return $result->getStdout();
2202 }
2203 
2221 function wfShellExecWithStderr( $cmd, &$retval = null, $environ = [], $limits = [] ) {
2222  return wfShellExec( $cmd, $retval, $environ, $limits,
2223  [ 'duplicateStderr' => true, 'profileMethod' => wfGetCaller() ] );
2224 }
2225 
2240 function wfShellWikiCmd( $script, array $parameters = [], array $options = [] ) {
2241  global $wgPhpCli;
2242  // Give site config file a chance to run the script in a wrapper.
2243  // The caller may likely want to call wfBasename() on $script.
2244  Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
2245  $cmd = [ $options['php'] ?? $wgPhpCli ];
2246  if ( isset( $options['wrapper'] ) ) {
2247  $cmd[] = $options['wrapper'];
2248  }
2249  $cmd[] = $script;
2250  // Escape each parameter for shell
2251  return Shell::escape( array_merge( $cmd, $parameters ) );
2252 }
2253 
2265 function wfMerge( $old, $mine, $yours, &$result, &$mergeAttemptResult = null ) {
2266  global $wgDiff3;
2267 
2268  # This check may also protect against code injection in
2269  # case of broken installations.
2270  Wikimedia\suppressWarnings();
2271  $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
2272  Wikimedia\restoreWarnings();
2273 
2274  if ( !$haveDiff3 ) {
2275  wfDebug( "diff3 not found\n" );
2276  return false;
2277  }
2278 
2279  # Make temporary files
2280  $td = wfTempDir();
2281  $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
2282  $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' );
2283  $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' );
2284 
2285  # NOTE: diff3 issues a warning to stderr if any of the files does not end with
2286  # a newline character. To avoid this, we normalize the trailing whitespace before
2287  # creating the diff.
2288 
2289  fwrite( $oldtextFile, rtrim( $old ) . "\n" );
2290  fclose( $oldtextFile );
2291  fwrite( $mytextFile, rtrim( $mine ) . "\n" );
2292  fclose( $mytextFile );
2293  fwrite( $yourtextFile, rtrim( $yours ) . "\n" );
2294  fclose( $yourtextFile );
2295 
2296  # Check for a conflict
2297  $cmd = Shell::escape( $wgDiff3, '-a', '--overlap-only', $mytextName,
2298  $oldtextName, $yourtextName );
2299  $handle = popen( $cmd, 'r' );
2300 
2301  $mergeAttemptResult = '';
2302  do {
2303  $data = fread( $handle, 8192 );
2304  if ( strlen( $data ) == 0 ) {
2305  break;
2306  }
2307  $mergeAttemptResult .= $data;
2308  } while ( true );
2309  pclose( $handle );
2310 
2311  $conflict = $mergeAttemptResult !== '';
2312 
2313  # Merge differences
2314  $cmd = Shell::escape( $wgDiff3, '-a', '-e', '--merge', $mytextName,
2315  $oldtextName, $yourtextName );
2316  $handle = popen( $cmd, 'r' );
2317  $result = '';
2318  do {
2319  $data = fread( $handle, 8192 );
2320  if ( strlen( $data ) == 0 ) {
2321  break;
2322  }
2323  $result .= $data;
2324  } while ( true );
2325  pclose( $handle );
2326  unlink( $mytextName );
2327  unlink( $oldtextName );
2328  unlink( $yourtextName );
2329 
2330  if ( $result === '' && $old !== '' && !$conflict ) {
2331  wfDebug( "Unexpected null result from diff3. Command: $cmd\n" );
2332  $conflict = true;
2333  }
2334  return !$conflict;
2335 }
2336 
2348 function wfDiff( $before, $after, $params = '-u' ) {
2349  if ( $before == $after ) {
2350  return '';
2351  }
2352 
2353  global $wgDiff;
2354  Wikimedia\suppressWarnings();
2355  $haveDiff = $wgDiff && file_exists( $wgDiff );
2356  Wikimedia\restoreWarnings();
2357 
2358  # This check may also protect against code injection in
2359  # case of broken installations.
2360  if ( !$haveDiff ) {
2361  wfDebug( "diff executable not found\n" );
2362  $diffs = new Diff( explode( "\n", $before ), explode( "\n", $after ) );
2363  $format = new UnifiedDiffFormatter();
2364  return $format->format( $diffs );
2365  }
2366 
2367  # Make temporary files
2368  $td = wfTempDir();
2369  $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
2370  $newtextFile = fopen( $newtextName = tempnam( $td, 'merge-your-' ), 'w' );
2371 
2372  fwrite( $oldtextFile, $before );
2373  fclose( $oldtextFile );
2374  fwrite( $newtextFile, $after );
2375  fclose( $newtextFile );
2376 
2377  // Get the diff of the two files
2378  $cmd = "$wgDiff " . $params . ' ' . Shell::escape( $oldtextName, $newtextName );
2379 
2380  $h = popen( $cmd, 'r' );
2381  if ( !$h ) {
2382  unlink( $oldtextName );
2383  unlink( $newtextName );
2384  throw new Exception( __METHOD__ . '(): popen() failed' );
2385  }
2386 
2387  $diff = '';
2388 
2389  do {
2390  $data = fread( $h, 8192 );
2391  if ( strlen( $data ) == 0 ) {
2392  break;
2393  }
2394  $diff .= $data;
2395  } while ( true );
2396 
2397  // Clean up
2398  pclose( $h );
2399  unlink( $oldtextName );
2400  unlink( $newtextName );
2401 
2402  // Kill the --- and +++ lines. They're not useful.
2403  $diff_lines = explode( "\n", $diff );
2404  if ( isset( $diff_lines[0] ) && strpos( $diff_lines[0], '---' ) === 0 ) {
2405  unset( $diff_lines[0] );
2406  }
2407  if ( isset( $diff_lines[1] ) && strpos( $diff_lines[1], '+++' ) === 0 ) {
2408  unset( $diff_lines[1] );
2409  }
2410 
2411  $diff = implode( "\n", $diff_lines );
2412 
2413  return $diff;
2414 }
2415 
2428 function wfBaseName( $path, $suffix = '' ) {
2429  if ( $suffix == '' ) {
2430  $encSuffix = '';
2431  } else {
2432  $encSuffix = '(?:' . preg_quote( $suffix, '#' ) . ')?';
2433  }
2434 
2435  $matches = [];
2436  if ( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) {
2437  return $matches[1];
2438  } else {
2439  return '';
2440  }
2441 }
2442 
2452 function wfRelativePath( $path, $from ) {
2453  // Normalize mixed input on Windows...
2454  $path = str_replace( '/', DIRECTORY_SEPARATOR, $path );
2455  $from = str_replace( '/', DIRECTORY_SEPARATOR, $from );
2456 
2457  // Trim trailing slashes -- fix for drive root
2458  $path = rtrim( $path, DIRECTORY_SEPARATOR );
2459  $from = rtrim( $from, DIRECTORY_SEPARATOR );
2460 
2461  $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) );
2462  $against = explode( DIRECTORY_SEPARATOR, $from );
2463 
2464  if ( $pieces[0] !== $against[0] ) {
2465  // Non-matching Windows drive letters?
2466  // Return a full path.
2467  return $path;
2468  }
2469 
2470  // Trim off common prefix
2471  while ( count( $pieces ) && count( $against )
2472  && $pieces[0] == $against[0] ) {
2473  array_shift( $pieces );
2474  array_shift( $against );
2475  }
2476 
2477  // relative dots to bump us to the parent
2478  while ( count( $against ) ) {
2479  array_unshift( $pieces, '..' );
2480  array_shift( $against );
2481  }
2482 
2483  array_push( $pieces, wfBaseName( $path ) );
2484 
2485  return implode( DIRECTORY_SEPARATOR, $pieces );
2486 }
2487 
2494 function wfResetSessionID() {
2495  wfDeprecated( __FUNCTION__, '1.27' );
2496  $session = SessionManager::getGlobalSession();
2497  $delay = $session->delaySave();
2498 
2499  $session->resetId();
2500 
2501  // Make sure a session is started, since that's what the old
2502  // wfResetSessionID() did.
2503  if ( session_id() !== $session->getId() ) {
2504  wfSetupSession( $session->getId() );
2505  }
2506 
2507  ScopedCallback::consume( $delay );
2508 }
2509 
2519 function wfSetupSession( $sessionId = false ) {
2520  wfDeprecated( __FUNCTION__, '1.27' );
2521 
2522  if ( $sessionId ) {
2523  session_id( $sessionId );
2524  }
2525 
2526  $session = SessionManager::getGlobalSession();
2527  $session->persist();
2528 
2529  if ( session_id() !== $session->getId() ) {
2530  session_id( $session->getId() );
2531  }
2532  Wikimedia\quietCall( 'session_start' );
2533 }
2534 
2542  global $IP;
2543 
2544  $file = "$IP/serialized/$name";
2545  if ( file_exists( $file ) ) {
2546  $blob = file_get_contents( $file );
2547  if ( $blob ) {
2548  return unserialize( $blob );
2549  }
2550  }
2551  return false;
2552 }
2553 
2561 function wfMemcKey( ...$args ) {
2562  return ObjectCache::getLocalClusterInstance()->makeKey( ...$args );
2563 }
2564 
2575 function wfForeignMemcKey( $db, $prefix, ...$args ) {
2576  $keyspace = $prefix ? "$db-$prefix" : $db;
2577  return ObjectCache::getLocalClusterInstance()->makeKeyInternal( $keyspace, $args );
2578 }
2579 
2592 function wfGlobalCacheKey( ...$args ) {
2593  return ObjectCache::getLocalClusterInstance()->makeGlobalKey( ...$args );
2594 }
2595 
2602 function wfWikiID() {
2603  global $wgDBprefix, $wgDBname;
2604  if ( $wgDBprefix ) {
2605  return "$wgDBname-$wgDBprefix";
2606  } else {
2607  return $wgDBname;
2608  }
2609 }
2610 
2619 function wfSplitWikiID( $wiki ) {
2620  $bits = explode( '-', $wiki, 2 );
2621  if ( count( $bits ) < 2 ) {
2622  $bits[] = '';
2623  }
2624  return $bits;
2625 }
2626 
2652 function wfGetDB( $db, $groups = [], $wiki = false ) {
2653  return wfGetLB( $wiki )->getConnection( $db, $groups, $wiki );
2654 }
2655 
2665 function wfGetLB( $wiki = false ) {
2666  if ( $wiki === false ) {
2667  return MediaWikiServices::getInstance()->getDBLoadBalancer();
2668  } else {
2669  $factory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
2670  return $factory->getMainLB( $wiki );
2671  }
2672 }
2673 
2681 function wfGetLBFactory() {
2682  return MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
2683 }
2684 
2693 function wfFindFile( $title, $options = [] ) {
2694  return RepoGroup::singleton()->findFile( $title, $options );
2695 }
2696 
2704 function wfLocalFile( $title ) {
2705  return RepoGroup::singleton()->getLocalRepo()->newFile( $title );
2706 }
2707 
2715  global $wgMiserMode;
2716  return $wgMiserMode
2717  || ( SiteStats::pages() > 100000
2718  && SiteStats::edits() > 1000000
2719  && SiteStats::users() > 10000 );
2720 }
2721 
2730 function wfScript( $script = 'index' ) {
2732  if ( $script === 'index' ) {
2733  return $wgScript;
2734  } elseif ( $script === 'load' ) {
2735  return $wgLoadScript;
2736  } else {
2737  return "{$wgScriptPath}/{$script}.php";
2738  }
2739 }
2740 
2746 function wfGetScriptUrl() {
2747  if ( isset( $_SERVER['SCRIPT_NAME'] ) ) {
2748  /* as it was called, minus the query string.
2749  *
2750  * Some sites use Apache rewrite rules to handle subdomains,
2751  * and have PHP set up in a weird way that causes PHP_SELF
2752  * to contain the rewritten URL instead of the one that the
2753  * outside world sees.
2754  *
2755  * If in this mode, use SCRIPT_URL instead, which mod_rewrite
2756  * provides containing the "before" URL.
2757  */
2758  return $_SERVER['SCRIPT_NAME'];
2759  } else {
2760  return $_SERVER['URL'];
2761  }
2762 }
2763 
2771 function wfBoolToStr( $value ) {
2772  return $value ? 'true' : 'false';
2773 }
2774 
2780 function wfGetNull() {
2781  return wfIsWindows() ? 'NUL' : '/dev/null';
2782 }
2783 
2807  $ifWritesSince = null, $wiki = false, $cluster = false, $timeout = null
2808 ) {
2809  $lbFactory = MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
2810 
2811  if ( $cluster === '*' ) {
2812  $cluster = false;
2813  $domain = false;
2814  } elseif ( $wiki === false ) {
2815  $domain = $lbFactory->getLocalDomainID();
2816  } else {
2817  $domain = $wiki;
2818  }
2819 
2820  $opts = [
2821  'domain' => $domain,
2822  'cluster' => $cluster,
2823  // B/C: first argument used to be "max seconds of lag"; ignore such values
2824  'ifWritesSince' => ( $ifWritesSince > 1e9 ) ? $ifWritesSince : null
2825  ];
2826  if ( $timeout !== null ) {
2827  $opts['timeout'] = $timeout;
2828  }
2829 
2830  return $lbFactory->waitForReplication( $opts );
2831 }
2832 
2842 function wfCountDown( $seconds ) {
2843  wfDeprecated( __FUNCTION__, '1.31' );
2844  for ( $i = $seconds; $i >= 0; $i-- ) {
2845  if ( $i != $seconds ) {
2846  echo str_repeat( "\x08", strlen( $i + 1 ) );
2847  }
2848  echo $i;
2849  flush();
2850  if ( $i ) {
2851  sleep( 1 );
2852  }
2853  }
2854  echo "\n";
2855 }
2856 
2866  global $wgIllegalFileChars;
2867  $illegalFileChars = $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : '';
2868  $name = preg_replace(
2869  "/[^" . Title::legalChars() . "]" . $illegalFileChars . "/",
2870  '-',
2871  $name
2872  );
2873  // $wgIllegalFileChars may not include '/' and '\', so we still need to do this
2874  $name = wfBaseName( $name );
2875  return $name;
2876 }
2877 
2883 function wfMemoryLimit() {
2884  global $wgMemoryLimit;
2885  $memlimit = wfShorthandToInteger( ini_get( 'memory_limit' ) );
2886  if ( $memlimit != -1 ) {
2887  $conflimit = wfShorthandToInteger( $wgMemoryLimit );
2888  if ( $conflimit == -1 ) {
2889  wfDebug( "Removing PHP's memory limit\n" );
2890  Wikimedia\suppressWarnings();
2891  ini_set( 'memory_limit', $conflimit );
2892  Wikimedia\restoreWarnings();
2893  return $conflimit;
2894  } elseif ( $conflimit > $memlimit ) {
2895  wfDebug( "Raising PHP's memory limit to $conflimit bytes\n" );
2896  Wikimedia\suppressWarnings();
2897  ini_set( 'memory_limit', $conflimit );
2898  Wikimedia\restoreWarnings();
2899  return $conflimit;
2900  }
2901  }
2902  return $memlimit;
2903 }
2904 
2913 
2914  $timeLimit = ini_get( 'max_execution_time' );
2915  // Note that CLI scripts use 0
2916  if ( $timeLimit > 0 && $wgTransactionalTimeLimit > $timeLimit ) {
2917  set_time_limit( $wgTransactionalTimeLimit );
2918  }
2919 
2920  ignore_user_abort( true ); // ignore client disconnects
2921 
2922  return $timeLimit;
2923 }
2924 
2932 function wfShorthandToInteger( $string = '', $default = -1 ) {
2933  $string = trim( $string );
2934  if ( $string === '' ) {
2935  return $default;
2936  }
2937  $last = $string[strlen( $string ) - 1];
2938  $val = intval( $string );
2939  switch ( $last ) {
2940  case 'g':
2941  case 'G':
2942  $val *= 1024;
2943  // break intentionally missing
2944  case 'm':
2945  case 'M':
2946  $val *= 1024;
2947  // break intentionally missing
2948  case 'k':
2949  case 'K':
2950  $val *= 1024;
2951  }
2952 
2953  return $val;
2954 }
2955 
2966 function wfBCP47( $code ) {
2967  wfDeprecated( __METHOD__, '1.31' );
2968  return LanguageCode::bcp47( $code );
2969 }
2970 
2978 function wfGetCache( $cacheType ) {
2979  return ObjectCache::getInstance( $cacheType );
2980 }
2981 
2988 function wfGetMainCache() {
2990 }
2991 
2998  global $wgMessageCacheType;
2999  return ObjectCache::getInstance( $wgMessageCacheType );
3000 }
3001 
3016 function wfUnpack( $format, $data, $length = false ) {
3017  if ( $length !== false ) {
3018  $realLen = strlen( $data );
3019  if ( $realLen < $length ) {
3020  throw new MWException( "Tried to use wfUnpack on a "
3021  . "string of length $realLen, but needed one "
3022  . "of at least length $length."
3023  );
3024  }
3025  }
3026 
3027  Wikimedia\suppressWarnings();
3028  $result = unpack( $format, $data );
3029  Wikimedia\restoreWarnings();
3030 
3031  if ( $result === false ) {
3032  // If it cannot extract the packed data.
3033  throw new MWException( "unpack could not unpack binary data" );
3034  }
3035  return $result;
3036 }
3037 
3052 function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
3053  # Handle redirects; callers almost always hit wfFindFile() anyway,
3054  # so just use that method because it has a fast process cache.
3055  $file = wfFindFile( $name ); // get the final name
3056  $name = $file ? $file->getTitle()->getDBkey() : $name;
3057 
3058  # Run the extension hook
3059  $bad = false;
3060  if ( !Hooks::run( 'BadImage', [ $name, &$bad ] ) ) {
3061  return (bool)$bad;
3062  }
3063 
3065  $key = $cache->makeKey(
3066  'bad-image-list', ( $blacklist === null ) ? 'default' : md5( $blacklist )
3067  );
3068  $badImages = $cache->get( $key );
3069 
3070  if ( $badImages === false ) { // cache miss
3071  if ( $blacklist === null ) {
3072  $blacklist = wfMessage( 'bad_image_list' )->inContentLanguage()->plain(); // site list
3073  }
3074  # Build the list now
3075  $badImages = [];
3076  $lines = explode( "\n", $blacklist );
3077  foreach ( $lines as $line ) {
3078  # List items only
3079  if ( substr( $line, 0, 1 ) !== '*' ) {
3080  continue;
3081  }
3082 
3083  # Find all links
3084  $m = [];
3085  if ( !preg_match_all( '/\[\[:?(.*?)\]\]/', $line, $m ) ) {
3086  continue;
3087  }
3088 
3089  $exceptions = [];
3090  $imageDBkey = false;
3091  foreach ( $m[1] as $i => $titleText ) {
3092  $title = Title::newFromText( $titleText );
3093  if ( !is_null( $title ) ) {
3094  if ( $i == 0 ) {
3095  $imageDBkey = $title->getDBkey();
3096  } else {
3097  $exceptions[$title->getPrefixedDBkey()] = true;
3098  }
3099  }
3100  }
3101 
3102  if ( $imageDBkey !== false ) {
3103  $badImages[$imageDBkey] = $exceptions;
3104  }
3105  }
3106  $cache->set( $key, $badImages, 60 );
3107  }
3108 
3109  $contextKey = $contextTitle ? $contextTitle->getPrefixedDBkey() : false;
3110  $bad = isset( $badImages[$name] ) && !isset( $badImages[$name][$contextKey] );
3111 
3112  return $bad;
3113 }
3114 
3122 function wfCanIPUseHTTPS( $ip ) {
3123  $canDo = true;
3124  Hooks::run( 'CanIPUseHTTPS', [ $ip, &$canDo ] );
3125  return !!$canDo;
3126 }
3127 
3135 function wfIsInfinity( $str ) {
3136  // These are hardcoded elsewhere in MediaWiki (e.g. mediawiki.special.block.js).
3137  $infinityValues = [ 'infinite', 'indefinite', 'infinity', 'never' ];
3138  return in_array( $str, $infinityValues );
3139 }
3140 
3155 function wfThumbIsStandard( File $file, array $params ) {
3157 
3158  $multipliers = [ 1 ];
3159  if ( $wgResponsiveImages ) {
3160  // These available sizes are hardcoded currently elsewhere in MediaWiki.
3161  // @see Linker::processResponsiveImages
3162  $multipliers[] = 1.5;
3163  $multipliers[] = 2;
3164  }
3165 
3166  $handler = $file->getHandler();
3167  if ( !$handler || !isset( $params['width'] ) ) {
3168  return false;
3169  }
3170 
3171  $basicParams = [];
3172  if ( isset( $params['page'] ) ) {
3173  $basicParams['page'] = $params['page'];
3174  }
3175 
3176  $thumbLimits = [];
3177  $imageLimits = [];
3178  // Expand limits to account for multipliers
3179  foreach ( $multipliers as $multiplier ) {
3180  $thumbLimits = array_merge( $thumbLimits, array_map(
3181  function ( $width ) use ( $multiplier ) {
3182  return round( $width * $multiplier );
3183  }, $wgThumbLimits )
3184  );
3185  $imageLimits = array_merge( $imageLimits, array_map(
3186  function ( $pair ) use ( $multiplier ) {
3187  return [
3188  round( $pair[0] * $multiplier ),
3189  round( $pair[1] * $multiplier ),
3190  ];
3191  }, $wgImageLimits )
3192  );
3193  }
3194 
3195  // Check if the width matches one of $wgThumbLimits
3196  if ( in_array( $params['width'], $thumbLimits ) ) {
3197  $normalParams = $basicParams + [ 'width' => $params['width'] ];
3198  // Append any default values to the map (e.g. "lossy", "lossless", ...)
3199  $handler->normaliseParams( $file, $normalParams );
3200  } else {
3201  // If not, then check if the width matchs one of $wgImageLimits
3202  $match = false;
3203  foreach ( $imageLimits as $pair ) {
3204  $normalParams = $basicParams + [ 'width' => $pair[0], 'height' => $pair[1] ];
3205  // Decide whether the thumbnail should be scaled on width or height.
3206  // Also append any default values to the map (e.g. "lossy", "lossless", ...)
3207  $handler->normaliseParams( $file, $normalParams );
3208  // Check if this standard thumbnail size maps to the given width
3209  if ( $normalParams['width'] == $params['width'] ) {
3210  $match = true;
3211  break;
3212  }
3213  }
3214  if ( !$match ) {
3215  return false; // not standard for description pages
3216  }
3217  }
3218 
3219  // Check that the given values for non-page, non-width, params are just defaults
3220  foreach ( $params as $key => $value ) {
3221  if ( !isset( $normalParams[$key] ) || $normalParams[$key] != $value ) {
3222  return false;
3223  }
3224  }
3225 
3226  return true;
3227 }
3228 
3241 function wfArrayPlus2d( array $baseArray, array $newValues ) {
3242  // First merge items that are in both arrays
3243  foreach ( $baseArray as $name => &$groupVal ) {
3244  if ( isset( $newValues[$name] ) ) {
3245  $groupVal += $newValues[$name];
3246  }
3247  }
3248  // Now add items that didn't exist yet
3249  $baseArray += $newValues;
3250 
3251  return $baseArray;
3252 }
3253 
3262 function wfGetRusage() {
3263  if ( !function_exists( 'getrusage' ) ) {
3264  return false;
3265  } elseif ( defined( 'HHVM_VERSION' ) && PHP_OS === 'Linux' ) {
3266  return getrusage( 2 /* RUSAGE_THREAD */ );
3267  } else {
3268  return getrusage( 0 /* RUSAGE_SELF */ );
3269  }
3270 }
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
wfSuppressWarnings( $end=false)
Reference-counted warning suppression.
mimeTypeMatch( $type, $avail)
Checks if a given MIME type matches any of the keys in the given array.
wfUrlProtocols( $includeProtocolRelative=true)
Returns a regular expression of url protocols.
wfBaseName( $path, $suffix='')
Return the final portion of a pathname.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
wfEscapeWikiText( $text)
Escapes the given text so that it may be output using addWikiText() without any linking, formatting, etc.
$wgDebugTimestamps
Prefix debug messages with relative timestamp.
wfWarn( $msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output $out
Definition: hooks.txt:785
static fetchLanguageNames( $inLanguage=self::AS_AUTONYMS, $include='mw')
Get an array of language names, indexed by code.
Definition: Language.php:843
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query
Definition: hooks.txt:1599
$wgScript
The URL path to index.php.
wfIsHHVM()
Check if we are running under HHVM.
wfMakeUrlIndexes( $url)
Make URL indexes, appropriate for the el_index field of externallinks.
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
$IP
Definition: WebStart.php:41
$wgDebugLogGroups
Map of string log group names to log destinations.
wfLoadSkin( $skin, $path=null)
Load a skin.
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:1996
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
wfShellWikiCmd( $script, array $parameters=[], array $options=[])
Generate a shell-escaped command line string to run a MediaWiki cli script.
wfGetRusage()
Get system resource usage of current request context.
wfIsBadImage( $name, $contextTitle=false, $blacklist=null)
Determine if an image exists on the &#39;bad image list&#39;.
static instance()
Singleton.
Definition: Profiler.php:62
wfExpandUrl( $url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfGetCache( $cacheType)
Get a specific cache object.
wfGetPrecompiledData( $name)
Get an object from the precompiled serialized directory.
$wgInternalServer
Internal server name as known to CDN, if different.
wfHostname()
Fetch server name for use in error reporting etc.
wfRecursiveRemoveDir( $dir)
Remove a directory and all its content.
wfParseUrl( $url)
parse_url() work-alike, but non-broken.
Status::newGood()` to allow deletion, and then `return false` from the hook function. Ensure you consume the 'ChangeTagAfterDelete' hook to carry out custom deletion actions. $tag:name of the tag $user:user initiating the action & $status:Status object. See above. 'ChangeTagsListActive':Allows you to nominate which of the tags your extension uses are in active use. & $tags:list of all active tags. Append to this array. 'ChangeTagsAfterUpdateTags':Called after tags have been updated with the ChangeTags::updateTags function. Params:$addedTags:tags effectively added in the update $removedTags:tags effectively removed in the update $prevTags:tags that were present prior to the update $rc_id:recentchanges table id $rev_id:revision table id $log_id:logging table id $params:tag params $rc:RecentChange being tagged when the tagging accompanies the action, or null $user:User who performed the tagging when the tagging is subsequent to the action, or null 'ChangeTagsAllowedAdd':Called when checking if a user can add tags to a change. & $allowedTags:List of all the tags the user is allowed to add. Any tags the user wants to add( $addTags) that are not in this array will cause it to fail. You may add or remove tags to this array as required. $addTags:List of tags user intends to add. $user:User who is adding the tags. 'ChangeUserGroups':Called before user groups are changed. $performer:The User who will perform the change $user:The User whose groups will be changed & $add:The groups that will be added & $remove:The groups that will be removed 'Collation::factory':Called if $wgCategoryCollation is an unknown collation. $collationName:Name of the collation in question & $collationObject:Null. Replace with a subclass of the Collation class that implements the collation given in $collationName. 'ConfirmEmailComplete':Called after a user 's email has been confirmed successfully. $user:user(object) whose email is being confirmed 'ContentAlterParserOutput':Modify parser output for a given content object. Called by Content::getParserOutput after parsing has finished. Can be used for changes that depend on the result of the parsing but have to be done before LinksUpdate is called(such as adding tracking categories based on the rendered HTML). $content:The Content to render $title:Title of the page, as context $parserOutput:ParserOutput to manipulate 'ContentGetParserOutput':Customize parser output for a given content object, called by AbstractContent::getParserOutput. May be used to override the normal model-specific rendering of page content. $content:The Content to render $title:Title of the page, as context $revId:The revision ID, as context $options:ParserOptions for rendering. To avoid confusing the parser cache, the output can only depend on parameters provided to this hook function, not on global state. $generateHtml:boolean, indicating whether full HTML should be generated. If false, generation of HTML may be skipped, but other information should still be present in the ParserOutput object. & $output:ParserOutput, to manipulate or replace 'ContentHandlerDefaultModelFor':Called when the default content model is determined for a given title. May be used to assign a different model for that title. $title:the Title in question & $model:the model name. Use with CONTENT_MODEL_XXX constants. 'ContentHandlerForModelID':Called when a ContentHandler is requested for a given content model name, but no entry for that model exists in $wgContentHandlers. Note:if your extension implements additional models via this hook, please use GetContentModels hook to make them known to core. $modeName:the requested content model name & $handler:set this to a ContentHandler object, if desired. 'ContentModelCanBeUsedOn':Called to determine whether that content model can be used on a given page. This is especially useful to prevent some content models to be used in some special location. $contentModel:ID of the content model in question $title:the Title in question. & $ok:Output parameter, whether it is OK to use $contentModel on $title. Handler functions that modify $ok should generally return false to prevent further hooks from further modifying $ok. 'ContribsPager::getQueryInfo':Before the contributions query is about to run & $pager:Pager object for contributions & $queryInfo:The query for the contribs Pager 'ContribsPager::reallyDoQuery':Called before really executing the query for My Contributions & $data:an array of results of all contribs queries $pager:The ContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'ContributionsLineEnding':Called before a contributions HTML line is finished $page:SpecialPage object for contributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'ContributionsToolLinks':Change tool links above Special:Contributions $id:User identifier $title:User page title & $tools:Array of tool links $specialPage:SpecialPage instance for context and services. Can be either SpecialContributions or DeletedContributionsPage. Extensions should type hint against a generic SpecialPage though. 'ConvertContent':Called by AbstractContent::convert when a conversion to another content model is requested. Handler functions that modify $result should generally return false to disable further attempts at conversion. $content:The Content object to be converted. $toModel:The ID of the content model to convert to. $lossy:boolean indicating whether lossy conversion is allowed. & $result:Output parameter, in case the handler function wants to provide a converted Content object. Note that $result->getContentModel() must return $toModel. 'ContentSecurityPolicyDefaultSource':Modify the allowed CSP load sources. This affects all directives except for the script directive. If you want to add a script source, see ContentSecurityPolicyScriptSource hook. & $defaultSrc:Array of Content-Security-Policy allowed sources $policyConfig:Current configuration for the Content-Security-Policy header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyDirectives':Modify the content security policy directives. Use this only if ContentSecurityPolicyDefaultSource and ContentSecurityPolicyScriptSource do not meet your needs. & $directives:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'ContentSecurityPolicyScriptSource':Modify the allowed CSP script sources. Note that you also have to use ContentSecurityPolicyDefaultSource if you want non-script sources to be loaded from whatever you add. & $scriptSrc:Array of CSP directives $policyConfig:Current configuration for the CSP header $mode:ContentSecurityPolicy::REPORT_ONLY_MODE or ContentSecurityPolicy::FULL_MODE depending on type of header 'CustomEditor':When invoking the page editor Return true to allow the normal editor to be used, or false if implementing a custom editor, e.g. for a special namespace, etc. $article:Article being edited $user:User performing the edit 'DatabaseOraclePostInit':Called after initialising an Oracle database $db:the DatabaseOracle object 'DeletedContribsPager::reallyDoQuery':Called before really executing the query for Special:DeletedContributions Similar to ContribsPager::reallyDoQuery & $data:an array of results of all contribs queries $pager:The DeletedContribsPager object hooked into $offset:Index offset, inclusive $limit:Exact query limit $descending:Query direction, false for ascending, true for descending 'DeletedContributionsLineEnding':Called before a DeletedContributions HTML line is finished. Similar to ContributionsLineEnding $page:SpecialPage object for DeletedContributions & $ret:the HTML line $row:the DB row for this line & $classes:the classes to add to the surrounding< li > & $attribs:associative array of other HTML attributes for the< li > element. Currently only data attributes reserved to MediaWiki are allowed(see Sanitizer::isReservedDataAttribute). 'DeleteUnknownPreferences':Called by the cleanupPreferences.php maintenance script to build a WHERE clause with which to delete preferences that are not known about. This hook is used by extensions that have dynamically-named preferences that should not be deleted in the usual cleanup process. For example, the Gadgets extension creates preferences prefixed with 'gadget-', and so anything with that prefix is excluded from the deletion. &where:An array that will be passed as the $cond parameter to IDatabase::select() to determine what will be deleted from the user_properties table. $db:The IDatabase object, useful for accessing $db->buildLike() etc. 'DifferenceEngineAfterLoadNewText':called in DifferenceEngine::loadNewText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before returning true from this function. $differenceEngine:DifferenceEngine object 'DifferenceEngineLoadTextAfterNewContentIsLoaded':called in DifferenceEngine::loadText() after the new revision 's content has been loaded into the class member variable $differenceEngine->mNewContent but before checking if the variable 's value is null. This hook can be used to inject content into said class member variable. $differenceEngine:DifferenceEngine object 'DifferenceEngineMarkPatrolledLink':Allows extensions to change the "mark as patrolled" link which is shown both on the diff header as well as on the bottom of a page, usually wrapped in a span element which has class="patrollink". $differenceEngine:DifferenceEngine object & $markAsPatrolledLink:The "mark as patrolled" link HTML(string) $rcid:Recent change ID(rc_id) for this change(int) 'DifferenceEngineMarkPatrolledRCID':Allows extensions to possibly change the rcid parameter. For example the rcid might be set to zero due to the user being the same as the performer of the change but an extension might still want to show it under certain conditions. & $rcid:rc_id(int) of the change or 0 $differenceEngine:DifferenceEngine object $change:RecentChange object $user:User object representing the current user 'DifferenceEngineNewHeader':Allows extensions to change the $newHeader variable, which contains information about the new revision, such as the revision 's author, whether the revision was marked as a minor edit or not, etc. $differenceEngine:DifferenceEngine object & $newHeader:The string containing the various #mw-diff-otitle[1-5] divs, which include things like revision author info, revision comment, RevisionDelete link and more $formattedRevisionTools:Array containing revision tools, some of which may have been injected with the DiffRevisionTools hook $nextlink:String containing the link to the next revision(if any) $status
Definition: hooks.txt:1277
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
$wgHttpsPort
For installations where the canonical server is HTTP but HTTPS is optionally supported, you can specify a non-standard HTTPS port here.
$wgOverrideHostname
Override server hostname detection with a hardcoded value.
wfMerge( $old, $mine, $yours, &$result, &$mergeAttemptResult=null)
wfMerge attempts to merge differences between three texts.
wfLogProfilingData()
A formatter that outputs unified diffs.
$source
$value
wfForeignMemcKey( $db, $prefix,... $args)
Make a cache key for a foreign DB.
wfIsInfinity( $str)
Determine input string is represents as infinity.
const PROTO_CURRENT
Definition: Defines.php:222
wfStripIllegalFilenameChars( $name)
Replace all invalid characters with &#39;-&#39;.
static getInstance( $id)
Get a cached instance of the specified type of cache object.
Definition: ObjectCache.php:92
Stub profiler that does nothing.
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message key
Definition: hooks.txt:2165
static getLocalClusterInstance()
Get the main cluster-local cache object.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency MediaWikiServices
Definition: injection.txt:23
wfUrlProtocolsWithoutProtRel()
Like wfUrlProtocols(), but excludes &#39;//&#39; from the protocol list.
$wgUrlProtocols
URL schemes that should be recognized as valid by wfParseUrl().
$wgDisableOutputCompression
Disable output compression (enabled by default if zlib is available)
wfLogWarning( $msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
wfTimestampOrNull( $outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
wfResetOutputBuffers( $resetGzipEncoding=true)
Clear away any user-level output buffers, discarding contents.
$wgTmpDirectory
The local filesystem path to a temporary directory.
wfGetServerUrl( $proto)
Get the wiki&#39;s "server", i.e.
static isStoragePath( $path)
Check if a given path is a "mwstore://" path.
wfIsWindows()
Check if the operating system is Windows.
wfLocalFile( $title)
Get an object referring to a locally registered file.
wfGetMessageCacheStorage()
Get the cache object used by the message cache.
wfPercent( $nr, $acc=2, $round=true)
wfSetupSession( $sessionId=false)
Initialise php session.
wfLogDBError( $text, array $context=[])
Log for database errors.
wfGetLangObj( $langcode=false)
Return a Language object from $langcode.
static configuration should be added through ResourceLoaderGetConfigVars instead can be used to get the real title e g db for database replication lag or jobqueue for job queue size converted to pseudo seconds It is possible to add more fields and they will be returned to the user in the API response after the basic globals have been set but before ordinary actions take place $output
Definition: hooks.txt:2221
wfVarDump( $var)
A wrapper around the PHP function var_export().
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUnknownUser':When a user doesn 't exist locally, this hook is called to give extensions an opportunity to auto-create it. If the auto-creation is successful, return false. $name:User name 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED since 1.28! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1994
wfCountDown( $seconds)
Count down from $seconds to zero on the terminal, with a one-second pause between showing each number...
$wgEnableMagicLinks
Enable the magic links feature of automatically turning ISBN xxx, PMID xxx, RFC xxx into links...
if( $line===false) $args
Definition: cdb.php:64
static getUsableTempDirectory()
Definition: TempFSFile.php:85
$wgDebugRawPage
If true, log debugging data from action=raw and load.php.
wfScript( $script='index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
wfFormatStackFrame( $frame)
Return a string representation of frame.
wfShellExec( $cmd, &$retval=null, $environ=[], $limits=[], $options=[])
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
wfArrayToCgi( $array1, $array2=null, $prefix='')
This function takes one or two arrays as input, and returns a CGI-style string, e.g.
$last
$wgPhpCli
Executable path of the PHP cli binary.
wfGetAllCallers( $limit=3)
Return a string consisting of callers in the stack.
$wgLanguageCode
Site language code.
wfAppendQuery( $url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
wfArrayFilter(array $arr, callable $callback)
static edits()
Definition: SiteStats.php:94
wfTimestamp( $outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$wgExtensionDirectory
Filesystem extensions directory.
wfLoadExtensions(array $exts)
Load multiple extensions at once.
wfIsDebugRawPage()
Returns true if debug logging should be suppressed if $wgDebugRawPage = false.
wfConfiguredReadOnlyReason()
Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
const PROTO_HTTPS
Definition: Defines.php:220
wfReportTime( $nonce=null)
Returns a script tag that stores the amount of time it took MediaWiki to handle the request in millis...
wfRemoveDotSegments( $urlPath)
Remove all dot-segments in the provided URL path.
wfMergeErrorArrays(... $args)
Merge arrays in the style of getUserPermissionsErrors, with duplicate removal e.g.
wfReadOnly()
Check whether the wiki is in read-only mode.
wfSetBit(&$dest, $bit, $state=true)
As for wfSetVar except setting a bit.
wfMatchesDomainList( $url, $domains)
Check whether a given URL has a domain that occurs in a given set of domains.
wfIncrStats( $key, $count=1)
Increment a statistics counter.
wfUrlencode( $s)
We want some things to be included as literal characters in our title URLs for prettiness, which urlencode encodes by default.
$wgLang
Definition: Setup.php:902
wfTempDir()
Tries to get the system directory for temporary files.
wfClientAcceptsGzip( $force=false)
Whether the client accept gzip encoding.
static getMain()
Get the RequestContext object associated with the main request.
wfNegotiateType( $cprefs, $sprefs)
Returns the &#39;best&#39; match between a client&#39;s requested internet media types and the server&#39;s list of a...
static warning( $msg, $callerOffset=1, $level=E_USER_NOTICE, $log='auto')
Adds a warning entry to the log.
Definition: MWDebug.php:151
wfCgiToArray( $query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
$wgIllegalFileChars
Additional characters that are not allowed in filenames.
const PROTO_INTERNAL
Definition: Defines.php:224
wfRandomString( $length=32)
Get a random string containing a number of pseudo-random hex characters.
getHandler()
Get a MediaHandler instance for this file.
Definition: File.php:1383
wfFindFile( $title, $options=[])
Find a file.
static singleton()
Get a RepoGroup instance.
Definition: RepoGroup.php:61
wfWaitForSlaves( $ifWritesSince=null, $wiki=false, $cluster=false, $timeout=null)
Waits for the replica DBs to catch up to the master position.
$wgMessageCacheType
The cache type for storing the contents of the MediaWiki namespace.
$wgMiserMode
Disable database-intensive features.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
static warnIfHeadersSent()
Log a warning message if headers have already been sent.
wfShowingResults( $offset, $limit)
wfMsgReplaceArgs( $message, $args)
Replace message parameter keys on the given formatted output.
static newFallbackSequence()
Factory function accepting multiple message keys and returning a message instance for the first messa...
Definition: Message.php:461
wfMessageFallback(... $keys)
This function accepts multiple message keys and returns a message instance for the first message whic...
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
static header( $code)
Output an HTTP status code header.
Definition: HttpStatus.php:96
$wgImageLimits
Limit images on image description pages to a user-selectable limit.
Class representing a &#39;diff&#39; between two sequences of strings.
wfHttpError( $code, $label, $desc)
Provide a simple HTTP error.
$cache
Definition: mcc.php:33
$params
static makeVariablesScript( $data, $nonce=null)
Definition: Skin.php:400
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition: hooks.txt:1996
$wgThumbLimits
Adjust thumbnails on image pages according to a user setting.
unserialize( $serialized)
wfDiff( $before, $after, $params='-u')
Returns unified plain-text diff of two texts.
wfBoolToStr( $value)
Convenience function converts boolean values into "true" or "false" (string) values.
namespace and then decline to actually register it file or subcat img or subcat $title
Definition: hooks.txt:936
wfIsCLI()
Check if we are running from the commandline.
wfLoadSkins(array $skins)
Load multiple skins at once.
static factory( $code)
Get a cached or new language object for a given language code.
Definition: Language.php:214
wfQueriesMustScale()
Should low-performance queries be disabled?
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
wfGetCaller( $level=2)
Get the name of the function which called this function wfGetCaller( 1 ) is the function with the wfG...
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return an< a > element with HTML attributes $attribs and contents $html will be returned If you return $ret will be returned $skin
Definition: hooks.txt:1996
wfDebugMem( $exact=false)
Send a line giving PHP memory usage.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
Definition: hooks.txt:785
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
wfGlobalCacheKey(... $args)
Make a cache key with database-agnostic prefix.
const PROTO_HTTP
Definition: Defines.php:219
$wgDebugLogPrefix
Prefix for debug log lines.
wfArrayInsertAfter(array $array, array $insert, $after)
Insert array into another array after the specified KEY
$wgMemoryLimit
The minimum amount of memory that MediaWiki "needs"; MediaWiki will try to raise PHP&#39;s memory limit i...
$wgDiff3
Path to the GNU diff3 utility.
wfAssembleUrl( $urlParts)
This function will reassemble a URL parsed with wfParseURL.
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
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...
wfSplitWikiID( $wiki)
Split a wiki ID into DB name and table prefix.
wfGetLBFactory()
Get the load balancer factory object.
const PROTO_CANONICAL
Definition: Defines.php:223
wfRandom()
Get a random decimal value in the domain of [0, 1), in a way not likely to give duplicate values for ...
$lines
Definition: router.php:61
wfReadOnlyReason()
Check if the site is in read-only mode and return the message if so.
wfExpandIRI( $url)
Take a URL, make sure it&#39;s expanded to fully qualified, and replace any encoded non-ASCII Unicode cha...
$wgScriptPath
The path we should point to.
wfMkdirParents( $dir, $mode=null, $caller=null)
Make directory, and make all parent directories if they don&#39;t exist.
static emitBufferedStatsdData(IBufferingStatsdDataFactory $stats, Config $config)
Send out any buffered statsd data according to sampling rules.
Definition: MediaWiki.php:930
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not...
wfGetMainCache()
Get the main cache object.
static pages()
Definition: SiteStats.php:112
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
$line
Definition: cdb.php:59
global $wgCommandLineMode
wfDebugBacktrace( $limit=0)
Safety wrapper for debug_backtrace().
$wgDBprefix
Table name prefix; this should be alphanumeric and not contain spaces nor hyphens.
wfShellExecWithStderr( $cmd, &$retval=null, $environ=[], $limits=[])
Execute a shell command, returning both stdout and stderr.
wfRestoreWarnings()
static makeIndexes( $url)
Converts a URL into a format for el_index.
Definition: LinkFilter.php:171
$wgStyleDirectory
Filesystem stylesheets directory.
wfMemoryLimit()
Set PHP&#39;s memory limit to the larger of php.ini or $wgMemoryLimit.
wfClearOutputBuffers()
More legible than passing a &#39;false&#39; parameter to wfResetOutputBuffers():
controlled by the following MediaWiki still creates a BagOStuff but calls it to it are no ops If the cache daemon can t be it should also disable itself fairly $wgDBname
Definition: memcached.txt:93
$wgCanonicalServer
Canonical URL of the server, to use in IRC feeds and notification e-mails.
wfTransactionalTimeLimit()
Set PHP&#39;s time limit to the larger of php.ini or $wgTransactionalTimeLimit.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
Definition: hooks.txt:2626
static deprecated( $function, $version=false, $component=false, $callerOffset=2)
Show a warning that $function is deprecated.
Definition: MWDebug.php:193
wfStringToBool( $val)
Convert string value to boolean, when the following are interpreted as true:
MediaWiki Logger LoggerFactory implements a PSR [0] compatible message logging system Named Psr Log LoggerInterface instances can be obtained from the MediaWiki Logger LoggerFactory::getInstance() static method. MediaWiki\Logger\LoggerFactory expects a class implementing the MediaWiki\Logger\Spi interface to act as a factory for new Psr\Log\LoggerInterface instances. The "Spi" in MediaWiki\Logger\Spi stands for "service provider interface". An SPI is an API intended to be implemented or extended by a third party. This software design pattern is intended to enable framework extension and replaceable components. It is specifically used in the MediaWiki\Logger\LoggerFactory service to allow alternate PSR-3 logging implementations to be easily integrated with MediaWiki. The service provider interface allows the backend logging library to be implemented in multiple ways. The $wgMWLoggerDefaultSpi global provides the classname of the default MediaWiki\Logger\Spi implementation to be loaded at runtime. This can either be the name of a class implementing the MediaWiki\Logger\Spi with a zero argument const ructor or a callable that will return an MediaWiki\Logger\Spi instance. Alternately the MediaWiki\Logger\LoggerFactory MediaWiki Logger LoggerFactory
Definition: logger.txt:5
wfArrayFilterByKey(array $arr, callable $callback)
wfEscapeShellArg(... $args)
Version of escapeshellarg() that works better on Windows.
wfUnpack( $format, $data, $length=false)
Wrapper around php&#39;s unpack.
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:634
wfMemcKey(... $args)
Make a cache key for the local wiki.
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:276
static getLocalServerInstance( $fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
if(! $wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:747
$wgServer
URL of the server.
wfRelativePath( $path, $from)
Generate a relative path name to the given file.
$wgOut
Definition: Setup.php:907
wfCanIPUseHTTPS( $ip)
Determine whether the client at a given source IP is likely to be able to access the wiki via HTTPS...
wfBacktrace( $raw=null)
Get a debug backtrace as a string.
wfArrayDiff2( $a, $b)
Like array_diff( $a, $b ) except that it works with two-dimensional arrays.
wfResetSessionID()
Reset the session id.
wfMessage( $key,... $params)
This is the function for getting translated interface messages.
wfGetNull()
Get a platform-independent path to the null file, e.g.
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable modifiable after all normalizations have been except for the $wgMaxImageArea check set to true or false to override the $wgMaxImageArea check result gives extension the possibility to transform it themselves $handler
Definition: hooks.txt:785
wfBCP47( $code)
Get the normalised IETF language tag See unit test for examples.
wfIniGetBool( $setting)
Safety wrapper around ini_get() for boolean settings.
wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed)
Appends to second array if $value differs from that in $default.
wfArrayPlus2d(array $baseArray, array $newValues)
Merges two (possibly) 2 dimensional arrays into the target array ($baseArray).
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition: File.php:51
wfAcceptToPrefs( $accept, $def=' */*')
Converts an Accept-* header into an array mapping string values to quality factors.
$ext
Definition: router.php:55
$wgResponsiveImages
Generate and use thumbnails suitable for screens with 1.5 and 2.0 pixel densities.
wfLoadExtension( $ext, $path=null)
Load an extension.
$wgDiff
Path to the GNU diff utility.
$wgLoadScript
The URL path to load.php.
wfThumbIsStandard(File $file, array $params)
Returns true if these thumbnail parameters match one that MediaWiki requests from file description pa...
$wgDirectoryMode
Default value for chmoding of new directories.
wfGetLB( $wiki=false)
Get a load balancer object.
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2626
wfArrayDiff2_cmp( $a, $b)
static users()
Definition: SiteStats.php:121
static bcp47( $code)
Get the normalised IETF language tag See unit test for examples.
wfShorthandToInteger( $string='', $default=-1)
Converts shorthand byte notation to integer form.
return true to allow those checks to and false if checking is done & $user
Definition: hooks.txt:1487
static run( $event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:200
wfObjectToArray( $objOrArray, $recursive=true)
Recursively converts the parameter (an object) to an array with the same data.
wfGetScriptUrl()
Get the script URL.
$matches
$wgShowHostnames
Expose backend server host names through the API and various HTML comments.
$wgTransactionalTimeLimit
The minimum amount of time that MediaWiki needs for "slow" write request, particularly ones with mult...
static newFromText( $text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:280