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 
27 use Liuggio\StatsdClient\Sender\SocketSender;
30 
31 // Hide compatibility functions from Doxygen
33 
41 // hash_equals function only exists in PHP >= 5.6.0
42 // http://php.net/hash_equals
43 if ( !function_exists( 'hash_equals' ) ) {
69  function hash_equals( $known_string, $user_string ) {
70  // Strict type checking as in PHP's native implementation
71  if ( !is_string( $known_string ) ) {
72  trigger_error( 'hash_equals(): Expected known_string to be a string, ' .
73  gettype( $known_string ) . ' given', E_USER_WARNING );
74 
75  return false;
76  }
77 
78  if ( !is_string( $user_string ) ) {
79  trigger_error( 'hash_equals(): Expected user_string to be a string, ' .
80  gettype( $user_string ) . ' given', E_USER_WARNING );
81 
82  return false;
83  }
84 
85  $known_string_len = strlen( $known_string );
86  if ( $known_string_len !== strlen( $user_string ) ) {
87  return false;
88  }
89 
90  $result = 0;
91  for ( $i = 0; $i < $known_string_len; $i++ ) {
92  $result |= ord( $known_string[$i] ) ^ ord( $user_string[$i] );
93  }
94 
95  return ( $result === 0 );
96  }
97 }
99 
110 function wfLoadExtension( $ext, $path = null ) {
111  if ( !$path ) {
113  $path = "$wgExtensionDirectory/$ext/extension.json";
114  }
116 }
117 
131 function wfLoadExtensions( array $exts ) {
133  $registry = ExtensionRegistry::getInstance();
134  foreach ( $exts as $ext ) {
135  $registry->queue( "$wgExtensionDirectory/$ext/extension.json" );
136  }
137 }
138 
147 function wfLoadSkin( $skin, $path = null ) {
148  if ( !$path ) {
150  $path = "$wgStyleDirectory/$skin/skin.json";
151  }
153 }
154 
162 function wfLoadSkins( array $skins ) {
164  $registry = ExtensionRegistry::getInstance();
165  foreach ( $skins as $skin ) {
166  $registry->queue( "$wgStyleDirectory/$skin/skin.json" );
167  }
168 }
169 
176 function wfArrayDiff2( $a, $b ) {
177  return array_udiff( $a, $b, 'wfArrayDiff2_cmp' );
178 }
179 
185 function wfArrayDiff2_cmp( $a, $b ) {
186  if ( is_string( $a ) && is_string( $b ) ) {
187  return strcmp( $a, $b );
188  } elseif ( count( $a ) !== count( $b ) ) {
189  return count( $a ) < count( $b ) ? -1 : 1;
190  } else {
191  reset( $a );
192  reset( $b );
193  while ( ( list( , $valueA ) = each( $a ) ) && ( list( , $valueB ) = each( $b ) ) ) {
194  $cmp = strcmp( $valueA, $valueB );
195  if ( $cmp !== 0 ) {
196  return $cmp;
197  }
198  }
199  return 0;
200  }
201 }
202 
212 function wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed ) {
213  if ( is_null( $changed ) ) {
214  throw new MWException( 'GlobalFunctions::wfAppendToArrayIfNotDefault got null' );
215  }
216  if ( $default[$key] !== $value ) {
217  $changed[$key] = $value;
218  }
219 }
220 
240 function wfMergeErrorArrays( /*...*/ ) {
241  $args = func_get_args();
242  $out = [];
243  foreach ( $args as $errors ) {
244  foreach ( $errors as $params ) {
245  $originalParams = $params;
246  if ( $params[0] instanceof MessageSpecifier ) {
247  $msg = $params[0];
248  $params = array_merge( [ $msg->getKey() ], $msg->getParams() );
249  }
250  # @todo FIXME: Sometimes get nested arrays for $params,
251  # which leads to E_NOTICEs
252  $spec = implode( "\t", $params );
253  $out[$spec] = $originalParams;
254  }
255  }
256  return array_values( $out );
257 }
258 
267 function wfArrayInsertAfter( array $array, array $insert, $after ) {
268  // Find the offset of the element to insert after.
269  $keys = array_keys( $array );
270  $offsetByKey = array_flip( $keys );
271 
272  $offset = $offsetByKey[$after];
273 
274  // Insert at the specified offset
275  $before = array_slice( $array, 0, $offset + 1, true );
276  $after = array_slice( $array, $offset + 1, count( $array ) - $offset, true );
277 
278  $output = $before + $insert + $after;
279 
280  return $output;
281 }
282 
290 function wfObjectToArray( $objOrArray, $recursive = true ) {
291  $array = [];
292  if ( is_object( $objOrArray ) ) {
293  $objOrArray = get_object_vars( $objOrArray );
294  }
295  foreach ( $objOrArray as $key => $value ) {
296  if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) {
298  }
299 
300  $array[$key] = $value;
301  }
302 
303  return $array;
304 }
305 
316 function wfRandom() {
317  // The maximum random value is "only" 2^31-1, so get two random
318  // values to reduce the chance of dupes
319  $max = mt_getrandmax() + 1;
320  $rand = number_format( ( mt_rand() * $max + mt_rand() ) / $max / $max, 12, '.', '' );
321  return $rand;
322 }
323 
334 function wfRandomString( $length = 32 ) {
335  $str = '';
336  for ( $n = 0; $n < $length; $n += 7 ) {
337  $str .= sprintf( '%07x', mt_rand() & 0xfffffff );
338  }
339  return substr( $str, 0, $length );
340 }
341 
369 function wfUrlencode( $s ) {
370  static $needle;
371 
372  if ( is_null( $s ) ) {
373  $needle = null;
374  return '';
375  }
376 
377  if ( is_null( $needle ) ) {
378  $needle = [ '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F', '%7E' ];
379  if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) ||
380  ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false )
381  ) {
382  $needle[] = '%3A';
383  }
384  }
385 
386  $s = urlencode( $s );
387  $s = str_ireplace(
388  $needle,
389  [ ';', '@', '$', '!', '*', '(', ')', ',', '/', '~', ':' ],
390  $s
391  );
392 
393  return $s;
394 }
395 
406 function wfArrayToCgi( $array1, $array2 = null, $prefix = '' ) {
407  if ( !is_null( $array2 ) ) {
408  $array1 = $array1 + $array2;
409  }
410 
411  $cgi = '';
412  foreach ( $array1 as $key => $value ) {
413  if ( !is_null( $value ) && $value !== false ) {
414  if ( $cgi != '' ) {
415  $cgi .= '&';
416  }
417  if ( $prefix !== '' ) {
418  $key = $prefix . "[$key]";
419  }
420  if ( is_array( $value ) ) {
421  $firstTime = true;
422  foreach ( $value as $k => $v ) {
423  $cgi .= $firstTime ? '' : '&';
424  if ( is_array( $v ) ) {
425  $cgi .= wfArrayToCgi( $v, null, $key . "[$k]" );
426  } else {
427  $cgi .= urlencode( $key . "[$k]" ) . '=' . urlencode( $v );
428  }
429  $firstTime = false;
430  }
431  } else {
432  if ( is_object( $value ) ) {
433  $value = $value->__toString();
434  }
435  $cgi .= urlencode( $key ) . '=' . urlencode( $value );
436  }
437  }
438  }
439  return $cgi;
440 }
441 
451 function wfCgiToArray( $query ) {
452  if ( isset( $query[0] ) && $query[0] == '?' ) {
453  $query = substr( $query, 1 );
454  }
455  $bits = explode( '&', $query );
456  $ret = [];
457  foreach ( $bits as $bit ) {
458  if ( $bit === '' ) {
459  continue;
460  }
461  if ( strpos( $bit, '=' ) === false ) {
462  // Pieces like &qwerty become 'qwerty' => '' (at least this is what php does)
463  $key = $bit;
464  $value = '';
465  } else {
466  list( $key, $value ) = explode( '=', $bit );
467  }
468  $key = urldecode( $key );
469  $value = urldecode( $value );
470  if ( strpos( $key, '[' ) !== false ) {
471  $keys = array_reverse( explode( '[', $key ) );
472  $key = array_pop( $keys );
473  $temp = $value;
474  foreach ( $keys as $k ) {
475  $k = substr( $k, 0, -1 );
476  $temp = [ $k => $temp ];
477  }
478  if ( isset( $ret[$key] ) ) {
479  $ret[$key] = array_merge( $ret[$key], $temp );
480  } else {
481  $ret[$key] = $temp;
482  }
483  } else {
484  $ret[$key] = $value;
485  }
486  }
487  return $ret;
488 }
489 
498 function wfAppendQuery( $url, $query ) {
499  if ( is_array( $query ) ) {
501  }
502  if ( $query != '' ) {
503  // Remove the fragment, if there is one
504  $fragment = false;
505  $hashPos = strpos( $url, '#' );
506  if ( $hashPos !== false ) {
507  $fragment = substr( $url, $hashPos );
508  $url = substr( $url, 0, $hashPos );
509  }
510 
511  // Add parameter
512  if ( false === strpos( $url, '?' ) ) {
513  $url .= '?';
514  } else {
515  $url .= '&';
516  }
517  $url .= $query;
518 
519  // Put the fragment back
520  if ( $fragment !== false ) {
521  $url .= $fragment;
522  }
523  }
524  return $url;
525 }
526 
550 function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) {
552  $wgHttpsPort;
553  if ( $defaultProto === PROTO_CANONICAL ) {
554  $serverUrl = $wgCanonicalServer;
555  } elseif ( $defaultProto === PROTO_INTERNAL && $wgInternalServer !== false ) {
556  // Make $wgInternalServer fall back to $wgServer if not set
557  $serverUrl = $wgInternalServer;
558  } else {
559  $serverUrl = $wgServer;
560  if ( $defaultProto === PROTO_CURRENT ) {
561  $defaultProto = $wgRequest->getProtocol() . '://';
562  }
563  }
564 
565  // Analyze $serverUrl to obtain its protocol
566  $bits = wfParseUrl( $serverUrl );
567  $serverHasProto = $bits && $bits['scheme'] != '';
568 
569  if ( $defaultProto === PROTO_CANONICAL || $defaultProto === PROTO_INTERNAL ) {
570  if ( $serverHasProto ) {
571  $defaultProto = $bits['scheme'] . '://';
572  } else {
573  // $wgCanonicalServer or $wgInternalServer doesn't have a protocol.
574  // This really isn't supposed to happen. Fall back to HTTP in this
575  // ridiculous case.
576  $defaultProto = PROTO_HTTP;
577  }
578  }
579 
580  $defaultProtoWithoutSlashes = substr( $defaultProto, 0, -2 );
581 
582  if ( substr( $url, 0, 2 ) == '//' ) {
583  $url = $defaultProtoWithoutSlashes . $url;
584  } elseif ( substr( $url, 0, 1 ) == '/' ) {
585  // If $serverUrl is protocol-relative, prepend $defaultProtoWithoutSlashes,
586  // otherwise leave it alone.
587  $url = ( $serverHasProto ? '' : $defaultProtoWithoutSlashes ) . $serverUrl . $url;
588  }
589 
590  $bits = wfParseUrl( $url );
591 
592  // ensure proper port for HTTPS arrives in URL
593  // https://phabricator.wikimedia.org/T67184
594  if ( $defaultProto === PROTO_HTTPS && $wgHttpsPort != 443 ) {
595  $bits['port'] = $wgHttpsPort;
596  }
597 
598  if ( $bits && isset( $bits['path'] ) ) {
599  $bits['path'] = wfRemoveDotSegments( $bits['path'] );
600  return wfAssembleUrl( $bits );
601  } elseif ( $bits ) {
602  # No path to expand
603  return $url;
604  } elseif ( substr( $url, 0, 1 ) != '/' ) {
605  # URL is a relative path
606  return wfRemoveDotSegments( $url );
607  }
608 
609  # Expanded URL is not valid.
610  return false;
611 }
612 
626 function wfAssembleUrl( $urlParts ) {
627  $result = '';
628 
629  if ( isset( $urlParts['delimiter'] ) ) {
630  if ( isset( $urlParts['scheme'] ) ) {
631  $result .= $urlParts['scheme'];
632  }
633 
634  $result .= $urlParts['delimiter'];
635  }
636 
637  if ( isset( $urlParts['host'] ) ) {
638  if ( isset( $urlParts['user'] ) ) {
639  $result .= $urlParts['user'];
640  if ( isset( $urlParts['pass'] ) ) {
641  $result .= ':' . $urlParts['pass'];
642  }
643  $result .= '@';
644  }
645 
646  $result .= $urlParts['host'];
647 
648  if ( isset( $urlParts['port'] ) ) {
649  $result .= ':' . $urlParts['port'];
650  }
651  }
652 
653  if ( isset( $urlParts['path'] ) ) {
654  $result .= $urlParts['path'];
655  }
656 
657  if ( isset( $urlParts['query'] ) ) {
658  $result .= '?' . $urlParts['query'];
659  }
660 
661  if ( isset( $urlParts['fragment'] ) ) {
662  $result .= '#' . $urlParts['fragment'];
663  }
664 
665  return $result;
666 }
667 
678 function wfRemoveDotSegments( $urlPath ) {
679  $output = '';
680  $inputOffset = 0;
681  $inputLength = strlen( $urlPath );
682 
683  while ( $inputOffset < $inputLength ) {
684  $prefixLengthOne = substr( $urlPath, $inputOffset, 1 );
685  $prefixLengthTwo = substr( $urlPath, $inputOffset, 2 );
686  $prefixLengthThree = substr( $urlPath, $inputOffset, 3 );
687  $prefixLengthFour = substr( $urlPath, $inputOffset, 4 );
688  $trimOutput = false;
689 
690  if ( $prefixLengthTwo == './' ) {
691  # Step A, remove leading "./"
692  $inputOffset += 2;
693  } elseif ( $prefixLengthThree == '../' ) {
694  # Step A, remove leading "../"
695  $inputOffset += 3;
696  } elseif ( ( $prefixLengthTwo == '/.' ) && ( $inputOffset + 2 == $inputLength ) ) {
697  # Step B, replace leading "/.$" with "/"
698  $inputOffset += 1;
699  $urlPath[$inputOffset] = '/';
700  } elseif ( $prefixLengthThree == '/./' ) {
701  # Step B, replace leading "/./" with "/"
702  $inputOffset += 2;
703  } elseif ( $prefixLengthThree == '/..' && ( $inputOffset + 3 == $inputLength ) ) {
704  # Step C, replace leading "/..$" with "/" and
705  # remove last path component in output
706  $inputOffset += 2;
707  $urlPath[$inputOffset] = '/';
708  $trimOutput = true;
709  } elseif ( $prefixLengthFour == '/../' ) {
710  # Step C, replace leading "/../" with "/" and
711  # remove last path component in output
712  $inputOffset += 3;
713  $trimOutput = true;
714  } elseif ( ( $prefixLengthOne == '.' ) && ( $inputOffset + 1 == $inputLength ) ) {
715  # Step D, remove "^.$"
716  $inputOffset += 1;
717  } elseif ( ( $prefixLengthTwo == '..' ) && ( $inputOffset + 2 == $inputLength ) ) {
718  # Step D, remove "^..$"
719  $inputOffset += 2;
720  } else {
721  # Step E, move leading path segment to output
722  if ( $prefixLengthOne == '/' ) {
723  $slashPos = strpos( $urlPath, '/', $inputOffset + 1 );
724  } else {
725  $slashPos = strpos( $urlPath, '/', $inputOffset );
726  }
727  if ( $slashPos === false ) {
728  $output .= substr( $urlPath, $inputOffset );
729  $inputOffset = $inputLength;
730  } else {
731  $output .= substr( $urlPath, $inputOffset, $slashPos - $inputOffset );
732  $inputOffset += $slashPos - $inputOffset;
733  }
734  }
735 
736  if ( $trimOutput ) {
737  $slashPos = strrpos( $output, '/' );
738  if ( $slashPos === false ) {
739  $output = '';
740  } else {
741  $output = substr( $output, 0, $slashPos );
742  }
743  }
744  }
745 
746  return $output;
747 }
748 
756 function wfUrlProtocols( $includeProtocolRelative = true ) {
757  global $wgUrlProtocols;
758 
759  // Cache return values separately based on $includeProtocolRelative
760  static $withProtRel = null, $withoutProtRel = null;
761  $cachedValue = $includeProtocolRelative ? $withProtRel : $withoutProtRel;
762  if ( !is_null( $cachedValue ) ) {
763  return $cachedValue;
764  }
765 
766  // Support old-style $wgUrlProtocols strings, for backwards compatibility
767  // with LocalSettings files from 1.5
768  if ( is_array( $wgUrlProtocols ) ) {
769  $protocols = [];
770  foreach ( $wgUrlProtocols as $protocol ) {
771  // Filter out '//' if !$includeProtocolRelative
772  if ( $includeProtocolRelative || $protocol !== '//' ) {
773  $protocols[] = preg_quote( $protocol, '/' );
774  }
775  }
776 
777  $retval = implode( '|', $protocols );
778  } else {
779  // Ignore $includeProtocolRelative in this case
780  // This case exists for pre-1.6 compatibility, and we can safely assume
781  // that '//' won't appear in a pre-1.6 config because protocol-relative
782  // URLs weren't supported until 1.18
783  $retval = $wgUrlProtocols;
784  }
785 
786  // Cache return value
787  if ( $includeProtocolRelative ) {
788  $withProtRel = $retval;
789  } else {
790  $withoutProtRel = $retval;
791  }
792  return $retval;
793 }
794 
802  return wfUrlProtocols( false );
803 }
804 
816 function wfParseUrl( $url ) {
817  global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
818 
819  // Protocol-relative URLs are handled really badly by parse_url(). It's so
820  // bad that the easiest way to handle them is to just prepend 'http:' and
821  // strip the protocol out later.
822  $wasRelative = substr( $url, 0, 2 ) == '//';
823  if ( $wasRelative ) {
824  $url = "http:$url";
825  }
826  MediaWiki\suppressWarnings();
827  $bits = parse_url( $url );
828  MediaWiki\restoreWarnings();
829  // parse_url() returns an array without scheme for some invalid URLs, e.g.
830  // parse_url("%0Ahttp://example.com") == [ 'host' => '%0Ahttp', 'path' => 'example.com' ]
831  if ( !$bits || !isset( $bits['scheme'] ) ) {
832  return false;
833  }
834 
835  // parse_url() incorrectly handles schemes case-sensitively. Convert it to lowercase.
836  $bits['scheme'] = strtolower( $bits['scheme'] );
837 
838  // most of the protocols are followed by ://, but mailto: and sometimes news: not, check for it
839  if ( in_array( $bits['scheme'] . '://', $wgUrlProtocols ) ) {
840  $bits['delimiter'] = '://';
841  } elseif ( in_array( $bits['scheme'] . ':', $wgUrlProtocols ) ) {
842  $bits['delimiter'] = ':';
843  // parse_url detects for news: and mailto: the host part of an url as path
844  // We have to correct this wrong detection
845  if ( isset( $bits['path'] ) ) {
846  $bits['host'] = $bits['path'];
847  $bits['path'] = '';
848  }
849  } else {
850  return false;
851  }
852 
853  /* Provide an empty host for eg. file:/// urls (see bug 28627) */
854  if ( !isset( $bits['host'] ) ) {
855  $bits['host'] = '';
856 
857  // bug 45069
858  if ( isset( $bits['path'] ) ) {
859  /* parse_url loses the third / for file:///c:/ urls (but not on variants) */
860  if ( substr( $bits['path'], 0, 1 ) !== '/' ) {
861  $bits['path'] = '/' . $bits['path'];
862  }
863  } else {
864  $bits['path'] = '';
865  }
866  }
867 
868  // If the URL was protocol-relative, fix scheme and delimiter
869  if ( $wasRelative ) {
870  $bits['scheme'] = '';
871  $bits['delimiter'] = '//';
872  }
873  return $bits;
874 }
875 
886 function wfExpandIRI( $url ) {
887  return preg_replace_callback(
888  '/((?:%[89A-F][0-9A-F])+)/i',
889  'wfExpandIRI_callback',
890  wfExpandUrl( $url )
891  );
892 }
893 
900  return urldecode( $matches[1] );
901 }
902 
909 function wfMakeUrlIndexes( $url ) {
910  $bits = wfParseUrl( $url );
911 
912  // Reverse the labels in the hostname, convert to lower case
913  // For emails reverse domainpart only
914  if ( $bits['scheme'] == 'mailto' ) {
915  $mailparts = explode( '@', $bits['host'], 2 );
916  if ( count( $mailparts ) === 2 ) {
917  $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) );
918  } else {
919  // No domain specified, don't mangle it
920  $domainpart = '';
921  }
922  $reversedHost = $domainpart . '@' . $mailparts[0];
923  } else {
924  $reversedHost = strtolower( implode( '.', array_reverse( explode( '.', $bits['host'] ) ) ) );
925  }
926  // Add an extra dot to the end
927  // Why? Is it in wrong place in mailto links?
928  if ( substr( $reversedHost, -1, 1 ) !== '.' ) {
929  $reversedHost .= '.';
930  }
931  // Reconstruct the pseudo-URL
932  $prot = $bits['scheme'];
933  $index = $prot . $bits['delimiter'] . $reversedHost;
934  // Leave out user and password. Add the port, path, query and fragment
935  if ( isset( $bits['port'] ) ) {
936  $index .= ':' . $bits['port'];
937  }
938  if ( isset( $bits['path'] ) ) {
939  $index .= $bits['path'];
940  } else {
941  $index .= '/';
942  }
943  if ( isset( $bits['query'] ) ) {
944  $index .= '?' . $bits['query'];
945  }
946  if ( isset( $bits['fragment'] ) ) {
947  $index .= '#' . $bits['fragment'];
948  }
949 
950  if ( $prot == '' ) {
951  return [ "http:$index", "https:$index" ];
952  } else {
953  return [ $index ];
954  }
955 }
956 
963 function wfMatchesDomainList( $url, $domains ) {
964  $bits = wfParseUrl( $url );
965  if ( is_array( $bits ) && isset( $bits['host'] ) ) {
966  $host = '.' . $bits['host'];
967  foreach ( (array)$domains as $domain ) {
968  $domain = '.' . $domain;
969  if ( substr( $host, -strlen( $domain ) ) === $domain ) {
970  return true;
971  }
972  }
973  }
974  return false;
975 }
976 
997 function wfDebug( $text, $dest = 'all', array $context = [] ) {
1000 
1001  if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
1002  return;
1003  }
1004 
1005  $text = trim( $text );
1006 
1007  if ( $wgDebugTimestamps ) {
1008  $context['seconds_elapsed'] = sprintf(
1009  '%6.4f',
1010  microtime( true ) - $wgRequestTime
1011  );
1012  $context['memory_used'] = sprintf(
1013  '%5.1fM',
1014  ( memory_get_usage( true ) / ( 1024 * 1024 ) )
1015  );
1016  }
1017 
1018  if ( $wgDebugLogPrefix !== '' ) {
1019  $context['prefix'] = $wgDebugLogPrefix;
1020  }
1021  $context['private'] = ( $dest === false || $dest === 'private' );
1022 
1023  $logger = LoggerFactory::getInstance( 'wfDebug' );
1024  $logger->debug( $text, $context );
1025 }
1026 
1031 function wfIsDebugRawPage() {
1032  static $cache;
1033  if ( $cache !== null ) {
1034  return $cache;
1035  }
1036  # Check for raw action using $_GET not $wgRequest, since the latter might not be initialised yet
1037  if ( ( isset( $_GET['action'] ) && $_GET['action'] == 'raw' )
1038  || (
1039  isset( $_SERVER['SCRIPT_NAME'] )
1040  && substr( $_SERVER['SCRIPT_NAME'], -8 ) == 'load.php'
1041  )
1042  ) {
1043  $cache = true;
1044  } else {
1045  $cache = false;
1046  }
1047  return $cache;
1048 }
1049 
1055 function wfDebugMem( $exact = false ) {
1056  $mem = memory_get_usage();
1057  if ( !$exact ) {
1058  $mem = floor( $mem / 1024 ) . ' KiB';
1059  } else {
1060  $mem .= ' B';
1061  }
1062  wfDebug( "Memory usage: $mem\n" );
1063 }
1064 
1090 function wfDebugLog(
1091  $logGroup, $text, $dest = 'all', array $context = []
1092 ) {
1093  $text = trim( $text );
1094 
1095  $logger = LoggerFactory::getInstance( $logGroup );
1096  $context['private'] = ( $dest === false || $dest === 'private' );
1097  $logger->info( $text, $context );
1098 }
1099 
1108 function wfLogDBError( $text, array $context = [] ) {
1109  $logger = LoggerFactory::getInstance( 'wfLogDBError' );
1110  $logger->error( trim( $text ), $context );
1111 }
1112 
1126 function wfDeprecated( $function, $version = false, $component = false, $callerOffset = 2 ) {
1127  MWDebug::deprecated( $function, $version, $component, $callerOffset + 1 );
1128 }
1129 
1140 function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) {
1141  MWDebug::warning( $msg, $callerOffset + 1, $level, 'auto' );
1142 }
1143 
1153 function wfLogWarning( $msg, $callerOffset = 1, $level = E_USER_WARNING ) {
1154  MWDebug::warning( $msg, $callerOffset + 1, $level, 'production' );
1155 }
1156 
1170 function wfErrorLog( $text, $file, array $context = [] ) {
1171  wfDeprecated( __METHOD__, '1.25' );
1172  $logger = LoggerFactory::getInstance( 'wfErrorLog' );
1173  $context['destination'] = $file;
1174  $logger->info( trim( $text ), $context );
1175 }
1176 
1182 
1184  $request = $context->getRequest();
1185 
1186  $profiler = Profiler::instance();
1187  $profiler->setContext( $context );
1188  $profiler->logData();
1189 
1190  $config = $context->getConfig();
1191  if ( $config->get( 'StatsdServer' ) ) {
1192  try {
1193  $statsdServer = explode( ':', $config->get( 'StatsdServer' ) );
1194  $statsdHost = $statsdServer[0];
1195  $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
1196  $statsdSender = new SocketSender( $statsdHost, $statsdPort );
1197  $statsdClient = new SamplingStatsdClient( $statsdSender, true, false );
1198  $statsdClient->send( $context->getStats()->getBuffer() );
1199  } catch ( Exception $ex ) {
1201  }
1202  }
1203 
1204  # Profiling must actually be enabled...
1205  if ( $profiler instanceof ProfilerStub ) {
1206  return;
1207  }
1208 
1209  if ( isset( $wgDebugLogGroups['profileoutput'] )
1210  && $wgDebugLogGroups['profileoutput'] === false
1211  ) {
1212  // Explicitly disabled
1213  return;
1214  }
1215  if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
1216  return;
1217  }
1218 
1219  $ctx = [ 'elapsed' => $request->getElapsedTime() ];
1220  if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
1221  $ctx['forwarded_for'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
1222  }
1223  if ( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {
1224  $ctx['client_ip'] = $_SERVER['HTTP_CLIENT_IP'];
1225  }
1226  if ( !empty( $_SERVER['HTTP_FROM'] ) ) {
1227  $ctx['from'] = $_SERVER['HTTP_FROM'];
1228  }
1229  if ( isset( $ctx['forwarded_for'] ) ||
1230  isset( $ctx['client_ip'] ) ||
1231  isset( $ctx['from'] ) ) {
1232  $ctx['proxy'] = $_SERVER['REMOTE_ADDR'];
1233  }
1234 
1235  // Don't load $wgUser at this late stage just for statistics purposes
1236  // @todo FIXME: We can detect some anons even if it is not loaded.
1237  // See User::getId()
1238  $user = $context->getUser();
1239  $ctx['anon'] = $user->isItemLoaded( 'id' ) && $user->isAnon();
1240 
1241  // Command line script uses a FauxRequest object which does not have
1242  // any knowledge about an URL and throw an exception instead.
1243  try {
1244  $ctx['url'] = urldecode( $request->getRequestURL() );
1245  } catch ( Exception $ignored ) {
1246  // no-op
1247  }
1248 
1249  $ctx['output'] = $profiler->getOutput();
1250 
1251  $log = LoggerFactory::getInstance( 'profileoutput' );
1252  $log->info( "Elapsed: {elapsed}; URL: <{url}>\n{output}", $ctx );
1253 }
1254 
1262 function wfIncrStats( $key, $count = 1 ) {
1263  $stats = RequestContext::getMain()->getStats();
1264  $stats->updateCount( $key, $count );
1265 }
1266 
1272 function wfReadOnly() {
1273  return wfReadOnlyReason() !== false;
1274 }
1275 
1284 function wfReadOnlyReason() {
1285  $readOnly = wfConfiguredReadOnlyReason();
1286  if ( $readOnly !== false ) {
1287  return $readOnly;
1288  }
1289 
1290  static $lbReadOnly = null;
1291  if ( $lbReadOnly === null ) {
1292  // Callers use this method to be aware that data presented to a user
1293  // may be very stale and thus allowing submissions can be problematic.
1294  $lbReadOnly = wfGetLB()->getReadOnlyReason();
1295  }
1296 
1297  return $lbReadOnly;
1298 }
1299 
1308 
1309  if ( $wgReadOnly === null ) {
1310  // Set $wgReadOnly for faster access next time
1311  if ( is_file( $wgReadOnlyFile ) && filesize( $wgReadOnlyFile ) > 0 ) {
1312  $wgReadOnly = file_get_contents( $wgReadOnlyFile );
1313  } else {
1314  $wgReadOnly = false;
1315  }
1316  }
1317 
1318  return $wgReadOnly;
1319 }
1320 
1336 function wfGetLangObj( $langcode = false ) {
1337  # Identify which language to get or create a language object for.
1338  # Using is_object here due to Stub objects.
1339  if ( is_object( $langcode ) ) {
1340  # Great, we already have the object (hopefully)!
1341  return $langcode;
1342  }
1343 
1345  if ( $langcode === true || $langcode === $wgLanguageCode ) {
1346  # $langcode is the language code of the wikis content language object.
1347  # or it is a boolean and value is true
1348  return $wgContLang;
1349  }
1350 
1351  global $wgLang;
1352  if ( $langcode === false || $langcode === $wgLang->getCode() ) {
1353  # $langcode is the language code of user language object.
1354  # or it was a boolean and value is false
1355  return $wgLang;
1356  }
1357 
1358  $validCodes = array_keys( Language::fetchLanguageNames() );
1359  if ( in_array( $langcode, $validCodes ) ) {
1360  # $langcode corresponds to a valid language.
1361  return Language::factory( $langcode );
1362  }
1363 
1364  # $langcode is a string, but not a valid language code; use content language.
1365  wfDebug( "Invalid language code passed to wfGetLangObj, falling back to content language.\n" );
1366  return $wgContLang;
1367 }
1368 
1385 function wfMessage( $key /*...*/ ) {
1386  $params = func_get_args();
1387  array_shift( $params );
1388  if ( isset( $params[0] ) && is_array( $params[0] ) ) {
1389  $params = $params[0];
1390  }
1391  return new Message( $key, $params );
1392 }
1393 
1406 function wfMessageFallback( /*...*/ ) {
1407  $args = func_get_args();
1408  return call_user_func_array( 'Message::newFallbackSequence', $args );
1409 }
1410 
1419 function wfMsgReplaceArgs( $message, $args ) {
1420  # Fix windows line-endings
1421  # Some messages are split with explode("\n", $msg)
1422  $message = str_replace( "\r", '', $message );
1423 
1424  // Replace arguments
1425  if ( is_array( $args ) && $args ) {
1426  if ( is_array( $args[0] ) ) {
1427  $args = array_values( $args[0] );
1428  }
1429  $replacementKeys = [];
1430  foreach ( $args as $n => $param ) {
1431  $replacementKeys['$' . ( $n + 1 )] = $param;
1432  }
1433  $message = strtr( $message, $replacementKeys );
1434  }
1435 
1436  return $message;
1437 }
1438 
1446 function wfHostname() {
1447  static $host;
1448  if ( is_null( $host ) ) {
1449 
1450  # Hostname overriding
1452  if ( $wgOverrideHostname !== false ) {
1453  # Set static and skip any detection
1454  $host = $wgOverrideHostname;
1455  return $host;
1456  }
1457 
1458  if ( function_exists( 'posix_uname' ) ) {
1459  // This function not present on Windows
1460  $uname = posix_uname();
1461  } else {
1462  $uname = false;
1463  }
1464  if ( is_array( $uname ) && isset( $uname['nodename'] ) ) {
1465  $host = $uname['nodename'];
1466  } elseif ( getenv( 'COMPUTERNAME' ) ) {
1467  # Windows computer name
1468  $host = getenv( 'COMPUTERNAME' );
1469  } else {
1470  # This may be a virtual server.
1471  $host = $_SERVER['SERVER_NAME'];
1472  }
1473  }
1474  return $host;
1475 }
1476 
1486 function wfReportTime() {
1488 
1489  $responseTime = round( ( microtime( true ) - $wgRequestTime ) * 1000 );
1490  $reportVars = [ 'wgBackendResponseTime' => $responseTime ];
1491  if ( $wgShowHostnames ) {
1492  $reportVars['wgHostname'] = wfHostname();
1493  }
1494  return Skin::makeVariablesScript( $reportVars );
1495 }
1496 
1507 function wfDebugBacktrace( $limit = 0 ) {
1508  static $disabled = null;
1509 
1510  if ( is_null( $disabled ) ) {
1511  $disabled = !function_exists( 'debug_backtrace' );
1512  if ( $disabled ) {
1513  wfDebug( "debug_backtrace() is disabled\n" );
1514  }
1515  }
1516  if ( $disabled ) {
1517  return [];
1518  }
1519 
1520  if ( $limit ) {
1521  return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit + 1 ), 1 );
1522  } else {
1523  return array_slice( debug_backtrace(), 1 );
1524  }
1525 }
1526 
1535 function wfBacktrace( $raw = null ) {
1537 
1538  if ( $raw === null ) {
1539  $raw = $wgCommandLineMode;
1540  }
1541 
1542  if ( $raw ) {
1543  $frameFormat = "%s line %s calls %s()\n";
1544  $traceFormat = "%s";
1545  } else {
1546  $frameFormat = "<li>%s line %s calls %s()</li>\n";
1547  $traceFormat = "<ul>\n%s</ul>\n";
1548  }
1549 
1550  $frames = array_map( function ( $frame ) use ( $frameFormat ) {
1551  $file = !empty( $frame['file'] ) ? basename( $frame['file'] ) : '-';
1552  $line = isset( $frame['line'] ) ? $frame['line'] : '-';
1553  $call = $frame['function'];
1554  if ( !empty( $frame['class'] ) ) {
1555  $call = $frame['class'] . $frame['type'] . $call;
1556  }
1557  return sprintf( $frameFormat, $file, $line, $call );
1558  }, wfDebugBacktrace() );
1559 
1560  return sprintf( $traceFormat, implode( '', $frames ) );
1561 }
1562 
1572 function wfGetCaller( $level = 2 ) {
1573  $backtrace = wfDebugBacktrace( $level + 1 );
1574  if ( isset( $backtrace[$level] ) ) {
1575  return wfFormatStackFrame( $backtrace[$level] );
1576  } else {
1577  return 'unknown';
1578  }
1579 }
1580 
1588 function wfGetAllCallers( $limit = 3 ) {
1589  $trace = array_reverse( wfDebugBacktrace() );
1590  if ( !$limit || $limit > count( $trace ) - 1 ) {
1591  $limit = count( $trace ) - 1;
1592  }
1593  $trace = array_slice( $trace, -$limit - 1, $limit );
1594  return implode( '/', array_map( 'wfFormatStackFrame', $trace ) );
1595 }
1596 
1603 function wfFormatStackFrame( $frame ) {
1604  if ( !isset( $frame['function'] ) ) {
1605  return 'NO_FUNCTION_GIVEN';
1606  }
1607  return isset( $frame['class'] ) && isset( $frame['type'] ) ?
1608  $frame['class'] . $frame['type'] . $frame['function'] :
1609  $frame['function'];
1610 }
1611 
1612 /* Some generic result counters, pulled out of SearchEngine */
1613 
1621 function wfShowingResults( $offset, $limit ) {
1622  return wfMessage( 'showingresults' )->numParams( $limit, $offset + 1 )->parse();
1623 }
1624 
1632 function wfClientAcceptsGzip( $force = false ) {
1633  static $result = null;
1634  if ( $result === null || $force ) {
1635  $result = false;
1636  if ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) {
1637  # @todo FIXME: We may want to blacklist some broken browsers
1638  $m = [];
1639  if ( preg_match(
1640  '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/',
1641  $_SERVER['HTTP_ACCEPT_ENCODING'],
1642  $m
1643  )
1644  ) {
1645  if ( isset( $m[2] ) && ( $m[1] == 'q' ) && ( $m[2] == 0 ) ) {
1646  $result = false;
1647  return $result;
1648  }
1649  wfDebug( "wfClientAcceptsGzip: client accepts gzip.\n" );
1650  $result = true;
1651  }
1652  }
1653  }
1654  return $result;
1655 }
1656 
1666 function wfEscapeWikiText( $text ) {
1667  static $repl = null, $repl2 = null;
1668  if ( $repl === null ) {
1669  $repl = [
1670  '"' => '&#34;', '&' => '&#38;', "'" => '&#39;', '<' => '&#60;',
1671  '=' => '&#61;', '>' => '&#62;', '[' => '&#91;', ']' => '&#93;',
1672  '{' => '&#123;', '|' => '&#124;', '}' => '&#125;', ';' => '&#59;',
1673  "\n#" => "\n&#35;", "\r#" => "\r&#35;",
1674  "\n*" => "\n&#42;", "\r*" => "\r&#42;",
1675  "\n:" => "\n&#58;", "\r:" => "\r&#58;",
1676  "\n " => "\n&#32;", "\r " => "\r&#32;",
1677  "\n\n" => "\n&#10;", "\r\n" => "&#13;\n",
1678  "\n\r" => "\n&#13;", "\r\r" => "\r&#13;",
1679  "\n\t" => "\n&#9;", "\r\t" => "\r&#9;", // "\n\t\n" is treated like "\n\n"
1680  "\n----" => "\n&#45;---", "\r----" => "\r&#45;---",
1681  '__' => '_&#95;', '://' => '&#58;//',
1682  ];
1683 
1684  // We have to catch everything "\s" matches in PCRE
1685  foreach ( [ 'ISBN', 'RFC', 'PMID' ] as $magic ) {
1686  $repl["$magic "] = "$magic&#32;";
1687  $repl["$magic\t"] = "$magic&#9;";
1688  $repl["$magic\r"] = "$magic&#13;";
1689  $repl["$magic\n"] = "$magic&#10;";
1690  $repl["$magic\f"] = "$magic&#12;";
1691  }
1692 
1693  // And handle protocols that don't use "://"
1694  global $wgUrlProtocols;
1695  $repl2 = [];
1696  foreach ( $wgUrlProtocols as $prot ) {
1697  if ( substr( $prot, -1 ) === ':' ) {
1698  $repl2[] = preg_quote( substr( $prot, 0, -1 ), '/' );
1699  }
1700  }
1701  $repl2 = $repl2 ? '/\b(' . implode( '|', $repl2 ) . '):/i' : '/^(?!)/';
1702  }
1703  $text = substr( strtr( "\n$text", $repl ), 1 );
1704  $text = preg_replace( $repl2, '$1&#58;', $text );
1705  return $text;
1706 }
1707 
1718 function wfSetVar( &$dest, $source, $force = false ) {
1719  $temp = $dest;
1720  if ( !is_null( $source ) || $force ) {
1721  $dest = $source;
1722  }
1723  return $temp;
1724 }
1725 
1735 function wfSetBit( &$dest, $bit, $state = true ) {
1736  $temp = (bool)( $dest & $bit );
1737  if ( !is_null( $state ) ) {
1738  if ( $state ) {
1739  $dest |= $bit;
1740  } else {
1741  $dest &= ~$bit;
1742  }
1743  }
1744  return $temp;
1745 }
1746 
1753 function wfVarDump( $var ) {
1754  global $wgOut;
1755  $s = str_replace( "\n", "<br />\n", var_export( $var, true ) . "\n" );
1756  if ( headers_sent() || !isset( $wgOut ) || !is_object( $wgOut ) ) {
1757  print $s;
1758  } else {
1759  $wgOut->addHTML( $s );
1760  }
1761 }
1762 
1770 function wfHttpError( $code, $label, $desc ) {
1771  global $wgOut;
1773  if ( $wgOut ) {
1774  $wgOut->disable();
1775  $wgOut->sendCacheControl();
1776  }
1777 
1778  header( 'Content-type: text/html; charset=utf-8' );
1779  print '<!DOCTYPE html>' .
1780  '<html><head><title>' .
1781  htmlspecialchars( $label ) .
1782  '</title></head><body><h1>' .
1783  htmlspecialchars( $label ) .
1784  '</h1><p>' .
1785  nl2br( htmlspecialchars( $desc ) ) .
1786  "</p></body></html>\n";
1787 }
1788 
1806 function wfResetOutputBuffers( $resetGzipEncoding = true ) {
1807  if ( $resetGzipEncoding ) {
1808  // Suppress Content-Encoding and Content-Length
1809  // headers from 1.10+s wfOutputHandler
1811  $wgDisableOutputCompression = true;
1812  }
1813  while ( $status = ob_get_status() ) {
1814  if ( isset( $status['flags'] ) ) {
1815  $flags = PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_REMOVABLE;
1816  $deleteable = ( $status['flags'] & $flags ) === $flags;
1817  } elseif ( isset( $status['del'] ) ) {
1818  $deleteable = $status['del'];
1819  } else {
1820  // Guess that any PHP-internal setting can't be removed.
1821  $deleteable = $status['type'] !== 0; /* PHP_OUTPUT_HANDLER_INTERNAL */
1822  }
1823  if ( !$deleteable ) {
1824  // Give up, and hope the result doesn't break
1825  // output behavior.
1826  break;
1827  }
1828  if ( $status['name'] === 'MediaWikiTestCase::wfResetOutputBuffersBarrier' ) {
1829  // Unit testing barrier to prevent this function from breaking PHPUnit.
1830  break;
1831  }
1832  if ( !ob_end_clean() ) {
1833  // Could not remove output buffer handler; abort now
1834  // to avoid getting in some kind of infinite loop.
1835  break;
1836  }
1837  if ( $resetGzipEncoding ) {
1838  if ( $status['name'] == 'ob_gzhandler' ) {
1839  // Reset the 'Content-Encoding' field set by this handler
1840  // so we can start fresh.
1841  header_remove( 'Content-Encoding' );
1842  break;
1843  }
1844  }
1845  }
1846 }
1847 
1861  wfResetOutputBuffers( false );
1862 }
1863 
1872 function wfAcceptToPrefs( $accept, $def = '*/*' ) {
1873  # No arg means accept anything (per HTTP spec)
1874  if ( !$accept ) {
1875  return [ $def => 1.0 ];
1876  }
1877 
1878  $prefs = [];
1879 
1880  $parts = explode( ',', $accept );
1881 
1882  foreach ( $parts as $part ) {
1883  # @todo FIXME: Doesn't deal with params like 'text/html; level=1'
1884  $values = explode( ';', trim( $part ) );
1885  $match = [];
1886  if ( count( $values ) == 1 ) {
1887  $prefs[$values[0]] = 1.0;
1888  } elseif ( preg_match( '/q\s*=\s*(\d*\.\d+)/', $values[1], $match ) ) {
1889  $prefs[$values[0]] = floatval( $match[1] );
1890  }
1891  }
1892 
1893  return $prefs;
1894 }
1895 
1908 function mimeTypeMatch( $type, $avail ) {
1909  if ( array_key_exists( $type, $avail ) ) {
1910  return $type;
1911  } else {
1912  $mainType = explode( '/', $type )[0];
1913  if ( array_key_exists( "$mainType/*", $avail ) ) {
1914  return "$mainType/*";
1915  } elseif ( array_key_exists( '*/*', $avail ) ) {
1916  return '*/*';
1917  } else {
1918  return null;
1919  }
1920  }
1921 }
1922 
1936 function wfNegotiateType( $cprefs, $sprefs ) {
1937  $combine = [];
1938 
1939  foreach ( array_keys( $sprefs ) as $type ) {
1940  $subType = explode( '/', $type )[1];
1941  if ( $subType != '*' ) {
1942  $ckey = mimeTypeMatch( $type, $cprefs );
1943  if ( $ckey ) {
1944  $combine[$type] = $sprefs[$type] * $cprefs[$ckey];
1945  }
1946  }
1947  }
1948 
1949  foreach ( array_keys( $cprefs ) as $type ) {
1950  $subType = explode( '/', $type )[1];
1951  if ( $subType != '*' && !array_key_exists( $type, $sprefs ) ) {
1952  $skey = mimeTypeMatch( $type, $sprefs );
1953  if ( $skey ) {
1954  $combine[$type] = $sprefs[$skey] * $cprefs[$type];
1955  }
1956  }
1957  }
1958 
1959  $bestq = 0;
1960  $besttype = null;
1961 
1962  foreach ( array_keys( $combine ) as $type ) {
1963  if ( $combine[$type] > $bestq ) {
1964  $besttype = $type;
1965  $bestq = $combine[$type];
1966  }
1967  }
1968 
1969  return $besttype;
1970 }
1971 
1978 function wfSuppressWarnings( $end = false ) {
1979  MediaWiki\suppressWarnings( $end );
1980 }
1981 
1986 function wfRestoreWarnings() {
1987  MediaWiki\suppressWarnings( true );
1988 }
1989 
1990 # Autodetect, convert and provide timestamps of various types
1991 
1995 define( 'TS_UNIX', 0 );
1996 
2000 define( 'TS_MW', 1 );
2001 
2005 define( 'TS_DB', 2 );
2006 
2010 define( 'TS_RFC2822', 3 );
2011 
2017 define( 'TS_ISO_8601', 4 );
2018 
2026 define( 'TS_EXIF', 5 );
2027 
2031 define( 'TS_ORACLE', 6 );
2032 
2036 define( 'TS_POSTGRES', 7 );
2037 
2041 define( 'TS_ISO_8601_BASIC', 9 );
2042 
2051 function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) {
2052  try {
2053  $timestamp = new MWTimestamp( $ts );
2054  return $timestamp->getTimestamp( $outputtype );
2055  } catch ( TimestampException $e ) {
2056  wfDebug( "wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n" );
2057  return false;
2058  }
2059 }
2060 
2069 function wfTimestampOrNull( $outputtype = TS_UNIX, $ts = null ) {
2070  if ( is_null( $ts ) ) {
2071  return null;
2072  } else {
2073  return wfTimestamp( $outputtype, $ts );
2074  }
2075 }
2076 
2082 function wfTimestampNow() {
2083  # return NOW
2084  return wfTimestamp( TS_MW, time() );
2085 }
2086 
2092 function wfIsWindows() {
2093  static $isWindows = null;
2094  if ( $isWindows === null ) {
2095  $isWindows = strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN';
2096  }
2097  return $isWindows;
2098 }
2099 
2105 function wfIsHHVM() {
2106  return defined( 'HHVM_VERSION' );
2107 }
2108 
2120 function wfTempDir() {
2122 
2123  if ( $wgTmpDirectory !== false ) {
2124  return $wgTmpDirectory;
2125  }
2126 
2127  $tmpDir = array_map( "getenv", [ 'TMPDIR', 'TMP', 'TEMP' ] );
2128  $tmpDir[] = sys_get_temp_dir();
2129  $tmpDir[] = ini_get( 'upload_tmp_dir' );
2130 
2131  foreach ( $tmpDir as $tmp ) {
2132  if ( $tmp && file_exists( $tmp ) && is_dir( $tmp ) && is_writable( $tmp ) ) {
2133  return $tmp;
2134  }
2135  }
2136 
2144  if ( wfIsWindows() ) {
2145  $tmp = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'mwtmp' . '-' . get_current_user();
2146  if ( !file_exists( $tmp ) ) {
2147  mkdir( $tmp );
2148  }
2149  if ( file_exists( $tmp ) && is_dir( $tmp ) && is_writable( $tmp ) ) {
2150  return $tmp;
2151  }
2152  }
2153 
2154  throw new MWException( 'No writable temporary directory could be found. ' .
2155  'Please set $wgTmpDirectory to a writable directory.' );
2156 }
2157 
2167 function wfMkdirParents( $dir, $mode = null, $caller = null ) {
2169 
2170  if ( FileBackend::isStoragePath( $dir ) ) { // sanity
2171  throw new MWException( __FUNCTION__ . " given storage path '$dir'." );
2172  }
2173 
2174  if ( !is_null( $caller ) ) {
2175  wfDebug( "$caller: called wfMkdirParents($dir)\n" );
2176  }
2177 
2178  if ( strval( $dir ) === '' || is_dir( $dir ) ) {
2179  return true;
2180  }
2181 
2182  $dir = str_replace( [ '\\', '/' ], DIRECTORY_SEPARATOR, $dir );
2183 
2184  if ( is_null( $mode ) ) {
2185  $mode = $wgDirectoryMode;
2186  }
2187 
2188  // Turn off the normal warning, we're doing our own below
2189  MediaWiki\suppressWarnings();
2190  $ok = mkdir( $dir, $mode, true ); // PHP5 <3
2191  MediaWiki\restoreWarnings();
2192 
2193  if ( !$ok ) {
2194  // directory may have been created on another request since we last checked
2195  if ( is_dir( $dir ) ) {
2196  return true;
2197  }
2198 
2199  // PHP doesn't report the path in its warning message, so add our own to aid in diagnosis.
2200  wfLogWarning( sprintf( "failed to mkdir \"%s\" mode 0%o", $dir, $mode ) );
2201  }
2202  return $ok;
2203 }
2204 
2211  wfDebug( __FUNCTION__ . "( $dir )\n" );
2212  // taken from http://de3.php.net/manual/en/function.rmdir.php#98622
2213  if ( is_dir( $dir ) ) {
2214  $objects = scandir( $dir );
2215  foreach ( $objects as $object ) {
2216  if ( $object != "." && $object != ".." ) {
2217  if ( filetype( $dir . '/' . $object ) == "dir" ) {
2218  wfRecursiveRemoveDir( $dir . '/' . $object );
2219  } else {
2220  unlink( $dir . '/' . $object );
2221  }
2222  }
2223  }
2224  reset( $objects );
2225  rmdir( $dir );
2226  }
2227 }
2228 
2235 function wfPercent( $nr, $acc = 2, $round = true ) {
2236  $ret = sprintf( "%.${acc}f", $nr );
2237  return $round ? round( $ret, $acc ) . '%' : "$ret%";
2238 }
2239 
2263 function wfIniGetBool( $setting ) {
2264  $val = strtolower( ini_get( $setting ) );
2265  // 'on' and 'true' can't have whitespace around them, but '1' can.
2266  return $val == 'on'
2267  || $val == 'true'
2268  || $val == 'yes'
2269  || preg_match( "/^\s*[+-]?0*[1-9]/", $val ); // approx C atoi() function
2270 }
2271 
2283 function wfEscapeShellArg( /*...*/ ) {
2285 
2286  $args = func_get_args();
2287  if ( count( $args ) === 1 && is_array( reset( $args ) ) ) {
2288  // If only one argument has been passed, and that argument is an array,
2289  // treat it as a list of arguments
2290  $args = reset( $args );
2291  }
2292 
2293  $first = true;
2294  $retVal = '';
2295  foreach ( $args as $arg ) {
2296  if ( !$first ) {
2297  $retVal .= ' ';
2298  } else {
2299  $first = false;
2300  }
2301 
2302  if ( wfIsWindows() ) {
2303  // Escaping for an MSVC-style command line parser and CMD.EXE
2304  // @codingStandardsIgnoreStart For long URLs
2305  // Refs:
2306  // * http://web.archive.org/web/20020708081031/http://mailman.lyra.org/pipermail/scite-interest/2002-March/000436.html
2307  // * http://technet.microsoft.com/en-us/library/cc723564.aspx
2308  // * Bug #13518
2309  // * CR r63214
2310  // Double the backslashes before any double quotes. Escape the double quotes.
2311  // @codingStandardsIgnoreEnd
2312  $tokens = preg_split( '/(\\\\*")/', $arg, -1, PREG_SPLIT_DELIM_CAPTURE );
2313  $arg = '';
2314  $iteration = 0;
2315  foreach ( $tokens as $token ) {
2316  if ( $iteration % 2 == 1 ) {
2317  // Delimiter, a double quote preceded by zero or more slashes
2318  $arg .= str_replace( '\\', '\\\\', substr( $token, 0, -1 ) ) . '\\"';
2319  } elseif ( $iteration % 4 == 2 ) {
2320  // ^ in $token will be outside quotes, need to be escaped
2321  $arg .= str_replace( '^', '^^', $token );
2322  } else { // $iteration % 4 == 0
2323  // ^ in $token will appear inside double quotes, so leave as is
2324  $arg .= $token;
2325  }
2326  $iteration++;
2327  }
2328  // Double the backslashes before the end of the string, because
2329  // we will soon add a quote
2330  $m = [];
2331  if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) {
2332  $arg = $m[1] . str_replace( '\\', '\\\\', $m[2] );
2333  }
2334 
2335  // Add surrounding quotes
2336  $retVal .= '"' . $arg . '"';
2337  } else {
2338  $retVal .= escapeshellarg( $arg );
2339  }
2340  }
2341  return $retVal;
2342 }
2343 
2351  static $disabled = null;
2352  if ( is_null( $disabled ) ) {
2353  if ( !function_exists( 'proc_open' ) ) {
2354  wfDebug( "proc_open() is disabled\n" );
2355  $disabled = 'disabled';
2356  } else {
2357  $disabled = false;
2358  }
2359  }
2360  return $disabled;
2361 }
2362 
2385 function wfShellExec( $cmd, &$retval = null, $environ = [],
2386  $limits = [], $options = []
2387 ) {
2390 
2391  $disabled = wfShellExecDisabled();
2392  if ( $disabled ) {
2393  $retval = 1;
2394  return 'Unable to run external programs, proc_open() is disabled.';
2395  }
2396 
2397  $includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr'];
2398  $profileMethod = isset( $options['profileMethod'] ) ? $options['profileMethod'] : wfGetCaller();
2399 
2401 
2402  $envcmd = '';
2403  foreach ( $environ as $k => $v ) {
2404  if ( wfIsWindows() ) {
2405  /* Surrounding a set in quotes (method used by wfEscapeShellArg) makes the quotes themselves
2406  * appear in the environment variable, so we must use carat escaping as documented in
2407  * http://technet.microsoft.com/en-us/library/cc723564.aspx
2408  * Note however that the quote isn't listed there, but is needed, and the parentheses
2409  * are listed there but doesn't appear to need it.
2410  */
2411  $envcmd .= "set $k=" . preg_replace( '/([&|()<>^"])/', '^\\1', $v ) . '&& ';
2412  } else {
2413  /* Assume this is a POSIX shell, thus required to accept variable assignments before the command
2414  * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_01
2415  */
2416  $envcmd .= "$k=" . escapeshellarg( $v ) . ' ';
2417  }
2418  }
2419  if ( is_array( $cmd ) ) {
2420  $cmd = wfEscapeShellArg( $cmd );
2421  }
2422 
2423  $cmd = $envcmd . $cmd;
2424 
2425  $useLogPipe = false;
2426  if ( is_executable( '/bin/bash' ) ) {
2427  $time = intval( isset( $limits['time'] ) ? $limits['time'] : $wgMaxShellTime );
2428  if ( isset( $limits['walltime'] ) ) {
2429  $wallTime = intval( $limits['walltime'] );
2430  } elseif ( isset( $limits['time'] ) ) {
2431  $wallTime = $time;
2432  } else {
2433  $wallTime = intval( $wgMaxShellWallClockTime );
2434  }
2435  $mem = intval( isset( $limits['memory'] ) ? $limits['memory'] : $wgMaxShellMemory );
2436  $filesize = intval( isset( $limits['filesize'] ) ? $limits['filesize'] : $wgMaxShellFileSize );
2437 
2438  if ( $time > 0 || $mem > 0 || $filesize > 0 || $wallTime > 0 ) {
2439  $cmd = '/bin/bash ' . escapeshellarg( "$IP/includes/limit.sh" ) . ' ' .
2440  escapeshellarg( $cmd ) . ' ' .
2441  escapeshellarg(
2442  "MW_INCLUDE_STDERR=" . ( $includeStderr ? '1' : '' ) . ';' .
2443  "MW_CPU_LIMIT=$time; " .
2444  'MW_CGROUP=' . escapeshellarg( $wgShellCgroup ) . '; ' .
2445  "MW_MEM_LIMIT=$mem; " .
2446  "MW_FILE_SIZE_LIMIT=$filesize; " .
2447  "MW_WALL_CLOCK_LIMIT=$wallTime; " .
2448  "MW_USE_LOG_PIPE=yes"
2449  );
2450  $useLogPipe = true;
2451  } elseif ( $includeStderr ) {
2452  $cmd .= ' 2>&1';
2453  }
2454  } elseif ( $includeStderr ) {
2455  $cmd .= ' 2>&1';
2456  }
2457  wfDebug( "wfShellExec: $cmd\n" );
2458 
2459  // Don't try to execute commands that exceed Linux's MAX_ARG_STRLEN.
2460  // Other platforms may be more accomodating, but we don't want to be
2461  // accomodating, because very long commands probably include user
2462  // input. See T129506.
2463  if ( strlen( $cmd ) > SHELL_MAX_ARG_STRLEN ) {
2464  throw new Exception( __METHOD__ .
2465  '(): total length of $cmd must not exceed SHELL_MAX_ARG_STRLEN' );
2466  }
2467 
2468  $desc = [
2469  0 => [ 'file', 'php://stdin', 'r' ],
2470  1 => [ 'pipe', 'w' ],
2471  2 => [ 'file', 'php://stderr', 'w' ] ];
2472  if ( $useLogPipe ) {
2473  $desc[3] = [ 'pipe', 'w' ];
2474  }
2475  $pipes = null;
2476  $scoped = Profiler::instance()->scopedProfileIn( __FUNCTION__ . '-' . $profileMethod );
2477  $proc = proc_open( $cmd, $desc, $pipes );
2478  if ( !$proc ) {
2479  wfDebugLog( 'exec', "proc_open() failed: $cmd" );
2480  $retval = -1;
2481  return '';
2482  }
2483  $outBuffer = $logBuffer = '';
2484  $emptyArray = [];
2485  $status = false;
2486  $logMsg = false;
2487 
2488  /* According to the documentation, it is possible for stream_select()
2489  * to fail due to EINTR. I haven't managed to induce this in testing
2490  * despite sending various signals. If it did happen, the error
2491  * message would take the form:
2492  *
2493  * stream_select(): unable to select [4]: Interrupted system call (max_fd=5)
2494  *
2495  * where [4] is the value of the macro EINTR and "Interrupted system
2496  * call" is string which according to the Linux manual is "possibly"
2497  * localised according to LC_MESSAGES.
2498  */
2499  $eintr = defined( 'SOCKET_EINTR' ) ? SOCKET_EINTR : 4;
2500  $eintrMessage = "stream_select(): unable to select [$eintr]";
2501 
2502  $running = true;
2503  $timeout = null;
2504  $numReadyPipes = 0;
2505 
2506  while ( $running === true || $numReadyPipes !== 0 ) {
2507  if ( $running ) {
2508  $status = proc_get_status( $proc );
2509  // If the process has terminated, switch to nonblocking selects
2510  // for getting any data still waiting to be read.
2511  if ( !$status['running'] ) {
2512  $running = false;
2513  $timeout = 0;
2514  }
2515  }
2516 
2517  $readyPipes = $pipes;
2518 
2519  // Clear last error
2520  // @codingStandardsIgnoreStart Generic.PHP.NoSilencedErrors.Discouraged
2521  @trigger_error( '' );
2522  $numReadyPipes = @stream_select( $readyPipes, $emptyArray, $emptyArray, $timeout );
2523  if ( $numReadyPipes === false ) {
2524  // @codingStandardsIgnoreEnd
2525  $error = error_get_last();
2526  if ( strncmp( $error['message'], $eintrMessage, strlen( $eintrMessage ) ) == 0 ) {
2527  continue;
2528  } else {
2529  trigger_error( $error['message'], E_USER_WARNING );
2530  $logMsg = $error['message'];
2531  break;
2532  }
2533  }
2534  foreach ( $readyPipes as $fd => $pipe ) {
2535  $block = fread( $pipe, 65536 );
2536  if ( $block === '' ) {
2537  // End of file
2538  fclose( $pipes[$fd] );
2539  unset( $pipes[$fd] );
2540  if ( !$pipes ) {
2541  break 2;
2542  }
2543  } elseif ( $block === false ) {
2544  // Read error
2545  $logMsg = "Error reading from pipe";
2546  break 2;
2547  } elseif ( $fd == 1 ) {
2548  // From stdout
2549  $outBuffer .= $block;
2550  } elseif ( $fd == 3 ) {
2551  // From log FD
2552  $logBuffer .= $block;
2553  if ( strpos( $block, "\n" ) !== false ) {
2554  $lines = explode( "\n", $logBuffer );
2555  $logBuffer = array_pop( $lines );
2556  foreach ( $lines as $line ) {
2557  wfDebugLog( 'exec', $line );
2558  }
2559  }
2560  }
2561  }
2562  }
2563 
2564  foreach ( $pipes as $pipe ) {
2565  fclose( $pipe );
2566  }
2567 
2568  // Use the status previously collected if possible, since proc_get_status()
2569  // just calls waitpid() which will not return anything useful the second time.
2570  if ( $running ) {
2571  $status = proc_get_status( $proc );
2572  }
2573 
2574  if ( $logMsg !== false ) {
2575  // Read/select error
2576  $retval = -1;
2577  proc_close( $proc );
2578  } elseif ( $status['signaled'] ) {
2579  $logMsg = "Exited with signal {$status['termsig']}";
2580  $retval = 128 + $status['termsig'];
2581  proc_close( $proc );
2582  } else {
2583  if ( $status['running'] ) {
2584  $retval = proc_close( $proc );
2585  } else {
2586  $retval = $status['exitcode'];
2587  proc_close( $proc );
2588  }
2589  if ( $retval == 127 ) {
2590  $logMsg = "Possibly missing executable file";
2591  } elseif ( $retval >= 129 && $retval <= 192 ) {
2592  $logMsg = "Probably exited with signal " . ( $retval - 128 );
2593  }
2594  }
2595 
2596  if ( $logMsg !== false ) {
2597  wfDebugLog( 'exec', "$logMsg: $cmd" );
2598  }
2599 
2600  return $outBuffer;
2601 }
2602 
2619 function wfShellExecWithStderr( $cmd, &$retval = null, $environ = [], $limits = [] ) {
2620  return wfShellExec( $cmd, $retval, $environ, $limits,
2621  [ 'duplicateStderr' => true, 'profileMethod' => wfGetCaller() ] );
2622 }
2623 
2628 function wfInitShellLocale() {
2629  static $done = false;
2630  if ( $done ) {
2631  return;
2632  }
2633  $done = true;
2635  putenv( "LC_CTYPE=$wgShellLocale" );
2636  setlocale( LC_CTYPE, $wgShellLocale );
2637 }
2638 
2651 function wfShellWikiCmd( $script, array $parameters = [], array $options = [] ) {
2652  global $wgPhpCli;
2653  // Give site config file a chance to run the script in a wrapper.
2654  // The caller may likely want to call wfBasename() on $script.
2655  Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
2656  $cmd = isset( $options['php'] ) ? [ $options['php'] ] : [ $wgPhpCli ];
2657  if ( isset( $options['wrapper'] ) ) {
2658  $cmd[] = $options['wrapper'];
2659  }
2660  $cmd[] = $script;
2661  // Escape each parameter for shell
2662  return wfEscapeShellArg( array_merge( $cmd, $parameters ) );
2663 }
2664 
2675 function wfMerge( $old, $mine, $yours, &$result ) {
2676  global $wgDiff3;
2677 
2678  # This check may also protect against code injection in
2679  # case of broken installations.
2680  MediaWiki\suppressWarnings();
2681  $haveDiff3 = $wgDiff3 && file_exists( $wgDiff3 );
2682  MediaWiki\restoreWarnings();
2683 
2684  if ( !$haveDiff3 ) {
2685  wfDebug( "diff3 not found\n" );
2686  return false;
2687  }
2688 
2689  # Make temporary files
2690  $td = wfTempDir();
2691  $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
2692  $mytextFile = fopen( $mytextName = tempnam( $td, 'merge-mine-' ), 'w' );
2693  $yourtextFile = fopen( $yourtextName = tempnam( $td, 'merge-your-' ), 'w' );
2694 
2695  # NOTE: diff3 issues a warning to stderr if any of the files does not end with
2696  # a newline character. To avoid this, we normalize the trailing whitespace before
2697  # creating the diff.
2698 
2699  fwrite( $oldtextFile, rtrim( $old ) . "\n" );
2700  fclose( $oldtextFile );
2701  fwrite( $mytextFile, rtrim( $mine ) . "\n" );
2702  fclose( $mytextFile );
2703  fwrite( $yourtextFile, rtrim( $yours ) . "\n" );
2704  fclose( $yourtextFile );
2705 
2706  # Check for a conflict
2707  $cmd = wfEscapeShellArg( $wgDiff3, '-a', '--overlap-only', $mytextName,
2708  $oldtextName, $yourtextName );
2709  $handle = popen( $cmd, 'r' );
2710 
2711  if ( fgets( $handle, 1024 ) ) {
2712  $conflict = true;
2713  } else {
2714  $conflict = false;
2715  }
2716  pclose( $handle );
2717 
2718  # Merge differences
2719  $cmd = wfEscapeShellArg( $wgDiff3, '-a', '-e', '--merge', $mytextName,
2720  $oldtextName, $yourtextName );
2721  $handle = popen( $cmd, 'r' );
2722  $result = '';
2723  do {
2724  $data = fread( $handle, 8192 );
2725  if ( strlen( $data ) == 0 ) {
2726  break;
2727  }
2728  $result .= $data;
2729  } while ( true );
2730  pclose( $handle );
2731  unlink( $mytextName );
2732  unlink( $oldtextName );
2733  unlink( $yourtextName );
2734 
2735  if ( $result === '' && $old !== '' && !$conflict ) {
2736  wfDebug( "Unexpected null result from diff3. Command: $cmd\n" );
2737  $conflict = true;
2738  }
2739  return !$conflict;
2740 }
2741 
2753 function wfDiff( $before, $after, $params = '-u' ) {
2754  if ( $before == $after ) {
2755  return '';
2756  }
2757 
2758  global $wgDiff;
2759  MediaWiki\suppressWarnings();
2760  $haveDiff = $wgDiff && file_exists( $wgDiff );
2761  MediaWiki\restoreWarnings();
2762 
2763  # This check may also protect against code injection in
2764  # case of broken installations.
2765  if ( !$haveDiff ) {
2766  wfDebug( "diff executable not found\n" );
2767  $diffs = new Diff( explode( "\n", $before ), explode( "\n", $after ) );
2768  $format = new UnifiedDiffFormatter();
2769  return $format->format( $diffs );
2770  }
2771 
2772  # Make temporary files
2773  $td = wfTempDir();
2774  $oldtextFile = fopen( $oldtextName = tempnam( $td, 'merge-old-' ), 'w' );
2775  $newtextFile = fopen( $newtextName = tempnam( $td, 'merge-your-' ), 'w' );
2776 
2777  fwrite( $oldtextFile, $before );
2778  fclose( $oldtextFile );
2779  fwrite( $newtextFile, $after );
2780  fclose( $newtextFile );
2781 
2782  // Get the diff of the two files
2783  $cmd = "$wgDiff " . $params . ' ' . wfEscapeShellArg( $oldtextName, $newtextName );
2784 
2785  $h = popen( $cmd, 'r' );
2786  if ( !$h ) {
2787  unlink( $oldtextName );
2788  unlink( $newtextName );
2789  throw new Exception( __METHOD__ . '(): popen() failed' );
2790  }
2791 
2792  $diff = '';
2793 
2794  do {
2795  $data = fread( $h, 8192 );
2796  if ( strlen( $data ) == 0 ) {
2797  break;
2798  }
2799  $diff .= $data;
2800  } while ( true );
2801 
2802  // Clean up
2803  pclose( $h );
2804  unlink( $oldtextName );
2805  unlink( $newtextName );
2806 
2807  // Kill the --- and +++ lines. They're not useful.
2808  $diff_lines = explode( "\n", $diff );
2809  if ( isset( $diff_lines[0] ) && strpos( $diff_lines[0], '---' ) === 0 ) {
2810  unset( $diff_lines[0] );
2811  }
2812  if ( isset( $diff_lines[1] ) && strpos( $diff_lines[1], '+++' ) === 0 ) {
2813  unset( $diff_lines[1] );
2814  }
2815 
2816  $diff = implode( "\n", $diff_lines );
2817 
2818  return $diff;
2819 }
2820 
2836 function wfUsePHP( $req_ver ) {
2837  $php_ver = PHP_VERSION;
2838 
2839  if ( version_compare( $php_ver, (string)$req_ver, '<' ) ) {
2840  throw new MWException( "PHP $req_ver required--this is only $php_ver" );
2841  }
2842 }
2843 
2866 function wfUseMW( $req_ver ) {
2868 
2869  if ( version_compare( $wgVersion, (string)$req_ver, '<' ) ) {
2870  throw new MWException( "MediaWiki $req_ver required--this is only $wgVersion" );
2871  }
2872 }
2873 
2886 function wfBaseName( $path, $suffix = '' ) {
2887  if ( $suffix == '' ) {
2888  $encSuffix = '';
2889  } else {
2890  $encSuffix = '(?:' . preg_quote( $suffix, '#' ) . ')?';
2891  }
2892 
2893  $matches = [];
2894  if ( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) {
2895  return $matches[1];
2896  } else {
2897  return '';
2898  }
2899 }
2900 
2911  // Normalize mixed input on Windows...
2912  $path = str_replace( '/', DIRECTORY_SEPARATOR, $path );
2913  $from = str_replace( '/', DIRECTORY_SEPARATOR, $from );
2914 
2915  // Trim trailing slashes -- fix for drive root
2916  $path = rtrim( $path, DIRECTORY_SEPARATOR );
2917  $from = rtrim( $from, DIRECTORY_SEPARATOR );
2918 
2919  $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) );
2920  $against = explode( DIRECTORY_SEPARATOR, $from );
2921 
2922  if ( $pieces[0] !== $against[0] ) {
2923  // Non-matching Windows drive letters?
2924  // Return a full path.
2925  return $path;
2926  }
2927 
2928  // Trim off common prefix
2929  while ( count( $pieces ) && count( $against )
2930  && $pieces[0] == $against[0] ) {
2931  array_shift( $pieces );
2932  array_shift( $against );
2933  }
2934 
2935  // relative dots to bump us to the parent
2936  while ( count( $against ) ) {
2937  array_unshift( $pieces, '..' );
2938  array_shift( $against );
2939  }
2940 
2941  array_push( $pieces, wfBaseName( $path ) );
2942 
2943  return implode( DIRECTORY_SEPARATOR, $pieces );
2944 }
2945 
2963 function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1,
2964  $lowercase = true, $engine = 'auto'
2965 ) {
2966  return Wikimedia\base_convert( $input, $sourceBase, $destBase, $pad, $lowercase, $engine );
2967 }
2968 
2973 function wfFixSessionID() {
2974  wfDeprecated( __FUNCTION__, '1.27' );
2975 }
2976 
2983 function wfResetSessionID() {
2984  wfDeprecated( __FUNCTION__, '1.27' );
2985  $session = SessionManager::getGlobalSession();
2986  $delay = $session->delaySave();
2987 
2988  $session->resetId();
2989 
2990  // Make sure a session is started, since that's what the old
2991  // wfResetSessionID() did.
2992  if ( session_id() !== $session->getId() ) {
2993  wfSetupSession( $session->getId() );
2994  }
2995 
2996  ScopedCallback::consume( $delay );
2997 }
2998 
3008 function wfSetupSession( $sessionId = false ) {
3009  wfDeprecated( __FUNCTION__, '1.27' );
3010 
3011  if ( $sessionId ) {
3012  session_id( $sessionId );
3013  }
3014 
3015  $session = SessionManager::getGlobalSession();
3016  $session->persist();
3017 
3018  if ( session_id() !== $session->getId() ) {
3019  session_id( $session->getId() );
3020  }
3021  MediaWiki\quietCall( 'session_start' );
3022 }
3023 
3031  global $IP;
3032 
3033  $file = "$IP/serialized/$name";
3034  if ( file_exists( $file ) ) {
3035  $blob = file_get_contents( $file );
3036  if ( $blob ) {
3037  return unserialize( $blob );
3038  }
3039  }
3040  return false;
3041 }
3042 
3049 function wfMemcKey( /*...*/ ) {
3050  return call_user_func_array(
3051  [ ObjectCache::getLocalClusterInstance(), 'makeKey' ],
3052  func_get_args()
3053  );
3054 }
3055 
3066 function wfForeignMemcKey( $db, $prefix /*...*/ ) {
3067  $args = array_slice( func_get_args(), 2 );
3068  $keyspace = $prefix ? "$db-$prefix" : $db;
3069  return call_user_func_array(
3070  [ ObjectCache::getLocalClusterInstance(), 'makeKeyInternal' ],
3071  [ $keyspace, $args ]
3072  );
3073 }
3074 
3086 function wfGlobalCacheKey( /*...*/ ) {
3087  return call_user_func_array(
3088  [ ObjectCache::getLocalClusterInstance(), 'makeGlobalKey' ],
3089  func_get_args()
3090  );
3091 }
3092 
3099 function wfWikiID() {
3101  if ( $wgDBprefix ) {
3102  return "$wgDBname-$wgDBprefix";
3103  } else {
3104  return $wgDBname;
3105  }
3106 }
3107 
3115 function wfSplitWikiID( $wiki ) {
3116  $bits = explode( '-', $wiki, 2 );
3117  if ( count( $bits ) < 2 ) {
3118  $bits[] = '';
3119  }
3120  return $bits;
3121 }
3122 
3148 function wfGetDB( $db, $groups = [], $wiki = false ) {
3149  return wfGetLB( $wiki )->getConnection( $db, $groups, $wiki );
3150 }
3151 
3161 function wfGetLB( $wiki = false ) {
3162  if ( $wiki === false ) {
3163  return \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancer();
3164  } else {
3165  $factory = \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
3166  return $factory->getMainLB( $wiki );
3167  }
3168 }
3169 
3177 function wfGetLBFactory() {
3178  return \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
3179 }
3180 
3189 function wfFindFile( $title, $options = [] ) {
3190  return RepoGroup::singleton()->findFile( $title, $options );
3191 }
3192 
3200 function wfLocalFile( $title ) {
3201  return RepoGroup::singleton()->getLocalRepo()->newFile( $title );
3202 }
3203 
3212  return $wgMiserMode
3213  || ( SiteStats::pages() > 100000
3214  && SiteStats::edits() > 1000000
3215  && SiteStats::users() > 10000 );
3216 }
3217 
3226 function wfScript( $script = 'index' ) {
3228  if ( $script === 'index' ) {
3229  return $wgScript;
3230  } elseif ( $script === 'load' ) {
3231  return $wgLoadScript;
3232  } else {
3233  return "{$wgScriptPath}/{$script}.php";
3234  }
3235 }
3236 
3242 function wfGetScriptUrl() {
3243  if ( isset( $_SERVER['SCRIPT_NAME'] ) ) {
3244  /* as it was called, minus the query string.
3245  *
3246  * Some sites use Apache rewrite rules to handle subdomains,
3247  * and have PHP set up in a weird way that causes PHP_SELF
3248  * to contain the rewritten URL instead of the one that the
3249  * outside world sees.
3250  *
3251  * If in this mode, use SCRIPT_URL instead, which mod_rewrite
3252  * provides containing the "before" URL.
3253  */
3254  return $_SERVER['SCRIPT_NAME'];
3255  } else {
3256  return $_SERVER['URL'];
3257  }
3258 }
3259 
3267 function wfBoolToStr( $value ) {
3268  return $value ? 'true' : 'false';
3269 }
3270 
3276 function wfGetNull() {
3277  return wfIsWindows() ? 'NUL' : '/dev/null';
3278 }
3279 
3303  $ifWritesSince = null, $wiki = false, $cluster = false, $timeout = null
3304 ) {
3305  if ( $timeout === null ) {
3306  $timeout = ( PHP_SAPI === 'cli' ) ? 86400 : 10;
3307  }
3308 
3309  if ( $cluster === '*' ) {
3310  $cluster = false;
3311  $wiki = false;
3312  } elseif ( $wiki === false ) {
3313  $wiki = wfWikiID();
3314  }
3315 
3316  try {
3317  wfGetLBFactory()->waitForReplication( [
3318  'wiki' => $wiki,
3319  'cluster' => $cluster,
3320  'timeout' => $timeout,
3321  // B/C: first argument used to be "max seconds of lag"; ignore such values
3322  'ifWritesSince' => ( $ifWritesSince > 1e9 ) ? $ifWritesSince : null
3323  ] );
3324  } catch ( DBReplicationWaitError $e ) {
3325  return false;
3326  }
3327 
3328  return true;
3329 }
3330 
3338 function wfCountDown( $seconds ) {
3339  for ( $i = $seconds; $i >= 0; $i-- ) {
3340  if ( $i != $seconds ) {
3341  echo str_repeat( "\x08", strlen( $i + 1 ) );
3342  }
3343  echo $i;
3344  flush();
3345  if ( $i ) {
3346  sleep( 1 );
3347  }
3348  }
3349  echo "\n";
3350 }
3351 
3362  $illegalFileChars = $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : '';
3363  $name = preg_replace(
3364  "/[^" . Title::legalChars() . "]" . $illegalFileChars . "/",
3365  '-',
3366  $name
3367  );
3368  // $wgIllegalFileChars may not include '/' and '\', so we still need to do this
3369  $name = wfBaseName( $name );
3370  return $name;
3371 }
3372 
3378 function wfMemoryLimit() {
3380  $memlimit = wfShorthandToInteger( ini_get( 'memory_limit' ) );
3381  if ( $memlimit != -1 ) {
3382  $conflimit = wfShorthandToInteger( $wgMemoryLimit );
3383  if ( $conflimit == -1 ) {
3384  wfDebug( "Removing PHP's memory limit\n" );
3385  MediaWiki\suppressWarnings();
3386  ini_set( 'memory_limit', $conflimit );
3387  MediaWiki\restoreWarnings();
3388  return $conflimit;
3389  } elseif ( $conflimit > $memlimit ) {
3390  wfDebug( "Raising PHP's memory limit to $conflimit bytes\n" );
3391  MediaWiki\suppressWarnings();
3392  ini_set( 'memory_limit', $conflimit );
3393  MediaWiki\restoreWarnings();
3394  return $conflimit;
3395  }
3396  }
3397  return $memlimit;
3398 }
3399 
3408 
3409  $timeLimit = ini_get( 'max_execution_time' );
3410  // Note that CLI scripts use 0
3411  if ( $timeLimit > 0 && $wgTransactionalTimeLimit > $timeLimit ) {
3412  set_time_limit( $wgTransactionalTimeLimit );
3413  }
3414 
3415  ignore_user_abort( true ); // ignore client disconnects
3416 
3417  return $timeLimit;
3418 }
3419 
3427 function wfShorthandToInteger( $string = '', $default = -1 ) {
3428  $string = trim( $string );
3429  if ( $string === '' ) {
3430  return $default;
3431  }
3432  $last = $string[strlen( $string ) - 1];
3433  $val = intval( $string );
3434  switch ( $last ) {
3435  case 'g':
3436  case 'G':
3437  $val *= 1024;
3438  // break intentionally missing
3439  case 'm':
3440  case 'M':
3441  $val *= 1024;
3442  // break intentionally missing
3443  case 'k':
3444  case 'K':
3445  $val *= 1024;
3446  }
3447 
3448  return $val;
3449 }
3450 
3458 function wfBCP47( $code ) {
3459  $codeSegment = explode( '-', $code );
3460  $codeBCP = [];
3461  foreach ( $codeSegment as $segNo => $seg ) {
3462  // when previous segment is x, it is a private segment and should be lc
3463  if ( $segNo > 0 && strtolower( $codeSegment[( $segNo - 1 )] ) == 'x' ) {
3464  $codeBCP[$segNo] = strtolower( $seg );
3465  // ISO 3166 country code
3466  } elseif ( ( strlen( $seg ) == 2 ) && ( $segNo > 0 ) ) {
3467  $codeBCP[$segNo] = strtoupper( $seg );
3468  // ISO 15924 script code
3469  } elseif ( ( strlen( $seg ) == 4 ) && ( $segNo > 0 ) ) {
3470  $codeBCP[$segNo] = ucfirst( strtolower( $seg ) );
3471  // Use lowercase for other cases
3472  } else {
3473  $codeBCP[$segNo] = strtolower( $seg );
3474  }
3475  }
3476  $langCode = implode( '-', $codeBCP );
3477  return $langCode;
3478 }
3479 
3486 function wfGetCache( $cacheType ) {
3487  return ObjectCache::getInstance( $cacheType );
3488 }
3489 
3495 function wfGetMainCache() {
3497  return ObjectCache::getInstance( $wgMainCacheType );
3498 }
3499 
3507  return ObjectCache::getInstance( $wgMessageCacheType );
3508 }
3509 
3517  return ObjectCache::getInstance( $wgParserCacheType );
3518 }
3519 
3530 function wfRunHooks( $event, array $args = [], $deprecatedVersion = null ) {
3531  return Hooks::run( $event, $args, $deprecatedVersion );
3532 }
3533 
3548 function wfUnpack( $format, $data, $length = false ) {
3549  if ( $length !== false ) {
3550  $realLen = strlen( $data );
3551  if ( $realLen < $length ) {
3552  throw new MWException( "Tried to use wfUnpack on a "
3553  . "string of length $realLen, but needed one "
3554  . "of at least length $length."
3555  );
3556  }
3557  }
3558 
3559  MediaWiki\suppressWarnings();
3560  $result = unpack( $format, $data );
3561  MediaWiki\restoreWarnings();
3562 
3563  if ( $result === false ) {
3564  // If it cannot extract the packed data.
3565  throw new MWException( "unpack could not unpack binary data" );
3566  }
3567  return $result;
3568 }
3569 
3584 function wfIsBadImage( $name, $contextTitle = false, $blacklist = null ) {
3585  # Handle redirects; callers almost always hit wfFindFile() anyway,
3586  # so just use that method because it has a fast process cache.
3587  $file = wfFindFile( $name ); // get the final name
3588  $name = $file ? $file->getTitle()->getDBkey() : $name;
3589 
3590  # Run the extension hook
3591  $bad = false;
3592  if ( !Hooks::run( 'BadImage', [ $name, &$bad ] ) ) {
3593  return $bad;
3594  }
3595 
3597  $key = wfMemcKey( 'bad-image-list', ( $blacklist === null ) ? 'default' : md5( $blacklist ) );
3598  $badImages = $cache->get( $key );
3599 
3600  if ( $badImages === false ) { // cache miss
3601  if ( $blacklist === null ) {
3602  $blacklist = wfMessage( 'bad_image_list' )->inContentLanguage()->plain(); // site list
3603  }
3604  # Build the list now
3605  $badImages = [];
3606  $lines = explode( "\n", $blacklist );
3607  foreach ( $lines as $line ) {
3608  # List items only
3609  if ( substr( $line, 0, 1 ) !== '*' ) {
3610  continue;
3611  }
3612 
3613  # Find all links
3614  $m = [];
3615  if ( !preg_match_all( '/\[\[:?(.*?)\]\]/', $line, $m ) ) {
3616  continue;
3617  }
3618 
3619  $exceptions = [];
3620  $imageDBkey = false;
3621  foreach ( $m[1] as $i => $titleText ) {
3622  $title = Title::newFromText( $titleText );
3623  if ( !is_null( $title ) ) {
3624  if ( $i == 0 ) {
3625  $imageDBkey = $title->getDBkey();
3626  } else {
3627  $exceptions[$title->getPrefixedDBkey()] = true;
3628  }
3629  }
3630  }
3631 
3632  if ( $imageDBkey !== false ) {
3633  $badImages[$imageDBkey] = $exceptions;
3634  }
3635  }
3636  $cache->set( $key, $badImages, 60 );
3637  }
3638 
3639  $contextKey = $contextTitle ? $contextTitle->getPrefixedDBkey() : false;
3640  $bad = isset( $badImages[$name] ) && !isset( $badImages[$name][$contextKey] );
3641 
3642  return $bad;
3643 }
3644 
3652 function wfCanIPUseHTTPS( $ip ) {
3653  $canDo = true;
3654  Hooks::run( 'CanIPUseHTTPS', [ $ip, &$canDo ] );
3655  return !!$canDo;
3656 }
3657 
3665 function wfIsInfinity( $str ) {
3666  $infinityValues = [ 'infinite', 'indefinite', 'infinity', 'never' ];
3667  return in_array( $str, $infinityValues );
3668 }
3669 
3684 function wfThumbIsStandard( File $file, array $params ) {
3686 
3687  $multipliers = [ 1 ];
3688  if ( $wgResponsiveImages ) {
3689  // These available sizes are hardcoded currently elsewhere in MediaWiki.
3690  // @see Linker::processResponsiveImages
3691  $multipliers[] = 1.5;
3692  $multipliers[] = 2;
3693  }
3694 
3695  $handler = $file->getHandler();
3696  if ( !$handler || !isset( $params['width'] ) ) {
3697  return false;
3698  }
3699 
3700  $basicParams = [];
3701  if ( isset( $params['page'] ) ) {
3702  $basicParams['page'] = $params['page'];
3703  }
3704 
3705  $thumbLimits = [];
3706  $imageLimits = [];
3707  // Expand limits to account for multipliers
3708  foreach ( $multipliers as $multiplier ) {
3709  $thumbLimits = array_merge( $thumbLimits, array_map(
3710  function ( $width ) use ( $multiplier ) {
3711  return round( $width * $multiplier );
3712  }, $wgThumbLimits )
3713  );
3714  $imageLimits = array_merge( $imageLimits, array_map(
3715  function ( $pair ) use ( $multiplier ) {
3716  return [
3717  round( $pair[0] * $multiplier ),
3718  round( $pair[1] * $multiplier ),
3719  ];
3720  }, $wgImageLimits )
3721  );
3722  }
3723 
3724  // Check if the width matches one of $wgThumbLimits
3725  if ( in_array( $params['width'], $thumbLimits ) ) {
3726  $normalParams = $basicParams + [ 'width' => $params['width'] ];
3727  // Append any default values to the map (e.g. "lossy", "lossless", ...)
3728  $handler->normaliseParams( $file, $normalParams );
3729  } else {
3730  // If not, then check if the width matchs one of $wgImageLimits
3731  $match = false;
3732  foreach ( $imageLimits as $pair ) {
3733  $normalParams = $basicParams + [ 'width' => $pair[0], 'height' => $pair[1] ];
3734  // Decide whether the thumbnail should be scaled on width or height.
3735  // Also append any default values to the map (e.g. "lossy", "lossless", ...)
3736  $handler->normaliseParams( $file, $normalParams );
3737  // Check if this standard thumbnail size maps to the given width
3738  if ( $normalParams['width'] == $params['width'] ) {
3739  $match = true;
3740  break;
3741  }
3742  }
3743  if ( !$match ) {
3744  return false; // not standard for description pages
3745  }
3746  }
3747 
3748  // Check that the given values for non-page, non-width, params are just defaults
3749  foreach ( $params as $key => $value ) {
3750  if ( !isset( $normalParams[$key] ) || $normalParams[$key] != $value ) {
3751  return false;
3752  }
3753  }
3754 
3755  return true;
3756 }
3757 
3770 function wfArrayPlus2d( array $baseArray, array $newValues ) {
3771  // First merge items that are in both arrays
3772  foreach ( $baseArray as $name => &$groupVal ) {
3773  if ( isset( $newValues[$name] ) ) {
3774  $groupVal += $newValues[$name];
3775  }
3776  }
3777  // Now add items that didn't exist yet
3778  $baseArray += $newValues;
3779 
3780  return $baseArray;
3781 }
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
$wgDebugTimestamps
Prefix debug messages with relative timestamp.
wfGetDB($db, $groups=[], $wiki=false)
Get a Database object.
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:776
wfPercent($nr, $acc=2, $round=true)
the array() calling protocol came about after MediaWiki 1.4rc1.
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:1435
wfWaitForSlaves($ifWritesSince=null, $wiki=false, $cluster=false, $timeout=null)
Waits for the slaves to catch up to the master position.
wfCanIPUseHTTPS($ip)
Determine whether the client at a given source IP is likely to be able to access the wiki via HTTPS...
$wgScript
The URL path to index.php.
A statsd client that applies the sampling rate to the data items before sending them.
$wgVersion
MediaWiki version number.
$context
Definition: load.php:43
wfScript($script= 'index')
Get the path to a specified script file, respecting file extensions; this is a wrapper around $wgScri...
if(count($args)==0) $dir
static warning($msg, $callerOffset=1, $level=E_USER_NOTICE, $log= 'auto')
Adds a warning entry to the log.
Definition: MWDebug.php:151
wfIsHHVM()
Check if we are running under HHVM.
wfForeignMemcKey($db, $prefix)
Make a cache key for a foreign DB.
$wgShellCgroup
Under Linux: a cgroup directory used to constrain memory usage of shell commands. ...
$IP
Definition: WebStart.php:58
$wgDebugLogGroups
Map of string log group names to log destinations.
wfShorthandToInteger($string= '', $default=-1)
Converts shorthand byte notation to integer form.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
wfMkdirParents($dir, $mode=null, $caller=null)
Make directory, and make all parent directories if they don't exist.
wfDebugMem($exact=false)
Send a line giving PHP memory usage.
The Message class provides methods which fulfil two basic services:
Definition: Message.php:159
div flags Integer display flags(NO_ACTION_LINK, NO_EXTRA_USER_LINKS) 'LogException'returning false will NOT prevent logging $e
Definition: hooks.txt:1980
static instance()
Singleton.
Definition: Profiler.php:60
static header($code)
Output an HTTP status code header.
Definition: HttpStatus.php:96
$wgMaxShellFileSize
Maximum file size created by shell processes under linux, in KB ImageMagick convert for example can b...
$wgInternalServer
Internal server name as known to CDN, if different.
wfHostname()
Fetch server name for use in error reporting etc.
mimeTypeMatch($type, $avail)
Checks if a given MIME type matches any of the keys in the given array.
$wgMaxShellMemory
Maximum amount of virtual memory available to shell processes under linux, in KB. ...
static getInstance($id)
Get a cached instance of the specified type of cache object.
Definition: ObjectCache.php:93
wfRelativePath($path, $from)
Generate a relative path name to the given file.
wfFormatStackFrame($frame)
Return a string representation of frame.
$wgHttpsPort
Port where you have HTTPS running Supports HTTPS on non-standard ports.
$wgOverrideHostname
Override server hostname detection with a hardcoded value.
wfDebugBacktrace($limit=0)
Safety wrapper for debug_backtrace().
wfRunHooks($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in $wgHooks.
wfBacktrace($raw=null)
Get a debug backtrace as a string.
wfLogProfilingData()
A formatter that outputs unified diffs.
$source
wfLogDBError($text, array $context=[])
Log for database errors.
wfHttpError($code, $label, $desc)
Provide a simple HTTP error.
$value
const PROTO_CURRENT
Definition: Defines.php:265
wfAppendToArrayIfNotDefault($key, $value, $default, &$changed)
Appends to second array if $value differs from that in $default.
wfMessageFallback()
This function accepts multiple message keys and returns a message instance for the first message whic...
Stub profiler that does nothing.
wfMakeUrlIndexes($url)
Make URL indexes, appropriate for the el_index field of externallinks.
static getLocalClusterInstance()
Get the main cluster-local cache object.
wfUrlProtocolsWithoutProtRel()
Like wfUrlProtocols(), but excludes '//' from the protocol list.
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2588
$wgDisableOutputCompression
Disable output compression (enabled by default if zlib is available)
wfIsBadImage($name, $contextTitle=false, $blacklist=null)
Determine if an image exists on the 'bad image list'.
wfObjectToArray($objOrArray, $recursive=true)
Recursively converts the parameter (an object) to an array with the same data.
wfLoadExtension($ext, $path=null)
Load an extension.
wfShellExec($cmd, &$retval=null, $environ=[], $limits=[], $options=[])
Execute a shell command, with time and memory limits mirrored from the PHP configuration if supported...
wfUrlencode($s)
We want some things to be included as literal characters in our title URLs for prettiness, which urlencode encodes by default.
static newFromText($text, $defaultNamespace=NS_MAIN)
Create a new Title from text, such as what one would find in a link.
Definition: Title.php:256
$wgTmpDirectory
The local filesystem path to a temporary directory.
when a variable name is used in a it is silently declared as a new local masking the global
Definition: design.txt:93
wfExpandUrl($url, $defaultProto=PROTO_CURRENT)
Expand a potentially local URL to a fully-qualified URL.
wfBoolToStr($value)
Convenience function converts boolean values into "true" or "false" (string) values.
wfIsWindows()
Check if the operating system is Windows.
wfReportTime()
Returns a script tag that stores the amount of time it took MediaWiki to handle the request in millis...
wfLocalFile($title)
Get an object referring to a locally registered file.
wfExpandIRI($url)
Take a URL, make sure it's expanded to fully qualified, and replace any encoded non-ASCII Unicode cha...
wfStripIllegalFilenameChars($name)
Replace all invalid characters with '-'.
wfGetMessageCacheStorage()
Get the cache object used by the message cache.
wfRandomString($length=32)
Get a random string containing a number of pseudo-random hex characters.
static makeVariablesScript($data)
Definition: Skin.php:326
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1629
wfNegotiateType($cprefs, $sprefs)
Returns the 'best' match between a client's requested internet media types and the server's list of a...
wfArrayDiff2($a, $b)
Like array_diff( $a, $b ) except that it works with two-dimensional arrays.
wfDebug($text, $dest= 'all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfGetParserCacheStorage()
Get the cache object used by the parser cache.
static fetchLanguageNames($inLanguage=null, $include= 'mw')
Get an array of language names, indexed by code.
Definition: Language.php:798
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as $wgLang
Definition: design.txt:56
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 '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. 'LanguageGetMagic':DEPRECATED!Use $magicWords in a file listed in $wgExtensionMessagesFiles instead.Use this to define synonyms of magic words depending of the language &$magicExtensions:associative array of magic words synonyms $lang:language code(string) '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 'LanguageGetSpecialPageAliases':DEPRECATED!Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead.Use to define aliases of special pages names depending of the language &$specialPageAliases:associative array of magic words synonyms $lang:language code(string) '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:Associative array mapping language codes to prefixed links of the form"language:title".&$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!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:1814
wfGlobalCacheKey()
Make a cache key with database-agnostic prefix.
if($line===false) $args
Definition: cdb.php:64
$wgDebugRawPage
If true, log debugging data from action=raw and load.php.
$factory
$last
wfTimestamp($outputtype=TS_UNIX, $ts=0)
Get a timestamp string in one of various formats.
$wgPhpCli
Executable path of the PHP cli binary (php/php5).
wfMsgReplaceArgs($message, $args)
Replace message parameter keys on the given formatted output.
$wgLanguageCode
Site language code.
wfCountDown($seconds)
Count down from $seconds to zero on the terminal, with a one-second pause between showing each number...
static edits()
Definition: SiteStats.php:129
$wgExtensionDirectory
Filesystem extensions directory.
wfCgiToArray($query)
This is the logical opposite of wfArrayToCgi(): it accepts a query string as its argument and returns...
wfDebugLog($logGroup, $text, $dest= 'all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not...
wfLoadExtensions(array $exts)
Load multiple extensions at once.
wfIsDebugRawPage()
Returns true if debug logging should be suppressed if $wgDebugRawPage = false.
global $wgCommandLineMode
Definition: Setup.php:511
wfConfiguredReadOnlyReason()
Get the value of $wgReadOnly or the contents of $wgReadOnlyFile.
wfDiff($before, $after, $params= '-u')
Returns unified plain-text diff of two texts.
const PROTO_HTTPS
Definition: Defines.php:263
wfResetOutputBuffers($resetGzipEncoding=true)
Clear away any user-level output buffers, discarding contents.
wfGetLB($wiki=false)
Get a load balancer object.
Exception class for replica DB wait timeouts.
Definition: LBFactory.php:472
wfEscapeWikiText($text)
Escapes the given text so that it may be output using addWikiText() without any linking, formatting, etc.
wfReadOnly()
Check whether the wiki is in read-only mode.
$wgParserCacheType
The cache type for storing article HTML.
wfSetBit(&$dest, $bit, $state=true)
As for wfSetVar except setting a bit.
wfAssembleUrl($urlParts)
This function will reassemble a URL parsed with wfParseURL.
wfTempDir()
Tries to get the system directory for temporary files.
const SHELL_MAX_ARG_STRLEN
Definition: Defines.php:313
static getMain()
Static methods.
unserialize($serialized)
Definition: ApiMessage.php:102
wfMergeErrorArrays()
Merge arrays in the style of getUserPermissionsErrors, with duplicate removal e.g.
static deprecated($function, $version=false, $component=false, $callerOffset=2)
Show a warning that $function is deprecated.
Definition: MWDebug.php:193
wfGetCache($cacheType)
Get a specific cache object.
wfAppendQuery($url, $query)
Append a query string to an existing URL, which may or may not already have query string parameters a...
$wgIllegalFileChars
Additional characters that are not allowed in filenames.
wfShellWikiCmd($script, array $parameters=[], array $options=[])
Generate a shell-escaped command line string to run a MediaWiki cli script.
const PROTO_INTERNAL
Definition: Defines.php:267
wfWarn($msg, $callerOffset=1, $level=E_USER_NOTICE)
Send a warning either to the debug log or in a PHP error depending on $wgDevelopmentWarnings.
getHandler()
Get a MediaHandler instance for this file.
Definition: File.php:1364
wfIniGetBool($setting)
Safety wrapper around ini_get() for boolean settings.
if($limit) $timestamp
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context $options
Definition: hooks.txt:1020
wfClientAcceptsGzip($force=false)
static singleton()
Get a RepoGroup instance.
Definition: RepoGroup.php:59
static isStoragePath($path)
Check if a given path is a "mwstore://" path.
$wgMessageCacheType
The cache type for storing the contents of the MediaWiki namespace.
$wgMiserMode
Disable database-intensive features.
wfMatchesDomainList($url, $domains)
Check whether a given URL has a domain that occurs in a given set of domains.
MediaWiki exception.
Definition: MWException.php:26
wfTimestampNow()
Convenience function; returns MediaWiki timestamp for the present time.
wfErrorLog($text, $file, array $context=[])
Log to a file without getting "file size exceeded" signals.
$wgImageLimits
Limit images on image description pages to a user-selectable limit.
Class representing a 'diff' between two sequences of strings.
wfLoadSkin($skin, $path=null)
Load a skin.
$cache
Definition: mcc.php:33
$params
$wgThumbLimits
Adjust thumbnails on image pages according to a user setting.
wfIsInfinity($str)
Determine input string is represents as infinity.
CACHE_MEMCACHED $wgMainCacheType
Definition: memcached.txt:63
wfDeprecated($function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
wfIncrStats($key, $count=1)
Increment a statistics counter.
wfExpandIRI_callback($matches)
Private callback for wfExpandIRI.
$tokens
$wgMaxShellWallClockTime
Maximum wall clock time (i.e.
wfBCP47($code)
Get the normalised IETF language tag See unit test for examples.
Allows to change the fields on the form that will be generated are created Can be used to omit specific feeds from being outputted You must not use this hook to add use OutputPage::addFeedLink() instead.&$feedLinks conditions will AND in the final query as a Content object as a Content object $title
Definition: hooks.txt:312
wfLoadSkins(array $skins)
Load multiple skins at once.
static run($event, array $args=[], $deprecatedVersion=null)
Call hook functions defined in Hooks::register and $wgHooks.
Definition: Hooks.php:131
wfQueriesMustScale()
Should low-performance queries be disabled?
wfWikiID()
Get an ASCII string identifying this wiki This is used as a prefix in memcached keys.
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:1816
$wgMaxShellTime
Maximum CPU time in seconds for shell processes under Linux.
wfShowingResults($offset, $limit)
wfArrayDiff2_cmp($a, $b)
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:1816
wfInitShellLocale()
Workaround for http://bugs.php.net/bug.php?id=45132 escapeshellarg() destroys non-ASCII characters if...
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
wfVarDump($var)
A wrapper around the PHP function var_export().
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:776
wfSuppressWarnings($end=false)
Reference-counted warning suppression.
const PROTO_HTTP
Definition: Defines.php:262
wfMerge($old, $mine, $yours, &$result)
wfMerge attempts to merge differences between three texts.
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account $user
Definition: hooks.txt:242
$wgDebugLogPrefix
Prefix for debug log lines.
wfUsePHP($req_ver)
This function works like "use VERSION" in Perl, the program will die with a backtrace if the current ...
wfShellExecDisabled()
Check if wfShellExec() is effectively disabled via php.ini config.
$wgShellLocale
Locale for LC_CTYPE, to work around http://bugs.php.net/bug.php?id=45132 For Unix-like operating syst...
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object & $output
Definition: hooks.txt:1020
const TS_MW
MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
wfFixSessionID()
$wgReadOnly
Set this to a string to put the wiki into read-only mode.
wfGetAllCallers($limit=3)
Return a string consisting of callers in the stack.
wfArrayInsertAfter(array $array, array $insert, $after)
Insert array into another array after the specified KEY
wfUrlProtocols($includeProtocolRelative=true)
Returns a regular expression of url protocols.
$wgMemoryLimit
The minimum amount of memory that MediaWiki "needs"; MediaWiki will try to raise PHP's memory limit...
$wgDiff3
Path to the GNU diff3 utility.
wfRemoveDotSegments($urlPath)
Remove all dot-segments in the provided URL path.
$from
$wgReadOnlyFile
If this lock file exists (size > 0), the wiki will be forced into read-only mode. ...
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...
wfGetLBFactory()
Get the load balancer factory object.
wfBaseName($path, $suffix= '')
Return the final portion of a pathname.
const PROTO_CANONICAL
Definition: Defines.php:266
wfBaseConvert($input, $sourceBase, $destBase, $pad=1, $lowercase=true, $engine= 'auto')
Convert an arbitrarily-long digit string from one numeric base to another, optionally zero-padding to...
wfRandom()
Get a random decimal value between 0 and 1, in a way not likely to give duplicate values for any real...
$lines
Definition: router.php:66
error also a ContextSource you ll probably need to make sure the header is varied on $request
Definition: hooks.txt:2458
wfReadOnlyReason()
Check if the site is in read-only mode and return the message if so.
wfUnpack($format, $data, $length=false)
Wrapper around php's unpack.
wfUseMW($req_ver)
This function works like "use VERSION" in Perl except it checks the version of MediaWiki, the program will die with a backtrace if the current version of MediaWiki is less than the version provided.
$wgScriptPath
The path we should point to.
static getLocalServerInstance($fallback=CACHE_NONE)
Factory function for CACHE_ACCEL (referenced from DefaultSettings.php)
wfGetMainCache()
Get the main cache object.
static pages()
Definition: SiteStats.php:145
wfArrayToCgi($array1, $array2=null, $prefix= '')
This function takes one or two arrays as input, and returns a CGI-style string, e.g.
$line
Definition: cdb.php:59
$wgDBprefix
Table name prefix.
wfRestoreWarnings()
$wgStyleDirectory
Filesystem stylesheets directory.
wfRecursiveRemoveDir($dir)
Remove a directory and all its content.
wfMemoryLimit()
Set PHP's memory limit to the larger of php.ini or $wgMemoryLimit.
wfClearOutputBuffers()
More legible than passing a 'false' parameter to wfResetOutputBuffers():
$wgCanonicalServer
Canonical URL of the server, to use in IRC feeds and notification e-mails.
wfTransactionalTimeLimit()
Set PHP's time limit to the larger of php.ini or $wgTransactionalTimeLimit.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set and then return false from the hook function Ensure you consume the ChangeTagAfterDelete hook to carry out custom deletion actions as context called by AbstractContent::getParserOutput May be used to override the normal model specific rendering of page content as context as context the output can only depend on parameters provided to this hook not on global state indicating whether full HTML should be generated If generation of HTML may be but other information should still be present in the ParserOutput object to manipulate or replace but no entry for that model exists in $wgContentHandlers if desired 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 inclusive $limit
Definition: hooks.txt:1020
this class mediates it Skin Encapsulates a look and feel for the wiki All of the functions that render HTML and make choices about how to render it are here and are called from various other places when and is meant to be subclassed with other skins that may override some of its functions The User object contains a reference to a and so rather than having a global skin object we just rely on the global User and get the skin with $wgUser and also has some character encoding functions and other locale stuff The current user interface language is instantiated as and the local content language as $wgContLang
Definition: design.txt:56
wfSetupSession($sessionId=false)
Initialise php session.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist e g Watchlist removed from all revisions and log entries to which it was applied This gives extensions a chance to take it off their books as the deletion has already been partly carried out by this point or something similar the user will be unable to create the tag set $status
Definition: hooks.txt:1020
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
static consume(ScopedCallback &$sc=null)
Trigger a scoped callback and destroy it.
$count
wfEscapeShellArg()
Windows-compatible version of escapeshellarg() Windows doesn't recognise single-quotes in the shell...
static legalChars()
Get a regex character class describing the legal characters in a link.
Definition: Title.php:585
wfAcceptToPrefs($accept, $def= '*/*')
Converts an Accept-* header into an array mapping string values to quality factors.
$wgServer
URL of the server.
wfMemcKey()
Make a cache key for the local wiki.
$wgOut
Definition: Setup.php:811
$version
Definition: parserTests.php:94
wfSplitWikiID($wiki)
Split a wiki ID into DB name and table prefix.
wfLogWarning($msg, $callerOffset=1, $level=E_USER_WARNING)
Send a warning as a PHP error and the debug log.
const TS_UNIX
Unix time - the number of seconds since 1970-01-01 00:00:00 UTC.
This serves as the entry point to the MediaWiki session handling system.
wfResetSessionID()
Reset the session id.
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:776
static logException($e)
Log an exception to the exception log (if enabled).
controlled by $wgMainCacheType controlled by $wgParserCacheType controlled by $wgMessageCacheType If you set CACHE_NONE to one of the three control default value for MediaWiki still create a but requests to it are no ops and we always fall through to the database If the cache daemon can t be it should also disable itself fairly smoothly By $wgMemc is used but when it is $parserMemc or $messageMemc this is mentioned $wgDBname
Definition: memcached.txt:96
wfTimestampOrNull($outputtype=TS_UNIX, $ts=null)
Return a formatted timestamp, or null if input is null.
float $wgRequestTime
Request start time as fractional seconds since epoch.
Definition: WebStart.php:43
wfParseUrl($url)
parse_url() work-alike, but non-broken.
static factory($code)
Get a cached or new language object for a given language code.
Definition: Language.php:179
wfArrayPlus2d(array $baseArray, array $newValues)
Merges two (possibly) 2 dimensional arrays into the target array ($baseArray).
wfShellExecWithStderr($cmd, &$retval=null, $environ=[], $limits=[])
Execute a shell command, returning both stdout and stderr.
Implements some public methods and some protected utility functions which are required by multiple ch...
Definition: File.php:50
wfGetPrecompiledData($name)
Get an object from the precompiled serialized directory.
$wgResponsiveImages
Generate and use thumbnails suitable for screens with 1.5 and 2.0 pixel densities.
$wgDiff
Path to the GNU diff utility.
wfMessage($key)
This is the function for getting translated interface messages.
$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.
please add to it if you re going to add events to the MediaWiki code where normally authentication against an external auth plugin would be creating a local account incomplete not yet checked for validity & $retval
Definition: hooks.txt:242
wfFindFile($title, $options=[])
Find a file.
Library for creating and parsing MW-style timestamps.
Definition: MWTimestamp.php:31
static users()
Definition: SiteStats.php:153
if(is_null($wgLocalTZoffset)) if(!$wgDBerrorLogTZ) $wgRequest
Definition: Setup.php:663
do that in ParserLimitReportFormat instead use this to modify the parameters of the image and a DIV can begin in one section and end in another Make sure your code can handle that case gracefully See the EditSectionClearerLink extension for an example zero but section is usually empty its values are the globals values before the output is cached one of or reset my talk my contributions etc etc otherwise the built in rate limiting checks are if enabled allows for interception of redirect as a string mapping parameter names to values & $type
Definition: hooks.txt:2376
wfGetCaller($level=2)
Get the name of the function which called this function wfGetCaller( 1 ) is the function with the wfG...
wfGetLangObj($langcode=false)
Return a Language object from $langcode.
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...
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:310