Merge "Add documentation for wfClientAcceptsGzip()"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 25 Oct 2016 21:45:03 +0000 (21:45 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 25 Oct 2016 21:45:03 +0000 (21:45 +0000)
1  2 
includes/GlobalFunctions.php

@@@ -26,19 -26,84 +26,19 @@@ if ( !defined( 'MEDIAWIKI' ) ) 
  
  use Liuggio\StatsdClient\Sender\SocketSender;
  use MediaWiki\Logger\LoggerFactory;
 +use MediaWiki\Session\SessionManager;
 +use Wikimedia\ScopedCallback;
  
  // Hide compatibility functions from Doxygen
  /// @cond
 -
  /**
   * Compatibility functions
   *
 - * We support PHP 5.3.3 and up.
 + * We support PHP 5.5.9 and up.
   * Re-implementations of newer functions or functions in non-standard
   * PHP extensions may be included here.
   */
  
 -if ( !function_exists( 'mb_substr' ) ) {
 -      /**
 -       * @codeCoverageIgnore
 -       * @see Fallback::mb_substr
 -       * @return string
 -       */
 -      function mb_substr( $str, $start, $count = 'end' ) {
 -              return Fallback::mb_substr( $str, $start, $count );
 -      }
 -
 -      /**
 -       * @codeCoverageIgnore
 -       * @see Fallback::mb_substr_split_unicode
 -       * @return int
 -       */
 -      function mb_substr_split_unicode( $str, $splitPos ) {
 -              return Fallback::mb_substr_split_unicode( $str, $splitPos );
 -      }
 -}
 -
 -if ( !function_exists( 'mb_strlen' ) ) {
 -      /**
 -       * @codeCoverageIgnore
 -       * @see Fallback::mb_strlen
 -       * @return int
 -       */
 -      function mb_strlen( $str, $enc = '' ) {
 -              return Fallback::mb_strlen( $str, $enc );
 -      }
 -}
 -
 -if ( !function_exists( 'mb_strpos' ) ) {
 -      /**
 -       * @codeCoverageIgnore
 -       * @see Fallback::mb_strpos
 -       * @return int
 -       */
 -      function mb_strpos( $haystack, $needle, $offset = 0, $encoding = '' ) {
 -              return Fallback::mb_strpos( $haystack, $needle, $offset, $encoding );
 -      }
 -}
 -
 -if ( !function_exists( 'mb_strrpos' ) ) {
 -      /**
 -       * @codeCoverageIgnore
 -       * @see Fallback::mb_strrpos
 -       * @return int
 -       */
 -      function mb_strrpos( $haystack, $needle, $offset = 0, $encoding = '' ) {
 -              return Fallback::mb_strrpos( $haystack, $needle, $offset, $encoding );
 -      }
 -}
 -
 -// gzdecode function only exists in PHP >= 5.4.0
 -// http://php.net/gzdecode
 -if ( !function_exists( 'gzdecode' ) ) {
 -      /**
 -       * @codeCoverageIgnore
 -       * @param string $data
 -       * @return string
 -       */
 -      function gzdecode( $data ) {
 -              return gzinflate( substr( $data, 10, -8 ) );
 -      }
 -}
 -
  // hash_equals function only exists in PHP >= 5.6.0
  // http://php.net/hash_equals
  if ( !function_exists( 'hash_equals' ) ) {
@@@ -223,30 -288,30 +223,30 @@@ function wfAppendToArrayIfNotDefault( $
   * Merge arrays in the style of getUserPermissionsErrors, with duplicate removal
   * e.g.
   *    wfMergeErrorArrays(
 - *            array( array( 'x' ) ),
 - *            array( array( 'x', '2' ) ),
 - *            array( array( 'x' ) ),
 - *            array( array( 'y' ) )
 + *            [ [ 'x' ] ],
 + *            [ [ 'x', '2' ] ],
 + *            [ [ 'x' ] ],
 + *            [ [ 'y' ] ]
   *    );
   * returns:
 - *            array(
 - *            array( 'x', '2' ),
 - *            array( 'x' ),
 - *            array( 'y' )
 - *    )
 + *            [
 + *            [ 'x', '2' ],
 + *            [ 'x' ],
 + *            [ 'y' ]
 + *    ]
   *
   * @param array $array1,...
   * @return array
   */
  function wfMergeErrorArrays( /*...*/ ) {
        $args = func_get_args();
 -      $out = array();
 +      $out = [];
        foreach ( $args as $errors ) {
                foreach ( $errors as $params ) {
                        $originalParams = $params;
                        if ( $params[0] instanceof MessageSpecifier ) {
                                $msg = $params[0];
 -                              $params = array_merge( array( $msg->getKey() ), $msg->getParams() );
 +                              $params = array_merge( [ $msg->getKey() ], $msg->getParams() );
                        }
                        # @todo FIXME: Sometimes get nested arrays for $params,
                        # which leads to E_NOTICEs
@@@ -289,7 -354,7 +289,7 @@@ function wfArrayInsertAfter( array $arr
   * @return array
   */
  function wfObjectToArray( $objOrArray, $recursive = true ) {
 -      $array = array();
 +      $array = [];
        if ( is_object( $objOrArray ) ) {
                $objOrArray = get_object_vars( $objOrArray );
        }
@@@ -359,7 -424,7 +359,7 @@@ function wfRandomString( $length = 32 
   *
   * ;:@$!*(),/~
   *
 - * However, IIS7 redirects fail when the url contains a colon (Bug 22709),
 + * However, IIS7 redirects fail when the url contains a colon (see T24709),
   * so no fancy : for IIS7.
   *
   * %2F in the page titles seems to fatally break for some reason.
@@@ -376,7 -441,7 +376,7 @@@ function wfUrlencode( $s ) 
        }
  
        if ( is_null( $needle ) ) {
 -              $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F', '%7E' );
 +              $needle = [ '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F', '%7E' ];
                if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) ||
                        ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false )
                ) {
        $s = urlencode( $s );
        $s = str_ireplace(
                $needle,
 -              array( ';', '@', '$', '!', '*', '(', ')', ',', '/', '~', ':' ),
 +              [ ';', '@', '$', '!', '*', '(', ')', ',', '/', '~', ':' ],
                $s
        );
  
@@@ -454,7 -519,7 +454,7 @@@ function wfCgiToArray( $query ) 
                $query = substr( $query, 1 );
        }
        $bits = explode( '&', $query );
 -      $ret = array();
 +      $ret = [];
        foreach ( $bits as $bit ) {
                if ( $bit === '' ) {
                        continue;
                        $temp = $value;
                        foreach ( $keys as $k ) {
                                $k = substr( $k, 0, -1 );
 -                              $temp = array( $k => $temp );
 +                              $temp = [ $k => $temp ];
                        }
                        if ( isset( $ret[$key] ) ) {
                                $ret[$key] = array_merge( $ret[$key], $temp );
@@@ -501,26 -566,12 +501,26 @@@ function wfAppendQuery( $url, $query ) 
                $query = wfArrayToCgi( $query );
        }
        if ( $query != '' ) {
 +              // Remove the fragment, if there is one
 +              $fragment = false;
 +              $hashPos = strpos( $url, '#' );
 +              if ( $hashPos !== false ) {
 +                      $fragment = substr( $url, $hashPos );
 +                      $url = substr( $url, 0, $hashPos );
 +              }
 +
 +              // Add parameter
                if ( false === strpos( $url, '?' ) ) {
                        $url .= '?';
                } else {
                        $url .= '&';
                }
                $url .= $query;
 +
 +              // Put the fragment back
 +              if ( $fragment !== false ) {
 +                      $url .= $fragment;
 +              }
        }
        return $url;
  }
@@@ -618,7 -669,7 +618,7 @@@ function wfExpandUrl( $url, $defaultPro
   * This is the basic structure used (brackets contain keys for $urlParts):
   * [scheme][delimiter][user]:[pass]@[host]:[port][path]?[query]#[fragment]
   *
 - * @todo Need to integrate this into wfExpandUrl (bug 32168)
 + * @todo Need to integrate this into wfExpandUrl (see T34168)
   *
   * @since 1.19
   * @param array $urlParts URL parts, as output from wfParseUrl
@@@ -671,7 -722,7 +671,7 @@@ function wfAssembleUrl( $urlParts ) 
   * '/a/./b/../c/' becomes '/a/c/'.  For details on the algorithm, please see
   * RFC3986 section 5.2.4.
   *
 - * @todo Need to integrate this into wfExpandUrl (bug 32168)
 + * @todo Need to integrate this into wfExpandUrl (see T34168)
   *
   * @param string $urlPath URL path, potentially containing dot-segments
   * @return string URL path with all dot-segments removed
@@@ -767,7 -818,7 +767,7 @@@ function wfUrlProtocols( $includeProtoc
        // Support old-style $wgUrlProtocols strings, for backwards compatibility
        // with LocalSettings files from 1.5
        if ( is_array( $wgUrlProtocols ) ) {
 -              $protocols = array();
 +              $protocols = [];
                foreach ( $wgUrlProtocols as $protocol ) {
                        // Filter out '//' if !$includeProtocolRelative
                        if ( $includeProtocolRelative || $protocol !== '//' ) {
@@@ -812,7 -863,7 +812,7 @@@ function wfUrlProtocolsWithoutProtRel(
   * 3) Adds a "delimiter" element to the array, either '://', ':' or '//' (see (2)).
   *
   * @param string $url A URL to parse
 - * @return string[] Bits of the URL in an associative array, per PHP docs
 + * @return string[]|bool Bits of the URL in an associative array, per PHP docs, false on failure
   */
  function wfParseUrl( $url ) {
        global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
        $bits = parse_url( $url );
        MediaWiki\restoreWarnings();
        // parse_url() returns an array without scheme for some invalid URLs, e.g.
 -      // parse_url("%0Ahttp://example.com") == array( 'host' => '%0Ahttp', 'path' => 'example.com' )
 +      // parse_url("%0Ahttp://example.com") == [ 'host' => '%0Ahttp', 'path' => 'example.com' ]
        if ( !$bits || !isset( $bits['scheme'] ) ) {
                return false;
        }
                return false;
        }
  
 -      /* Provide an empty host for eg. file:/// urls (see bug 28627) */
 +      /* Provide an empty host for eg. file:/// urls (see T30627) */
        if ( !isset( $bits['host'] ) ) {
                $bits['host'] = '';
  
 -              // bug 45069
 +              // See T47069
                if ( isset( $bits['path'] ) ) {
                        /* parse_url loses the third / for file:///c:/ urls (but not on variants) */
                        if ( substr( $bits['path'], 0, 1 ) !== '/' ) {
@@@ -949,9 -1000,9 +949,9 @@@ function wfMakeUrlIndexes( $url ) 
        }
  
        if ( $prot == '' ) {
 -              return array( "http:$index", "https:$index" );
 +              return [ "http:$index", "https:$index" ];
        } else {
 -              return array( $index );
 +              return [ $index ];
        }
  }
  
@@@ -987,15 -1038,10 +987,15 @@@ function wfMatchesDomainList( $url, $do
   * @since 1.25 support for additional context data
   *
   * @param string $text
 - * @param string|bool $dest Unused
 + * @param string|bool $dest Destination of the message:
 + *     - 'all': both to the log and HTML (debug toolbar or HTML comments)
 + *     - 'private': excluded from HTML output
 + *   For backward compatibility, it can also take a boolean:
 + *     - true: same as 'all'
 + *     - false: same as 'private'
   * @param array $context Additional logging context data
   */
 -function wfDebug( $text, $dest = 'all', array $context = array() ) {
 +function wfDebug( $text, $dest = 'all', array $context = [] ) {
        global $wgDebugRawPage, $wgDebugLogPrefix;
        global $wgDebugTimestamps, $wgRequestTime;
  
        if ( $wgDebugLogPrefix !== '' ) {
                $context['prefix'] = $wgDebugLogPrefix;
        }
 +      $context['private'] = ( $dest === false || $dest === 'private' );
  
        $logger = LoggerFactory::getInstance( 'wfDebug' );
        $logger->debug( $text, $context );
@@@ -1081,6 -1126,7 +1081,6 @@@ function wfDebugMem( $exact = false ) 
   * @param string $text
   * @param string|bool $dest Destination of the message:
   *     - 'all': both to the log and HTML (debug toolbar or HTML comments)
 - *     - 'log': only to the log and not in HTML
   *     - 'private': only to the specific log if set in $wgDebugLogGroups and
   *       discarded otherwise
   *   For backward compatibility, it can also take a boolean:
   * @param array $context Additional logging context data
   */
  function wfDebugLog(
 -      $logGroup, $text, $dest = 'all', array $context = array()
 +      $logGroup, $text, $dest = 'all', array $context = []
  ) {
 -      // Turn $dest into a string if it's a boolean (for b/c)
 -      if ( $dest === true ) {
 -              $dest = 'all';
 -      } elseif ( $dest === false ) {
 -              $dest = 'private';
 -      }
 -
        $text = trim( $text );
  
        $logger = LoggerFactory::getInstance( $logGroup );
 -      $context['private'] = ( $dest === 'private' );
 +      $context['private'] = ( $dest === false || $dest === 'private' );
        $logger->info( $text, $context );
  }
  
   * @param string $text Database error message.
   * @param array $context Additional logging context data
   */
 -function wfLogDBError( $text, array $context = array() ) {
 +function wfLogDBError( $text, array $context = [] ) {
        $logger = LoggerFactory::getInstance( 'wfLogDBError' );
        $logger->error( trim( $text ), $context );
  }
@@@ -1168,7 -1221,7 +1168,7 @@@ function wfLogWarning( $msg, $callerOff
   * @throws MWException
   * @deprecated since 1.25 Use \MediaWiki\Logger\LegacyLogger::emit or UDPTransport
   */
 -function wfErrorLog( $text, $file, array $context = array() ) {
 +function wfErrorLog( $text, $file, array $context = [] ) {
        wfDeprecated( __METHOD__, '1.25' );
        $logger = LoggerFactory::getInstance( 'wfErrorLog' );
        $context['destination'] = $file;
@@@ -1196,7 -1249,6 +1196,7 @@@ function wfLogProfilingData() 
                        $statsdPort = isset( $statsdServer[1] ) ? $statsdServer[1] : 8125;
                        $statsdSender = new SocketSender( $statsdHost, $statsdPort );
                        $statsdClient = new SamplingStatsdClient( $statsdSender, true, false );
 +                      $statsdClient->setSamplingRates( $config->get( 'StatsdSamplingRates' ) );
                        $statsdClient->send( $context->getStats()->getBuffer() );
                } catch ( Exception $ex ) {
                        MWExceptionHandler::logException( $ex );
                return;
        }
  
 -      $ctx = array( 'elapsed' => $request->getElapsedTime() );
 +      $ctx = [ 'elapsed' => $request->getElapsedTime() ];
        if ( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
                $ctx['forwarded_for'] = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
@@@ -1279,7 -1331,7 +1279,7 @@@ function wfReadOnly() 
   * Check if the site is in read-only mode and return the message if so
   *
   * This checks wfConfiguredReadOnlyReason() and the main load balancer
 - * for slave lag. This may result in DB_SLAVE connection being made.
 + * for replica DB lag. This may result in DB connection being made.
   *
   * @return string|bool String when in read-only mode; false otherwise
   */
@@@ -1410,6 -1462,159 +1410,6 @@@ function wfMessageFallback( /*...*/ ) 
        return call_user_func_array( 'Message::newFallbackSequence', $args );
  }
  
 -/**
 - * Get a message from anywhere, for the current user language.
 - *
 - * Use wfMsgForContent() instead if the message should NOT
 - * change depending on the user preferences.
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key Lookup key for the message, usually
 - *    defined in languages/Language.php
 - *
 - * Parameters to the message, which can be used to insert variable text into
 - * it, can be passed to this function in the following formats:
 - * - One per argument, starting at the second parameter
 - * - As an array in the second parameter
 - * These are not shown in the function definition.
 - *
 - * @return string
 - */
 -function wfMsg( $key ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      $args = func_get_args();
 -      array_shift( $args );
 -      return wfMsgReal( $key, $args );
 -}
 -
 -/**
 - * Same as above except doesn't transform the message
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key
 - * @return string
 - */
 -function wfMsgNoTrans( $key ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      $args = func_get_args();
 -      array_shift( $args );
 -      return wfMsgReal( $key, $args, true, false, false );
 -}
 -
 -/**
 - * Get a message from anywhere, for the current global language
 - * set with $wgLanguageCode.
 - *
 - * Use this if the message should NOT change dependent on the
 - * language set in the user's preferences. This is the case for
 - * most text written into logs, as well as link targets (such as
 - * the name of the copyright policy page). Link titles, on the
 - * other hand, should be shown in the UI language.
 - *
 - * Note that MediaWiki allows users to change the user interface
 - * language in their preferences, but a single installation
 - * typically only contains content in one language.
 - *
 - * Be wary of this distinction: If you use wfMsg() where you should
 - * use wfMsgForContent(), a user of the software may have to
 - * customize potentially hundreds of messages in
 - * order to, e.g., fix a link in every possible language.
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key Lookup key for the message, usually
 - *     defined in languages/Language.php
 - * @return string
 - */
 -function wfMsgForContent( $key ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      global $wgForceUIMsgAsContentMsg;
 -      $args = func_get_args();
 -      array_shift( $args );
 -      $forcontent = true;
 -      if ( is_array( $wgForceUIMsgAsContentMsg )
 -              && in_array( $key, $wgForceUIMsgAsContentMsg )
 -      ) {
 -              $forcontent = false;
 -      }
 -      return wfMsgReal( $key, $args, true, $forcontent );
 -}
 -
 -/**
 - * Same as above except doesn't transform the message
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key
 - * @return string
 - */
 -function wfMsgForContentNoTrans( $key ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      global $wgForceUIMsgAsContentMsg;
 -      $args = func_get_args();
 -      array_shift( $args );
 -      $forcontent = true;
 -      if ( is_array( $wgForceUIMsgAsContentMsg )
 -              && in_array( $key, $wgForceUIMsgAsContentMsg )
 -      ) {
 -              $forcontent = false;
 -      }
 -      return wfMsgReal( $key, $args, true, $forcontent, false );
 -}
 -
 -/**
 - * Really get a message
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key Key to get.
 - * @param array $args
 - * @param bool $useDB
 - * @param string|bool $forContent Language code, or false for user lang, true for content lang.
 - * @param bool $transform Whether or not to transform the message.
 - * @return string The requested message.
 - */
 -function wfMsgReal( $key, $args, $useDB = true, $forContent = false, $transform = true ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      $message = wfMsgGetKey( $key, $useDB, $forContent, $transform );
 -      $message = wfMsgReplaceArgs( $message, $args );
 -      return $message;
 -}
 -
 -/**
 - * Fetch a message string value, but don't replace any keys yet.
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key
 - * @param bool $useDB
 - * @param string|bool $langCode Code of the language to get the message for, or
 - *   behaves as a content language switch if it is a boolean.
 - * @param bool $transform Whether to parse magic words, etc.
 - * @return string
 - */
 -function wfMsgGetKey( $key, $useDB = true, $langCode = false, $transform = true ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      Hooks::run( 'NormalizeMessageKey', array( &$key, &$useDB, &$langCode, &$transform ) );
 -
 -      $cache = MessageCache::singleton();
 -      $message = $cache->get( $key, $useDB, $langCode );
 -      if ( $message === false ) {
 -              $message = '&lt;' . htmlspecialchars( $key ) . '&gt;';
 -      } elseif ( $transform ) {
 -              $message = $cache->transform( $message );
 -      }
 -      return $message;
 -}
 -
  /**
   * Replace message parameter keys on the given formatted output.
   *
@@@ -1424,11 -1629,11 +1424,11 @@@ function wfMsgReplaceArgs( $message, $a
        $message = str_replace( "\r", '', $message );
  
        // Replace arguments
 -      if ( count( $args ) ) {
 +      if ( is_array( $args ) && $args ) {
                if ( is_array( $args[0] ) ) {
                        $args = array_values( $args[0] );
                }
 -              $replacementKeys = array();
 +              $replacementKeys = [];
                foreach ( $args as $n => $param ) {
                        $replacementKeys['$' . ( $n + 1 )] = $param;
                }
        return $message;
  }
  
 -/**
 - * Return an HTML-escaped version of a message.
 - * Parameter replacements, if any, are done *after* the HTML-escaping,
 - * so parameters may contain HTML (eg links or form controls). Be sure
 - * to pre-escape them if you really do want plaintext, or just wrap
 - * the whole thing in htmlspecialchars().
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key
 - * @param string $args,... Parameters
 - * @return string
 - */
 -function wfMsgHtml( $key ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      $args = func_get_args();
 -      array_shift( $args );
 -      return wfMsgReplaceArgs( htmlspecialchars( wfMsgGetKey( $key ) ), $args );
 -}
 -
 -/**
 - * Return an HTML version of message
 - * Parameter replacements, if any, are done *after* parsing the wiki-text message,
 - * so parameters may contain HTML (eg links or form controls). Be sure
 - * to pre-escape them if you really do want plaintext, or just wrap
 - * the whole thing in htmlspecialchars().
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key
 - * @param string $args,... Parameters
 - * @return string
 - */
 -function wfMsgWikiHtml( $key ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      $args = func_get_args();
 -      array_shift( $args );
 -      return wfMsgReplaceArgs(
 -              MessageCache::singleton()->parse( wfMsgGetKey( $key ), null,
 -              /* can't be set to false */ true, /* interface */ true )->getText(),
 -              $args );
 -}
 -
 -/**
 - * Returns message in the requested format
 - *
 - * @deprecated since 1.18
 - *
 - * @param string $key Key of the message
 - * @param array $options Processing rules.
 - *   Can take the following options:
 - *     parse: parses wikitext to HTML
 - *     parseinline: parses wikitext to HTML and removes the surrounding
 - *       p's added by parser or tidy
 - *     escape: filters message through htmlspecialchars
 - *     escapenoentities: same, but allows entity references like &#160; through
 - *     replaceafter: parameters are substituted after parsing or escaping
 - *     parsemag: transform the message using magic phrases
 - *     content: fetch message for content language instead of interface
 - *   Also can accept a single associative argument, of the form 'language' => 'xx':
 - *     language: Language object or language code to fetch message for
 - *       (overridden by content).
 - * Behavior for conflicting options (e.g., parse+parseinline) is undefined.
 - *
 - * @return string
 - */
 -function wfMsgExt( $key, $options ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      $args = func_get_args();
 -      array_shift( $args );
 -      array_shift( $args );
 -      $options = (array)$options;
 -      $validOptions = array( 'parse', 'parseinline', 'escape', 'escapenoentities', 'replaceafter',
 -              'parsemag', 'content' );
 -
 -      foreach ( $options as $arrayKey => $option ) {
 -              if ( !preg_match( '/^[0-9]+|language$/', $arrayKey ) ) {
 -                      // An unknown index, neither numeric nor "language"
 -                      wfWarn( "wfMsgExt called with incorrect parameter key $arrayKey", 1, E_USER_WARNING );
 -              } elseif ( preg_match( '/^[0-9]+$/', $arrayKey ) && !in_array( $option, $validOptions ) ) {
 -                      // A numeric index with unknown value
 -                      wfWarn( "wfMsgExt called with incorrect parameter $option", 1, E_USER_WARNING );
 -              }
 -      }
 -
 -      if ( in_array( 'content', $options, true ) ) {
 -              $forContent = true;
 -              $langCode = true;
 -              $langCodeObj = null;
 -      } elseif ( array_key_exists( 'language', $options ) ) {
 -              $forContent = false;
 -              $langCode = wfGetLangObj( $options['language'] );
 -              $langCodeObj = $langCode;
 -      } else {
 -              $forContent = false;
 -              $langCode = false;
 -              $langCodeObj = null;
 -      }
 -
 -      $string = wfMsgGetKey( $key, /*DB*/true, $langCode, /*Transform*/false );
 -
 -      if ( !in_array( 'replaceafter', $options, true ) ) {
 -              $string = wfMsgReplaceArgs( $string, $args );
 -      }
 -
 -      $messageCache = MessageCache::singleton();
 -      $parseInline = in_array( 'parseinline', $options, true );
 -      if ( in_array( 'parse', $options, true ) || $parseInline ) {
 -              $string = $messageCache->parse( $string, null, true, !$forContent, $langCodeObj );
 -              if ( $string instanceof ParserOutput ) {
 -                      $string = $string->getText();
 -              }
 -
 -              if ( $parseInline ) {
 -                      $string = Parser::stripOuterParagraph( $string );
 -              }
 -      } elseif ( in_array( 'parsemag', $options, true ) ) {
 -              $string = $messageCache->transform( $string,
 -                              !$forContent, $langCodeObj );
 -      }
 -
 -      if ( in_array( 'escape', $options, true ) ) {
 -              $string = htmlspecialchars( $string );
 -      } elseif ( in_array( 'escapenoentities', $options, true ) ) {
 -              $string = Sanitizer::escapeHtmlAllowEntities( $string );
 -      }
 -
 -      if ( in_array( 'replaceafter', $options, true ) ) {
 -              $string = wfMsgReplaceArgs( $string, $args );
 -      }
 -
 -      return $string;
 -}
 -
 -/**
 - * Since wfMsg() and co suck, they don't return false if the message key they
 - * looked up didn't exist but instead the key wrapped in <>'s, this function checks for the
 - * nonexistence of messages by checking the MessageCache::get() result directly.
 - *
 - * @deprecated since 1.18. Use Message::isDisabled().
 - *
 - * @param string $key The message key looked up
 - * @return bool True if the message *doesn't* exist.
 - */
 -function wfEmptyMsg( $key ) {
 -      wfDeprecated( __METHOD__, '1.21' );
 -
 -      return MessageCache::singleton()->get( $key, /*useDB*/true, /*content*/false ) === false;
 -}
 -
  /**
   * Fetch server name for use in error reporting etc.
   * Use real server name if available, so we know which machine
@@@ -1489,7 -1847,7 +1489,7 @@@ function wfReportTime() 
        global $wgRequestTime, $wgShowHostnames;
  
        $responseTime = round( ( microtime( true ) - $wgRequestTime ) * 1000 );
 -      $reportVars = array( 'wgBackendResponseTime' => $responseTime );
 +      $reportVars = [ 'wgBackendResponseTime' => $responseTime ];
        if ( $wgShowHostnames ) {
                $reportVars['wgHostname'] = wfHostname();
        }
@@@ -1516,10 -1874,10 +1516,10 @@@ function wfDebugBacktrace( $limit = 0 
                }
        }
        if ( $disabled ) {
 -              return array();
 +              return [];
        }
  
 -      if ( $limit && version_compare( PHP_VERSION, '5.4.0', '>=' ) ) {
 +      if ( $limit ) {
                return array_slice( debug_backtrace( DEBUG_BACKTRACE_PROVIDE_OBJECT, $limit + 1 ), 1 );
        } else {
                return array_slice( debug_backtrace(), 1 );
@@@ -1625,11 -1983,13 +1625,13 @@@ function wfShowingResults( $offset, $li
  }
  
  /**
-  * @todo document
-  * @todo FIXME: We may want to blacklist some broken browsers
+  * Whether the client accept gzip encoding
+  *
+  * Uses the Accept-Encoding header to check if the client supports gzip encoding.
+  * Use this when considering to send a gzip-encoded response to the client.
   *
-  * @param bool $force
-  * @return bool Whereas client accept gzip compression
+  * @param bool $force Forces another check even if we already have a cached result.
+  * @return bool
   */
  function wfClientAcceptsGzip( $force = false ) {
        static $result = null;
                $result = false;
                if ( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) {
                        # @todo FIXME: We may want to blacklist some broken browsers
 -                      $m = array();
 +                      $m = [];
                        if ( preg_match(
                                        '/\bgzip(?:;(q)=([0-9]+(?:\.[0-9]+)))?\b/',
                                        $_SERVER['HTTP_ACCEPT_ENCODING'],
        return $result;
  }
  
 -/**
 - * Obtain the offset and limit values from the request string;
 - * used in special pages
 - *
 - * @param int $deflimit Default limit if none supplied
 - * @param string $optionname Name of a user preference to check against
 - * @return array
 - * @deprecated since 1.24, just call WebRequest::getLimitOffset() directly
 - */
 -function wfCheckLimits( $deflimit = 50, $optionname = 'rclimit' ) {
 -      global $wgRequest;
 -      wfDeprecated( __METHOD__, '1.24' );
 -      return $wgRequest->getLimitOffset( $deflimit, $optionname );
 -}
 -
  /**
   * Escapes the given text so that it may be output using addWikiText()
   * without any linking, formatting, etc. making its way through. This
   * @return string
   */
  function wfEscapeWikiText( $text ) {
 +      global $wgEnableMagicLinks;
        static $repl = null, $repl2 = null;
        if ( $repl === null ) {
 -              $repl = array(
 +              $repl = [
                        '"' => '&#34;', '&' => '&#38;', "'" => '&#39;', '<' => '&#60;',
                        '=' => '&#61;', '>' => '&#62;', '[' => '&#91;', ']' => '&#93;',
                        '{' => '&#123;', '|' => '&#124;', '}' => '&#125;', ';' => '&#59;',
                        "\n\t" => "\n&#9;", "\r\t" => "\r&#9;", // "\n\t\n" is treated like "\n\n"
                        "\n----" => "\n&#45;---", "\r----" => "\r&#45;---",
                        '__' => '_&#95;', '://' => '&#58;//',
 -              );
 +              ];
  
 +              $magicLinks = array_keys( array_filter( $wgEnableMagicLinks ) );
                // We have to catch everything "\s" matches in PCRE
 -              foreach ( array( 'ISBN', 'RFC', 'PMID' ) as $magic ) {
 +              foreach ( $magicLinks as $magic ) {
                        $repl["$magic "] = "$magic&#32;";
                        $repl["$magic\t"] = "$magic&#9;";
                        $repl["$magic\r"] = "$magic&#13;";
  
                // And handle protocols that don't use "://"
                global $wgUrlProtocols;
 -              $repl2 = array();
 +              $repl2 = [];
                foreach ( $wgUrlProtocols as $prot ) {
                        if ( substr( $prot, -1 ) === ':' ) {
                                $repl2[] = preg_quote( substr( $prot, 0, -1 ), '/' );
                        }
                }
 -              $repl2 = $repl2 ? '/\b(' . join( '|', $repl2 ) . '):/i' : '/^(?!)/';
 +              $repl2 = $repl2 ? '/\b(' . implode( '|', $repl2 ) . '):/i' : '/^(?!)/';
        }
        $text = substr( strtr( "\n$text", $repl ), 1 );
        $text = preg_replace( $repl2, '$1&#58;', $text );
@@@ -1876,17 -2249,17 +1878,17 @@@ function wfClearOutputBuffers() 
  function wfAcceptToPrefs( $accept, $def = '*/*' ) {
        # No arg means accept anything (per HTTP spec)
        if ( !$accept ) {
 -              return array( $def => 1.0 );
 +              return [ $def => 1.0 ];
        }
  
 -      $prefs = array();
 +      $prefs = [];
  
        $parts = explode( ',', $accept );
  
        foreach ( $parts as $part ) {
                # @todo FIXME: Doesn't deal with params like 'text/html; level=1'
                $values = explode( ';', trim( $part ) );
 -              $match = array();
 +              $match = [];
                if ( count( $values ) == 1 ) {
                        $prefs[$values[0]] = 1.0;
                } elseif ( preg_match( '/q\s*=\s*(\d*\.\d+)/', $values[1], $match ) ) {
@@@ -1913,9 -2286,9 +1915,9 @@@ function mimeTypeMatch( $type, $avail 
        if ( array_key_exists( $type, $avail ) ) {
                return $type;
        } else {
 -              $parts = explode( '/', $type );
 -              if ( array_key_exists( $parts[0] . '/*', $avail ) ) {
 -                      return $parts[0] . '/*';
 +              $mainType = explode( '/', $type )[0];
 +              if ( array_key_exists( "$mainType/*", $avail ) ) {
 +                      return "$mainType/*";
                } elseif ( array_key_exists( '*/*', $avail ) ) {
                        return '*/*';
                } else {
   * XXX: generalize to negotiate other stuff
   */
  function wfNegotiateType( $cprefs, $sprefs ) {
 -      $combine = array();
 +      $combine = [];
  
        foreach ( array_keys( $sprefs ) as $type ) {
 -              $parts = explode( '/', $type );
 -              if ( $parts[1] != '*' ) {
 +              $subType = explode( '/', $type )[1];
 +              if ( $subType != '*' ) {
                        $ckey = mimeTypeMatch( $type, $cprefs );
                        if ( $ckey ) {
                                $combine[$type] = $sprefs[$type] * $cprefs[$ckey];
        }
  
        foreach ( array_keys( $cprefs ) as $type ) {
 -              $parts = explode( '/', $type );
 -              if ( $parts[1] != '*' && !array_key_exists( $type, $sprefs ) ) {
 +              $subType = explode( '/', $type )[1];
 +              if ( $subType != '*' && !array_key_exists( $type, $sprefs ) ) {
                        $skey = mimeTypeMatch( $type, $sprefs );
                        if ( $skey ) {
                                $combine[$type] = $sprefs[$skey] * $cprefs[$type];
@@@ -1993,7 -2366,56 +1995,7 @@@ function wfRestoreWarnings() 
  
  # Autodetect, convert and provide timestamps of various types
  
 -/**
 - * Unix time - the number of seconds since 1970-01-01 00:00:00 UTC
 - */
 -define( 'TS_UNIX', 0 );
 -
 -/**
 - * MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS)
 - */
 -define( 'TS_MW', 1 );
 -
 -/**
 - * MySQL DATETIME (YYYY-MM-DD HH:MM:SS)
 - */
 -define( 'TS_DB', 2 );
 -
 -/**
 - * RFC 2822 format, for E-mail and HTTP headers
 - */
 -define( 'TS_RFC2822', 3 );
 -
 -/**
 - * ISO 8601 format with no timezone: 1986-02-09T20:00:00Z
 - *
 - * This is used by Special:Export
 - */
 -define( 'TS_ISO_8601', 4 );
 -
 -/**
 - * An Exif timestamp (YYYY:MM:DD HH:MM:SS)
 - *
 - * @see http://exif.org/Exif2-2.PDF The Exif 2.2 spec, see page 28 for the
 - *       DateTime tag and page 36 for the DateTimeOriginal and
 - *       DateTimeDigitized tags.
 - */
 -define( 'TS_EXIF', 5 );
 -
 -/**
 - * Oracle format time.
 - */
 -define( 'TS_ORACLE', 6 );
 -
 -/**
 - * Postgres format time.
 - */
 -define( 'TS_POSTGRES', 7 );
 -
 -/**
 - * ISO 8601 basic format with no timezone: 19860209T200000Z.  This is used by ResourceLoader
 - */
 -define( 'TS_ISO_8601_BASIC', 9 );
 +require_once __DIR__ . '/libs/time/defines.php';
  
  /**
   * Get a timestamp string in one of various formats
   * @return string|bool String / false The same date in the format specified in $outputtype or false
   */
  function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) {
 -      try {
 -              $timestamp = new MWTimestamp( $ts );
 -              return $timestamp->getTimestamp( $outputtype );
 -      } catch ( TimestampException $e ) {
 +      $ret = MWTimestamp::convert( $outputtype, $ts );
 +      if ( $ret === false ) {
                wfDebug( "wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n" );
 -              return false;
        }
 +      return $ret;
  }
  
  /**
@@@ -2034,7 -2458,7 +2036,7 @@@ function wfTimestampOrNull( $outputtyp
   */
  function wfTimestampNow() {
        # return NOW
 -      return wfTimestamp( TS_MW, time() );
 +      return MWTimestamp::now( TS_MW );
  }
  
  /**
@@@ -2062,8 -2486,8 +2064,8 @@@ function wfIsHHVM() 
  /**
   * Tries to get the system directory for temporary files. First
   * $wgTmpDirectory is checked, and then the TMPDIR, TMP, and TEMP
 - * environment variables are then checked in sequence, and if none are
 - * set try sys_get_temp_dir().
 + * environment variables are then checked in sequence, then
 + * sys_get_temp_dir(), then upload_tmp_dir from php.ini.
   *
   * NOTE: When possible, use instead the tmpfile() function to create
   * temporary files to avoid race conditions on file creation, etc.
@@@ -2077,7 -2501,14 +2079,7 @@@ function wfTempDir() 
                return $wgTmpDirectory;
        }
  
 -      $tmpDir = array_map( "getenv", array( 'TMPDIR', 'TMP', 'TEMP' ) );
 -
 -      foreach ( $tmpDir as $tmp ) {
 -              if ( $tmp && file_exists( $tmp ) && is_dir( $tmp ) && is_writable( $tmp ) ) {
 -                      return $tmp;
 -              }
 -      }
 -      return sys_get_temp_dir();
 +      return TempFSFile::getUsableTempDirectory();
  }
  
  /**
@@@ -2104,7 -2535,7 +2106,7 @@@ function wfMkdirParents( $dir, $mode = 
                return true;
        }
  
 -      $dir = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, $dir );
 +      $dir = str_replace( [ '\\', '/' ], DIRECTORY_SEPARATOR, $dir );
  
        if ( is_null( $mode ) ) {
                $mode = $wgDirectoryMode;
@@@ -2195,11 -2626,12 +2197,11 @@@ function wfIniGetBool( $setting ) 
  }
  
  /**
 - * Windows-compatible version of escapeshellarg()
 - * Windows doesn't recognise single-quotes in the shell, but the escapeshellarg()
 - * function puts single quotes in regardless of OS.
 + * Version of escapeshellarg() that works better on Windows.
   *
 - * Also fixes the locale problems on Linux in PHP 5.2.6+ (bug backported to
 - * earlier distro releases of PHP)
 + * Originally, this fixed the incorrect use of single quotes on Windows
 + * (https://bugs.php.net/bug.php?id=26285) and the locale problems on Linux in
 + * PHP 5.2.6+ (bug backported to earlier distro releases of PHP).
   *
   * @param string ... strings to escape and glue together, or a single array of strings parameter
   * @return string
@@@ -2229,7 -2661,7 +2231,7 @@@ function wfEscapeShellArg( /*...*/ ) 
                        // Refs:
                        //  * http://web.archive.org/web/20020708081031/http://mailman.lyra.org/pipermail/scite-interest/2002-March/000436.html
                        //  * http://technet.microsoft.com/en-us/library/cc723564.aspx
 -                      //  * Bug #13518
 +                      //  * T15518
                        //  * CR r63214
                        // Double the backslashes before any double quotes. Escape the double quotes.
                        // @codingStandardsIgnoreEnd
                        }
                        // Double the backslashes before the end of the string, because
                        // we will soon add a quote
 -                      $m = array();
 +                      $m = [];
                        if ( preg_match( '/^(.*?)(\\\\+)$/', $arg, $m ) ) {
                                $arg = $m[1] . str_replace( '\\', '\\\\', $m[2] );
                        }
  /**
   * Check if wfShellExec() is effectively disabled via php.ini config
   *
 - * @return bool|string False or one of (safemode,disabled)
 + * @return bool|string False or 'disabled'
   * @since 1.22
   */
  function wfShellExecDisabled() {
        static $disabled = null;
        if ( is_null( $disabled ) ) {
 -              if ( wfIniGetBool( 'safe_mode' ) ) {
 -                      wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" );
 -                      $disabled = 'safemode';
 -              } elseif ( !function_exists( 'proc_open' ) ) {
 +              if ( !function_exists( 'proc_open' ) ) {
                        wfDebug( "proc_open() is disabled\n" );
                        $disabled = 'disabled';
                } else {
   *
   * @return string Collected stdout as a string
   */
 -function wfShellExec( $cmd, &$retval = null, $environ = array(),
 -      $limits = array(), $options = array()
 +function wfShellExec( $cmd, &$retval = null, $environ = [],
 +      $limits = [], $options = []
  ) {
        global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime,
                $wgMaxShellWallClockTime, $wgShellCgroup;
        $disabled = wfShellExecDisabled();
        if ( $disabled ) {
                $retval = 1;
 -              return $disabled == 'safemode' ?
 -                      'Unable to run external programs in safe mode.' :
 -                      'Unable to run external programs, proc_open() is disabled.';
 +              return 'Unable to run external programs, proc_open() is disabled.';
        }
  
        $includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr'];
        }
        wfDebug( "wfShellExec: $cmd\n" );
  
 -      $desc = array(
 -              0 => array( 'file', 'php://stdin', 'r' ),
 -              1 => array( 'pipe', 'w' ),
 -              2 => array( 'file', 'php://stderr', 'w' ) );
 +      // Don't try to execute commands that exceed Linux's MAX_ARG_STRLEN.
 +      // Other platforms may be more accomodating, but we don't want to be
 +      // accomodating, because very long commands probably include user
 +      // input. See T129506.
 +      if ( strlen( $cmd ) > SHELL_MAX_ARG_STRLEN ) {
 +              throw new Exception( __METHOD__ .
 +                      '(): total length of $cmd must not exceed SHELL_MAX_ARG_STRLEN' );
 +      }
 +
 +      $desc = [
 +              0 => [ 'file', 'php://stdin', 'r' ],
 +              1 => [ 'pipe', 'w' ],
 +              2 => [ 'file', 'php://stderr', 'w' ] ];
        if ( $useLogPipe ) {
 -              $desc[3] = array( 'pipe', 'w' );
 +              $desc[3] = [ 'pipe', 'w' ];
        }
        $pipes = null;
        $scoped = Profiler::instance()->scopedProfileIn( __FUNCTION__ . '-' . $profileMethod );
                return '';
        }
        $outBuffer = $logBuffer = '';
 -      $emptyArray = array();
 +      $emptyArray = [];
        $status = false;
        $logMsg = false;
  
        $eintr = defined( 'SOCKET_EINTR' ) ? SOCKET_EINTR : 4;
        $eintrMessage = "stream_select(): unable to select [$eintr]";
  
 -      // Build a table mapping resource IDs to pipe FDs to work around a
 -      // PHP 5.3 issue in which stream_select() does not preserve array keys
 -      // <https://bugs.php.net/bug.php?id=53427>.
 -      $fds = array();
 -      foreach ( $pipes as $fd => $pipe ) {
 -              $fds[(int)$pipe] = $fd;
 -      }
 -
        $running = true;
        $timeout = null;
        $numReadyPipes = 0;
                                break;
                        }
                }
 -              foreach ( $readyPipes as $pipe ) {
 +              foreach ( $readyPipes as $fd => $pipe ) {
                        $block = fread( $pipe, 65536 );
 -                      $fd = $fds[(int)$pipe];
                        if ( $block === '' ) {
                                // End of file
                                fclose( $pipes[$fd] );
   *   this overwrites the global wgMaxShell* limits.
   * @return string Collected stdout and stderr as a string
   */
 -function wfShellExecWithStderr( $cmd, &$retval = null, $environ = array(), $limits = array() ) {
 +function wfShellExecWithStderr( $cmd, &$retval = null, $environ = [], $limits = [] ) {
        return wfShellExec( $cmd, $retval, $environ, $limits,
 -              array( 'duplicateStderr' => true, 'profileMethod' => wfGetCaller() ) );
 +              [ 'duplicateStderr' => true, 'profileMethod' => wfGetCaller() ] );
  }
  
  /**
@@@ -2556,8 -2993,10 +2558,8 @@@ function wfInitShellLocale() 
        }
        $done = true;
        global $wgShellLocale;
 -      if ( !wfIniGetBool( 'safe_mode' ) ) {
 -              putenv( "LC_CTYPE=$wgShellLocale" );
 -              setlocale( LC_CTYPE, $wgShellLocale );
 -      }
 +      putenv( "LC_CTYPE=$wgShellLocale" );
 +      setlocale( LC_CTYPE, $wgShellLocale );
  }
  
  /**
   *            'wrapper': Path to a PHP wrapper to handle the maintenance script
   * @return string
   */
 -function wfShellWikiCmd( $script, array $parameters = array(), array $options = array() ) {
 +function wfShellWikiCmd( $script, array $parameters = [], array $options = [] ) {
        global $wgPhpCli;
        // Give site config file a chance to run the script in a wrapper.
        // The caller may likely want to call wfBasename() on $script.
 -      Hooks::run( 'wfShellWikiCmd', array( &$script, &$parameters, &$options ) );
 -      $cmd = isset( $options['php'] ) ? array( $options['php'] ) : array( $wgPhpCli );
 +      Hooks::run( 'wfShellWikiCmd', [ &$script, &$parameters, &$options ] );
 +      $cmd = isset( $options['php'] ) ? [ $options['php'] ] : [ $wgPhpCli ];
        if ( isset( $options['wrapper'] ) ) {
                $cmd[] = $options['wrapper'];
        }
@@@ -2814,7 -3253,7 +2816,7 @@@ function wfBaseName( $path, $suffix = '
                $encSuffix = '(?:' . preg_quote( $suffix, '#' ) . ')?';
        }
  
 -      $matches = array();
 +      $matches = [];
        if ( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) {
                return $matches[1];
        } else {
@@@ -2874,7 -3313,7 +2876,7 @@@ function wfRelativePath( $path, $from 
   * Supports base 2 through 36; digit values 10-36 are represented
   * as lowercase letters a-z. Input is case-insensitive.
   *
 - * @deprecated 1.27 Use Wikimedia\base_convert() directly
 + * @deprecated since 1.27 Use Wikimedia\base_convert() directly
   *
   * @param string $input Input number
   * @param int $sourceBase Base of the input number
@@@ -2891,58 -3330,96 +2893,58 @@@ function wfBaseConvert( $input, $source
  }
  
  /**
 - * Check if there is sufficient entropy in php's built-in session generation
 - *
 - * @return bool True = there is sufficient entropy
 - */
 -function wfCheckEntropy() {
 -      return (
 -                      ( wfIsWindows() && version_compare( PHP_VERSION, '5.3.3', '>=' ) )
 -                      || ini_get( 'session.entropy_file' )
 -              )
 -              && intval( ini_get( 'session.entropy_length' ) ) >= 32;
 -}
 -
 -/**
 - * Override session_id before session startup if php's built-in
 - * session generation code is not secure.
 + * @deprecated since 1.27, PHP's session generation isn't used with
 + *  MediaWiki\Session\SessionManager
   */
  function wfFixSessionID() {
 -      // If the cookie or session id is already set we already have a session and should abort
 -      if ( isset( $_COOKIE[session_name()] ) || session_id() ) {
 -              return;
 -      }
 -
 -      // PHP's built-in session entropy is enabled if:
 -      // - entropy_file is set or you're on Windows with php 5.3.3+
 -      // - AND entropy_length is > 0
 -      // We treat it as disabled if it doesn't have an entropy length of at least 32
 -      $entropyEnabled = wfCheckEntropy();
 -
 -      // If built-in entropy is not enabled or not sufficient override PHP's
 -      // built in session id generation code
 -      if ( !$entropyEnabled ) {
 -              wfDebug( __METHOD__ . ": PHP's built in entropy is disabled or not sufficient, " .
 -                      "overriding session id generation using our cryptrand source.\n" );
 -              session_id( MWCryptRand::generateHex( 32 ) );
 -      }
 +      wfDeprecated( __FUNCTION__, '1.27' );
  }
  
  /**
 - * Reset the session_id
 + * Reset the session id
   *
 + * @deprecated since 1.27, use MediaWiki\Session\SessionManager instead
   * @since 1.22
   */
  function wfResetSessionID() {
 -      global $wgCookieSecure;
 -      $oldSessionId = session_id();
 -      $cookieParams = session_get_cookie_params();
 -      if ( wfCheckEntropy() && $wgCookieSecure == $cookieParams['secure'] ) {
 -              session_regenerate_id( false );
 -      } else {
 -              $tmp = $_SESSION;
 -              session_destroy();
 -              wfSetupSession( MWCryptRand::generateHex( 32 ) );
 -              $_SESSION = $tmp;
 +      wfDeprecated( __FUNCTION__, '1.27' );
 +      $session = SessionManager::getGlobalSession();
 +      $delay = $session->delaySave();
 +
 +      $session->resetId();
 +
 +      // Make sure a session is started, since that's what the old
 +      // wfResetSessionID() did.
 +      if ( session_id() !== $session->getId() ) {
 +              wfSetupSession( $session->getId() );
        }
 -      $newSessionId = session_id();
 +
 +      ScopedCallback::consume( $delay );
  }
  
  /**
   * Initialise php session
   *
 - * @param bool $sessionId
 + * @deprecated since 1.27, use MediaWiki\Session\SessionManager instead.
 + *  Generally, "using" SessionManager will be calling ->getSessionById() or
 + *  ::getGlobalSession() (depending on whether you were passing $sessionId
 + *  here), then calling $session->persist().
 + * @param bool|string $sessionId
   */
  function wfSetupSession( $sessionId = false ) {
 -      global $wgSessionsInObjectCache, $wgSessionHandler;
 -      global $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly;
 +      wfDeprecated( __FUNCTION__, '1.27' );
  
 -      if ( $wgSessionsInObjectCache ) {
 -              ObjectCacheSessionHandler::install();
 -      } elseif ( $wgSessionHandler && $wgSessionHandler != ini_get( 'session.save_handler' ) ) {
 -              # Only set this if $wgSessionHandler isn't null and session.save_handler
 -              # hasn't already been set to the desired value (that causes errors)
 -              ini_set( 'session.save_handler', $wgSessionHandler );
 -      }
 -
 -      session_set_cookie_params(
 -              0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly );
 -      session_cache_limiter( 'private, must-revalidate' );
        if ( $sessionId ) {
                session_id( $sessionId );
 -      } else {
 -              wfFixSessionID();
        }
  
 -      MediaWiki\suppressWarnings();
 -      session_start();
 -      MediaWiki\restoreWarnings();
 +      $session = SessionManager::getGlobalSession();
 +      $session->persist();
  
 -      if ( $wgSessionsInObjectCache ) {
 -              ObjectCacheSessionHandler::renewCurrentSession();
 +      if ( session_id() !== $session->getId() ) {
 +              session_id( $session->getId() );
        }
 +      MediaWiki\quietCall( 'session_start' );
  }
  
  /**
@@@ -2972,7 -3449,7 +2974,7 @@@ function wfGetPrecompiledData( $name ) 
   */
  function wfMemcKey( /*...*/ ) {
        return call_user_func_array(
 -              array( ObjectCache::getLocalClusterInstance(), 'makeKey' ),
 +              [ ObjectCache::getLocalClusterInstance(), 'makeKey' ],
                func_get_args()
        );
  }
@@@ -2991,8 -3468,8 +2993,8 @@@ function wfForeignMemcKey( $db, $prefi
        $args = array_slice( func_get_args(), 2 );
        $keyspace = $prefix ? "$db-$prefix" : $db;
        return call_user_func_array(
 -              array( ObjectCache::getLocalClusterInstance(), 'makeKeyInternal' ),
 -              array( $keyspace, $args )
 +              [ ObjectCache::getLocalClusterInstance(), 'makeKeyInternal' ],
 +              [ $keyspace, $args ]
        );
  }
  
   */
  function wfGlobalCacheKey( /*...*/ ) {
        return call_user_func_array(
 -              array( ObjectCache::getLocalClusterInstance(), 'makeGlobalKey' ),
 +              [ ObjectCache::getLocalClusterInstance(), 'makeGlobalKey' ],
                func_get_args()
        );
  }
@@@ -3048,7 -3525,7 +3050,7 @@@ function wfSplitWikiID( $wiki ) 
   * Get a Database object.
   *
   * @param int $db Index of the connection to get. May be DB_MASTER for the
 - *            master (for write queries), DB_SLAVE for potentially lagged read
 + *            master (for write queries), DB_REPLICA for potentially lagged read
   *            queries, or an integer >= 0 for a particular server.
   *
   * @param string|string[] $groups Query groups. An array of group names that this query
   *
   * @param string|bool $wiki The wiki ID, or false for the current wiki
   *
 - * Note: multiple calls to wfGetDB(DB_SLAVE) during the course of one request
 + * Note: multiple calls to wfGetDB(DB_REPLICA) during the course of one request
   * will always return the same object, unless the underlying connection or load
   * balancer is manually destroyed.
   *
   * Note 2: use $this->getDB() in maintenance scripts that may be invoked by
   * updater to ensure that a proper database is being updated.
   *
 - * @return DatabaseBase
 + * @todo Replace calls to wfGetDB with calls to LoadBalancer::getConnection()
 + *       on an injected instance of LoadBalancer.
 + *
 + * @return Database
   */
 -function wfGetDB( $db, $groups = array(), $wiki = false ) {
 +function wfGetDB( $db, $groups = [], $wiki = false ) {
        return wfGetLB( $wiki )->getConnection( $db, $groups, $wiki );
  }
  
  /**
   * Get a load balancer object.
   *
 + * @deprecated since 1.27, use MediaWikiServices::getDBLoadBalancer()
 + *              or MediaWikiServices::getDBLoadBalancerFactory() instead.
 + *
   * @param string|bool $wiki Wiki ID, or false for the current wiki
   * @return LoadBalancer
   */
  function wfGetLB( $wiki = false ) {
 -      return wfGetLBFactory()->getMainLB( $wiki );
 +      if ( $wiki === false ) {
 +              return \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancer();
 +      } else {
 +              $factory = \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
 +              return $factory->getMainLB( $wiki );
 +      }
  }
  
  /**
   * Get the load balancer factory object
   *
 + * @deprecated since 1.27, use MediaWikiServices::getDBLoadBalancerFactory() instead.
 + *
   * @return LBFactory
   */
  function wfGetLBFactory() {
 -      return LBFactory::singleton();
 +      return \MediaWiki\MediaWikiServices::getInstance()->getDBLoadBalancerFactory();
  }
  
  /**
   * @param array $options Associative array of options (see RepoGroup::findFile)
   * @return File|bool File, or false if the file does not exist
   */
 -function wfFindFile( $title, $options = array() ) {
 +function wfFindFile( $title, $options = [] ) {
        return RepoGroup::singleton()->findFile( $title, $options );
  }
  
@@@ -3202,10 -3666,10 +3204,10 @@@ function wfGetNull() 
  }
  
  /**
 - * Waits for the slaves to catch up to the master position
 + * Waits for the replica DBs to catch up to the master position
   *
   * Use this when updating very large numbers of rows, as in maintenance scripts,
 - * to avoid causing too much lag. Of course, this is a no-op if there are no slaves.
 + * to avoid causing too much lag. Of course, this is a no-op if there are no replica DBs.
   *
   * By default this waits on the main DB cluster of the current wiki.
   * If $cluster is set to "*" it will wait on all DB clusters, including
   * @param string|bool $cluster Cluster name accepted by LBFactory. Default: false.
   * @param int|null $timeout Max wait time. Default: 1 day (cli), ~10 seconds (web)
   * @return bool Success (able to connect and no timeouts reached)
 + * @deprecated since 1.27 Use LBFactory::waitForReplication
   */
  function wfWaitForSlaves(
        $ifWritesSince = null, $wiki = false, $cluster = false, $timeout = null
  ) {
 -      // B/C: first argument used to be "max seconds of lag"; ignore such values
 -      $ifWritesSince = ( $ifWritesSince > 1e9 ) ? $ifWritesSince : null;
 -
        if ( $timeout === null ) {
                $timeout = ( PHP_SAPI === 'cli' ) ? 86400 : 10;
        }
  
 -      // Figure out which clusters need to be checked
 -      /** @var LoadBalancer[] $lbs */
 -      $lbs = array();
        if ( $cluster === '*' ) {
 -              wfGetLBFactory()->forEachLB( function ( LoadBalancer $lb ) use ( &$lbs ) {
 -                      $lbs[] = $lb;
 -              } );
 -      } elseif ( $cluster !== false ) {
 -              $lbs[] = wfGetLBFactory()->getExternalLB( $cluster );
 -      } else {
 -              $lbs[] = wfGetLB( $wiki );
 -      }
 -
 -      // Get all the master positions of applicable DBs right now.
 -      // This can be faster since waiting on one cluster reduces the
 -      // time needed to wait on the next clusters.
 -      $masterPositions = array_fill( 0, count( $lbs ), false );
 -      foreach ( $lbs as $i => $lb ) {
 -              if ( $lb->getServerCount() <= 1 ) {
 -                      // Bug 27975 - Don't try to wait for slaves if there are none
 -                      // Prevents permission error when getting master position
 -                      continue;
 -              } elseif ( $ifWritesSince && $lb->lastMasterChangeTimestamp() < $ifWritesSince ) {
 -                      continue; // no writes since the last wait
 -              }
 -              $masterPositions[$i] = $lb->getMasterPos();
 +              $cluster = false;
 +              $wiki = false;
 +      } elseif ( $wiki === false ) {
 +              $wiki = wfWikiID();
        }
  
 -      $ok = true;
 -      foreach ( $lbs as $i => $lb ) {
 -              if ( $masterPositions[$i] ) {
 -                      // The DBMS may not support getMasterPos() or the whole
 -                      // load balancer might be fake (e.g. $wgAllDBsAreLocalhost).
 -                      $ok = $lb->waitForAll( $masterPositions[$i], $timeout ) && $ok;
 -              }
 +      try {
 +              wfGetLBFactory()->waitForReplication( [
 +                      'wiki' => $wiki,
 +                      'cluster' => $cluster,
 +                      'timeout' => $timeout,
 +                      // B/C: first argument used to be "max seconds of lag"; ignore such values
 +                      'ifWritesSince' => ( $ifWritesSince > 1e9 ) ? $ifWritesSince : null
 +              ] );
 +      } catch ( DBReplicationWaitError $e ) {
 +              return false;
        }
  
 -      return $ok;
 +      return true;
  }
  
  /**
@@@ -3274,9 -3758,9 +3276,9 @@@ function wfCountDown( $seconds ) 
  }
  
  /**
 - * Replace all invalid characters with -
 - * Additional characters can be defined in $wgIllegalFileChars (see bug 20489)
 - * By default, $wgIllegalFileChars = ':'
 + * Replace all invalid characters with '-'.
 + * Additional characters can be defined in $wgIllegalFileChars (see T22489).
 + * By default, $wgIllegalFileChars includes ':', '/', '\'.
   *
   * @param string $name Filename to process
   * @return string
  function wfStripIllegalFilenameChars( $name ) {
        global $wgIllegalFileChars;
        $illegalFileChars = $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : '';
 -      $name = wfBaseName( $name );
        $name = preg_replace(
                "/[^" . Title::legalChars() . "]" . $illegalFileChars . "/",
                '-',
                $name
        );
 +      // $wgIllegalFileChars may not include '/' and '\', so we still need to do this
 +      $name = wfBaseName( $name );
        return $name;
  }
  
@@@ -3381,7 -3864,7 +3383,7 @@@ function wfShorthandToInteger( $string 
   */
  function wfBCP47( $code ) {
        $codeSegment = explode( '-', $code );
 -      $codeBCP = array();
 +      $codeBCP = [];
        foreach ( $codeSegment as $segNo => $seg ) {
                // when previous segment is x, it is a private segment and should be lc
                if ( $segNo > 0 && strtolower( $codeSegment[( $segNo - 1 )] ) == 'x' ) {
@@@ -3449,9 -3932,9 +3451,9 @@@ function wfGetParserCacheStorage() 
   * @param string|null $deprecatedVersion Optionally mark hook as deprecated with version number
   *
   * @return bool True if no handler aborted the hook
 - * @deprecated 1.25 - use Hooks::run
 + * @deprecated since 1.25 - use Hooks::run
   */
 -function wfRunHooks( $event, array $args = array(), $deprecatedVersion = null ) {
 +function wfRunHooks( $event, array $args = [], $deprecatedVersion = null ) {
        return Hooks::run( $event, $args, $deprecatedVersion );
  }
  
@@@ -3513,7 -3996,7 +3515,7 @@@ function wfIsBadImage( $name, $contextT
  
        # Run the extension hook
        $bad = false;
 -      if ( !Hooks::run( 'BadImage', array( $name, &$bad ) ) ) {
 +      if ( !Hooks::run( 'BadImage', [ $name, &$bad ] ) ) {
                return $bad;
        }
  
                        $blacklist = wfMessage( 'bad_image_list' )->inContentLanguage()->plain(); // site list
                }
                # Build the list now
 -              $badImages = array();
 +              $badImages = [];
                $lines = explode( "\n", $blacklist );
                foreach ( $lines as $line ) {
                        # List items only
                        }
  
                        # Find all links
 -                      $m = array();
 +                      $m = [];
                        if ( !preg_match_all( '/\[\[:?(.*?)\]\]/', $line, $m ) ) {
                                continue;
                        }
  
 -                      $exceptions = array();
 +                      $exceptions = [];
                        $imageDBkey = false;
                        foreach ( $m[1] as $i => $titleText ) {
                                $title = Title::newFromText( $titleText );
   */
  function wfCanIPUseHTTPS( $ip ) {
        $canDo = true;
 -      Hooks::run( 'CanIPUseHTTPS', array( $ip, &$canDo ) );
 +      Hooks::run( 'CanIPUseHTTPS', [ $ip, &$canDo ] );
        return !!$canDo;
  }
  
   * @since 1.25
   */
  function wfIsInfinity( $str ) {
 -      $infinityValues = array( 'infinite', 'indefinite', 'infinity', 'never' );
 +      $infinityValues = [ 'infinite', 'indefinite', 'infinity', 'never' ];
        return in_array( $str, $infinityValues );
  }
  
  function wfThumbIsStandard( File $file, array $params ) {
        global $wgThumbLimits, $wgImageLimits, $wgResponsiveImages;
  
 -      $multipliers = array( 1 );
 +      $multipliers = [ 1 ];
        if ( $wgResponsiveImages ) {
                // These available sizes are hardcoded currently elsewhere in MediaWiki.
                // @see Linker::processResponsiveImages
                return false;
        }
  
 -      $basicParams = array();
 +      $basicParams = [];
        if ( isset( $params['page'] ) ) {
                $basicParams['page'] = $params['page'];
        }
  
 -      $thumbLimits = array();
 -      $imageLimits = array();
 +      $thumbLimits = [];
 +      $imageLimits = [];
        // Expand limits to account for multipliers
        foreach ( $multipliers as $multiplier ) {
                $thumbLimits = array_merge( $thumbLimits, array_map(
                );
                $imageLimits = array_merge( $imageLimits, array_map(
                        function ( $pair ) use ( $multiplier ) {
 -                              return array(
 +                              return [
                                        round( $pair[0] * $multiplier ),
                                        round( $pair[1] * $multiplier ),
 -                              );
 +                              ];
                        }, $wgImageLimits )
                );
        }
  
        // Check if the width matches one of $wgThumbLimits
        if ( in_array( $params['width'], $thumbLimits ) ) {
 -              $normalParams = $basicParams + array( 'width' => $params['width'] );
 +              $normalParams = $basicParams + [ 'width' => $params['width'] ];
                // Append any default values to the map (e.g. "lossy", "lossless", ...)
                $handler->normaliseParams( $file, $normalParams );
        } else {
                // If not, then check if the width matchs one of $wgImageLimits
                $match = false;
                foreach ( $imageLimits as $pair ) {
 -                      $normalParams = $basicParams + array( 'width' => $pair[0], 'height' => $pair[1] );
 +                      $normalParams = $basicParams + [ 'width' => $pair[0], 'height' => $pair[1] ];
                        // Decide whether the thumbnail should be scaled on width or height.
                        // Also append any default values to the map (e.g. "lossy", "lossless", ...)
                        $handler->normaliseParams( $file, $normalParams );