Merge "Rename wfIsHipHop() to wfIsHHVM()"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 4 Nov 2013 18:32:39 +0000 (18:32 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 4 Nov 2013 18:32:39 +0000 (18:32 +0000)
1  2 
includes/GlobalFunctions.php

@@@ -81,6 -81,7 +81,6 @@@ if ( !function_exists( 'mb_strpos' ) ) 
        function mb_strpos( $haystack, $needle, $offset = 0, $encoding = '' ) {
                return Fallback::mb_strpos( $haystack, $needle, $offset, $encoding );
        }
 -
  }
  
  if ( !function_exists( 'mb_strrpos' ) ) {
@@@ -282,8 -283,8 +282,8 @@@ function wfRandom() 
        # The maximum random value is "only" 2^31-1, so get two random
        # values to reduce the chance of dupes
        $max = mt_getrandmax() + 1;
 -      $rand = number_format( ( mt_rand() * $max + mt_rand() )
 -              / $max / $max, 12, '.', '' );
 +      $rand = number_format( ( mt_rand() * $max + mt_rand() ) / $max / $max, 12, '.', '' );
 +
        return $rand;
  }
  
@@@ -329,7 -330,6 +329,7 @@@ function wfRandomString( $length = 32 
   */
  function wfUrlencode( $s ) {
        static $needle;
 +
        if ( is_null( $s ) ) {
                $needle = null;
                return '';
  
        if ( is_null( $needle ) ) {
                $needle = array( '%3B', '%40', '%24', '%21', '%2A', '%28', '%29', '%2C', '%2F' );
 -              if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) || ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false ) ) {
 +              if ( !isset( $_SERVER['SERVER_SOFTWARE'] ) ||
 +                      ( strpos( $_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS/7' ) === false )
 +              ) {
                        $needle[] = '%3A';
                }
        }
@@@ -472,17 -470,15 +472,17 @@@ function wfAppendQuery( $url, $query ) 
  }
  
  /**
 - * Expand a potentially local URL to a fully-qualified URL.  Assumes $wgServer
 + * Expand a potentially local URL to a fully-qualified URL. Assumes $wgServer
   * is correct.
   *
   * The meaning of the PROTO_* constants is as follows:
   * PROTO_HTTP: Output a URL starting with http://
   * PROTO_HTTPS: Output a URL starting with https://
   * PROTO_RELATIVE: Output a URL starting with // (protocol-relative URL)
 - * PROTO_CURRENT: Output a URL starting with either http:// or https:// , depending on which protocol was used for the current incoming request
 - * PROTO_CANONICAL: For URLs without a domain, like /w/index.php , use $wgCanonicalServer. For protocol-relative URLs, use the protocol of $wgCanonicalServer
 + * PROTO_CURRENT: Output a URL starting with either http:// or https:// , depending
 + *    on which protocol was used for the current incoming request
 + * PROTO_CANONICAL: For URLs without a domain, like /w/index.php , use $wgCanonicalServer.
 + *    For protocol-relative URLs, use the protocol of $wgCanonicalServer
   * PROTO_INTERNAL: Like PROTO_CANONICAL, but uses $wgInternalServer instead of $wgCanonicalServer
   *
   * @todo this won't work with current-path-relative URLs
   *
   * @param string $url either fully-qualified or a local path + query
   * @param $defaultProto Mixed: one of the PROTO_* constants. Determines the
 - *                             protocol to use if $url or $wgServer is
 - *                             protocol-relative
 + *    protocol to use if $url or $wgServer is protocol-relative
   * @return string Fully-qualified URL, current-path-relative URL or false if
 - *                no valid URL can be constructed
 + *    no valid URL can be constructed
   */
  function wfExpandUrl( $url, $defaultProto = PROTO_CURRENT ) {
        global $wgServer, $wgCanonicalServer, $wgInternalServer;
                if ( $serverHasProto ) {
                        $defaultProto = $bits['scheme'] . '://';
                } else {
 -                      // $wgCanonicalServer or $wgInternalServer doesn't have a protocol. This really isn't supposed to happen
 -                      // Fall back to HTTP in this ridiculous case
 +                      // $wgCanonicalServer or $wgInternalServer doesn't have a protocol.
 +                      // This really isn't supposed to happen. Fall back to HTTP in this
 +                      // ridiculous case.
                        $defaultProto = PROTO_HTTP;
                }
        }
        if ( substr( $url, 0, 2 ) == '//' ) {
                $url = $defaultProtoWithoutSlashes . $url;
        } elseif ( substr( $url, 0, 1 ) == '/' ) {
 -              // If $serverUrl is protocol-relative, prepend $defaultProtoWithoutSlashes, otherwise leave it alone
 +              // If $serverUrl is protocol-relative, prepend $defaultProtoWithoutSlashes,
 +              // otherwise leave it alone.
                $url = ( $serverHasProto ? '' : $defaultProtoWithoutSlashes ) . $serverUrl . $url;
        }
  
@@@ -744,10 -739,9 +744,10 @@@ function wfUrlProtocolsWithoutProtRel(
  /**
   * parse_url() work-alike, but non-broken.  Differences:
   *
 - * 1) Does not raise warnings on bad URLs (just returns false)
 - * 2) Handles protocols that don't use :// (e.g., mailto: and news: , as well as protocol-relative URLs) correctly
 - * 3) Adds a "delimiter" element to the array, either '://', ':' or '//' (see (2))
 + * 1) Does not raise warnings on bad URLs (just returns false).
 + * 2) Handles protocols that don't use :// (e.g., mailto: and news:, as well as
 + *    protocol-relative URLs) correctly.
 + * 3) Adds a "delimiter" element to the array, either '://', ':' or '//' (see (2)).
   *
   * @param string $url a URL to parse
   * @return Array: bits of the URL in an associative array, per PHP docs
  function wfParseUrl( $url ) {
        global $wgUrlProtocols; // Allow all protocols defined in DefaultSettings/LocalSettings.php
  
 -      // Protocol-relative URLs are handled really badly by parse_url(). It's so bad that the easiest
 -      // way to handle them is to just prepend 'http:' and strip the protocol out later
 +      // Protocol-relative URLs are handled really badly by parse_url(). It's so
 +      // bad that the easiest way to handle them is to just prepend 'http:' and
 +      // strip the protocol out later.
        $wasRelative = substr( $url, 0, 2 ) == '//';
        if ( $wasRelative ) {
                $url = "http:$url";
   * @return string
   */
  function wfExpandIRI( $url ) {
 -      return preg_replace_callback( '/((?:%[89A-F][0-9A-F])+)/i', 'wfExpandIRI_callback', wfExpandUrl( $url ) );
 +      return preg_replace_callback(
 +              '/((?:%[89A-F][0-9A-F])+)/i',
 +              'wfExpandIRI_callback',
 +              wfExpandUrl( $url )
 +      );
  }
  
  /**
@@@ -1064,8 -1053,7 +1064,8 @@@ function wfLogDBError( $text ) 
   * Throws a warning that $function is deprecated
   *
   * @param $function String
 - * @param string|bool $version Version of MediaWiki that the function was deprecated in (Added in 1.19).
 + * @param string|bool $version Version of MediaWiki that the function
 + *    was deprecated in (Added in 1.19).
   * @param string|bool $component Added in 1.19.
   * @param $callerOffset integer: How far up the call stack is the original
   *    caller. 2 = function that called the function that called
@@@ -2337,15 -2325,7 +2337,15 @@@ function wfSuppressWarnings( $end = fal
                }
        } else {
                if ( !$suppressCount ) {
 -                      $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED | E_USER_DEPRECATED | E_STRICT ) );
 +                      $originalLevel = error_reporting( E_ALL & ~(
 +                              E_WARNING |
 +                              E_NOTICE |
 +                              E_USER_WARNING |
 +                              E_USER_NOTICE |
 +                              E_DEPRECATED |
 +                              E_USER_DEPRECATED |
 +                              E_STRICT
 +                      ) );
                }
                ++$suppressCount;
        }
@@@ -2470,12 -2450,12 +2470,12 @@@ function wfIsWindows() 
  }
  
  /**
-  * Check if we are running under HipHop
+  * Check if we are running under HHVM
   *
   * @return Bool
   */
- function wfIsHipHop() {
-       return defined( 'HPHP_VERSION' );
+ function wfIsHHVM() {
+       return defined( 'HHVM_VERSION' );
  }
  
  /**
@@@ -2676,14 -2656,12 +2676,14 @@@ function wfEscapeShellArg() 
  
                if ( wfIsWindows() ) {
                        // Escaping for an MSVC-style command line parser and CMD.EXE
 +                      // @codingStandardsIgnoreStart For long URLs
                        // 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
                        //  * CR r63214
                        // Double the backslashes before any double quotes. Escape the double quotes.
 +                      // @codingStandardsIgnoreEnd
                        $tokens = preg_split( '/(\\\\*")/', $arg, -1, PREG_SPLIT_DELIM_CAPTURE );
                        $arg = '';
                        $iteration = 0;
@@@ -2732,9 -2710,9 +2732,9 @@@ function wfShellExecDisabled() 
                        $functions = explode( ',', ini_get( 'disable_functions' ) );
                        $functions = array_map( 'trim', $functions );
                        $functions = array_map( 'strtolower', $functions );
 -                      if ( in_array( 'passthru', $functions ) ) {
 -                              wfDebug( "passthru is in disabled_functions\n" );
 -                              $disabled = 'passthru';
 +                      if ( in_array( 'proc_open', $functions ) ) {
 +                              wfDebug( "proc_open is in disabled_functions\n" );
 +                              $disabled = 'disabled';
                        }
                }
        }
   * configuration if supported.
   * @param string $cmd Command line, properly escaped for shell.
   * @param &$retval null|Mixed optional, will receive the program's exit code.
 - *                 (non-zero is usually failure)
 + *                 (non-zero is usually failure). If there is an error from
 + *                 read, select, or proc_open(), this will be set to -1.
   * @param array $environ optional environment variables which should be
   *                 added to the executed command environment.
   * @param array $limits optional array with limits(filesize, memory, time, walltime)
   *                 this overwrites the global wgShellMax* limits.
 - * @param array $options Array of options. Only one is "duplicateStderr" => true, which
 - *                 Which duplicates stderr to stdout, including errors from limit.sh
 + * @param array $options Array of options:
 + *    - duplicateStderr: Set this to true to duplicate stderr to stdout, 
 + *      including errors from limit.sh
 + *      
   * @return string collected stdout as a string
   */
 -function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array(), $options = array() ) {
 +function wfShellExec( $cmd, &$retval = null, $environ = array(),
 +      $limits = array(), $options = array()
 +) {
        global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime,
                $wgMaxShellWallClockTime, $wgShellCgroup;
  
                $retval = 1;
                return $disabled == 'safemode' ?
                        'Unable to run external programs in safe mode.' :
 -                      'Unable to run external programs, passthru() is disabled.';
 +                      'Unable to run external programs, proc_open() is disabled.';
        }
  
        $includeStderr = isset( $options['duplicateStderr'] ) && $options['duplicateStderr'];
        }
        $cmd = $envcmd . $cmd;
  
 +      $useLogPipe = false;
        if ( php_uname( 's' ) == 'Linux' ) {
                $time = intval ( isset( $limits['time'] ) ? $limits['time'] : $wgMaxShellTime );
                if ( isset( $limits['walltime'] ) ) {
                                        'MW_CGROUP=' . escapeshellarg( $wgShellCgroup ) . '; ' .
                                        "MW_MEM_LIMIT=$mem; " .
                                        "MW_FILE_SIZE_LIMIT=$filesize; " .
 -                                      "MW_WALL_CLOCK_LIMIT=$wallTime"
 +                                      "MW_WALL_CLOCK_LIMIT=$wallTime; " .
 +                                      "MW_USE_LOG_PIPE=yes"
                                );
 +                      $useLogPipe = true;
                } elseif ( $includeStderr ) {
                        $cmd .= ' 2>&1';
                }
        }
        wfDebug( "wfShellExec: $cmd\n" );
  
 -      // Default to an unusual value that shouldn't happen naturally,
 -      // so in the unlikely event of a weird php bug, it would be
 -      // more obvious what happened.
 -      $retval = 200;
 -      ob_start();
 -      passthru( $cmd, $retval );
 -      $output = ob_get_contents();
 -      ob_end_clean();
 +      $desc = array(
 +              0 => array( 'file', 'php://stdin', 'r' ),
 +              1 => array( 'pipe', 'w' ),
 +              2 => array( 'file', 'php://stderr', 'w' ) );
 +      if ( $useLogPipe ) {
 +              $desc[3] = array( 'pipe', 'w' );
 +      }
 +      $pipes = null;
 +      $proc = proc_open( $cmd, $desc, $pipes );
 +      if ( !$proc ) {
 +              wfDebugLog( 'exec', "proc_open() failed: $cmd\n" );
 +              $retval = -1;
 +              return '';
 +      }
 +      $outBuffer = $logBuffer = '';
 +      $emptyArray = array();
 +      $status = false;
 +      $logMsg = false;
 +
 +      // According to the documentation, it is possible for stream_select()
 +      // to fail due to EINTR. I haven't managed to induce this in testing 
 +      // despite sending various signals. If it did happen, the error 
 +      // message would take the form: 
 +      //
 +      // stream_select(): unable to select [4]: Interrupted system call (max_fd=5)
 +      //
 +      // where [4] is the value of the macro EINTR and "Interrupted system
 +      // call" is string which according to the Linux manual is "possibly"
 +      // localised according to LC_MESSAGES.
 +      $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;
 +      }
 +
 +      while ( true ) {
 +              $status = proc_get_status( $proc );
 +              if ( !$status['running'] ) {
 +                      break;
 +              }
 +              $status = false;
  
 -      if ( $retval == 127 ) {
 -              wfDebugLog( 'exec', "Possibly missing executable file: $cmd\n" );
 +              $readyPipes = $pipes;
 +
 +              // Clear last error
 +              @trigger_error( '' );
 +              if ( @stream_select( $readyPipes, $emptyArray, $emptyArray, null ) === false ) {
 +                      $error = error_get_last();
 +                      if ( strncmp( $error['message'], $eintrMessage, strlen( $eintrMessage ) ) == 0 ) {
 +                              continue;
 +                      } else {
 +                              trigger_error( $error['message'], E_USER_WARNING );
 +                              $logMsg = $error['message'];
 +                              break;
 +                      }
 +              }
 +              foreach ( $readyPipes as $pipe ) {
 +                      $block = fread( $pipe, 65536 );
 +                      $fd = $fds[(int)$pipe];
 +                      if ( $block === '' ) {
 +                              // End of file
 +                              fclose( $pipes[$fd] );
 +                              unset( $pipes[$fd] );
 +                              if ( !$pipes ) {
 +                                      break 2;
 +                              }
 +                      } elseif ( $block === false ) {
 +                              // Read error
 +                              $logMsg = "Error reading from pipe";
 +                              break 2;
 +                      } elseif ( $fd == 1 ) {
 +                              // From stdout
 +                              $outBuffer .= $block;
 +                      } elseif ( $fd == 3 ) {
 +                              // From log FD
 +                              $logBuffer .= $block;
 +                              if ( strpos( $block, "\n" ) !== false ) {
 +                                      $lines = explode( "\n", $logBuffer );
 +                                      $logBuffer = array_pop( $lines );
 +                                      foreach ( $lines as $line ) {
 +                                              wfDebugLog( 'exec', $line );
 +                                      }
 +                              }
 +                      }
 +              }
        }
 -      return $output;
 +
 +      foreach ( $pipes as $pipe ) {
 +              fclose( $pipe );
 +      }
 +
 +      // Use the status previously collected if possible, since proc_get_status()
 +      // just calls waitpid() which will not return anything useful the second time.
 +      if ( $status === false ) {
 +              $status = proc_get_status( $proc );
 +      }
 +
 +      if ( $logMsg !== false ) {
 +              // Read/select error
 +              $retval = -1;
 +              proc_close( $proc );
 +      } elseif ( $status['signaled'] ) {
 +              $logMsg = "Exited with signal {$status['termsig']}";
 +              $retval = 128 + $status['termsig'];
 +              proc_close( $proc );
 +      } else {
 +              if ( $status['running'] ) {
 +                      $retval = proc_close( $proc );
 +              } else {
 +                      $retval = $status['exitcode'];
 +                      proc_close( $proc );
 +              }
 +              if ( $retval == 127 ) {
 +                      $logMsg = "Possibly missing executable file";
 +              } elseif ( $retval >= 129 && $retval <= 192 ) {
 +                      $logMsg = "Probably exited with signal " . ( $retval - 128 );
 +              }
 +      }
 +
 +      if ( $logMsg !== false ) {
 +              wfDebugLog( 'exec', "$logMsg: $cmd\n" );
 +      }
 +
 +      return $outBuffer;
  }
  
  /**
@@@ -3211,14 -3065,6 +3211,14 @@@ function wfUsePHP( $req_ver ) 
   * This is useful for extensions which due to their nature are not kept in sync
   * with releases
   *
 + * Note: Due to the behavior of PHP's version_compare() which is used in this
 + * fuction, if you want to allow the 'wmf' development versions add a 'c' (or
 + * any single letter other than 'a', 'b' or 'p') as a post-fix to your
 + * targeted version number. For example if you wanted to allow any variation
 + * of 1.22 use `wfUseMW( '1.22c' )`. Using an 'a' or 'b' instead of 'c' will
 + * not result in the same comparison due to the internal logic of
 + * version_compare().
 + *
   * @see perldoc -f use
   *
   * @param $req_ver Mixed: the version to check, can be a string, an integer, or
@@@ -3246,12 -3092,9 +3246,12 @@@ function wfUseMW( $req_ver ) 
   * @return String
   */
  function wfBaseName( $path, $suffix = '' ) {
 -      $encSuffix = ( $suffix == '' )
 -              ? ''
 -              : ( '(?:' . preg_quote( $suffix, '#' ) . ')?' );
 +      if ( $suffix == '' ) {
 +              $encSuffix = '';
 +      } else {
 +              $encSuffix = '(?:' . preg_quote( $suffix, '#' ) . ')?';
 +      }
 +
        $matches = array();
        if ( preg_match( "#([^/\\\\]*?){$encSuffix}[/\\\\]*$#", $path, $matches ) ) {
                return $matches[1];
@@@ -3332,9 -3175,7 +3332,9 @@@ function wfDoUpdates( $commit = '' ) 
   * @param string $engine Either "gmp", "bcmath", or "php"
   * @return string|bool The output number as a string, or false on error
   */
 -function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = true, $engine = 'auto' ) {
 +function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1,
 +      $lowercase = true, $engine = 'auto'
 +) {
        $input = (string)$input;
        if (
                $sourceBase < 2 ||
                $sourceBase != (int)$sourceBase ||
                $destBase != (int)$destBase ||
                $pad != (int)$pad ||
 -              !preg_match( "/^[" . substr( '0123456789abcdefghijklmnopqrstuvwxyz', 0, $sourceBase ) . "]+$/i", $input )
 +              !preg_match(
 +                      "/^[" . substr( '0123456789abcdefghijklmnopqrstuvwxyz', 0, $sourceBase ) . "]+$/i",
 +                      $input
 +              )
        ) {
                return false;
        }
@@@ -3481,11 -3319,9 +3481,11 @@@ function wfFixSessionID() 
        // 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 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" );
 +              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 ) );
        }
  }
@@@ -3791,7 -3627,9 +3791,7 @@@ function wfBoolToStr( $value ) 
   * @return string
   */
  function wfGetNull() {
 -      return wfIsWindows()
 -              ? 'NUL'
 -              : '/dev/null';
 +      return wfIsWindows() ? 'NUL' : '/dev/null';
  }
  
  /**
   * in maintenance scripts, to avoid causing too much lag.  Of course, this is
   * a no-op if there are no slaves.
   *
 - * @param $maxLag Integer (deprecated)
 - * @param $wiki mixed Wiki identifier accepted by wfGetLB
 - * @param $cluster string cluster name accepted by LBFactory
 + * @param int|bool $maxLag (deprecated)
 + * @param mixed $wiki Wiki identifier accepted by wfGetLB
 + * @param string|bool $cluster Cluster name accepted by LBFactory. Default: false.
   */
  function wfWaitForSlaves( $maxLag = false, $wiki = false, $cluster = false ) {
 -      $lb = ( $cluster !== false )
 -              ? wfGetLBFactory()->getExternalLB( $cluster )
 -              : wfGetLB( $wiki );
 +      if( $cluster !== false ) {
 +              $lb = wfGetLBFactory()->getExternalLB( $cluster );
 +      } else {
 +              $lb = wfGetLB( $wiki );
 +      }
 +
        // bug 27975 - Don't try to wait for slaves if there are none
        // Prevents permission error when getting master position
        if ( $lb->getServerCount() > 1 ) {
@@@ -3866,10 -3701,8 +3866,10 @@@ function wfCountDown( $n ) 
   *              characters before hashing.
   * @return string
   * @codeCoverageIgnore
 - * @deprecated since 1.20; Please use MWCryptRand for security purposes and wfRandomString for pseudo-random strings
 - * @warning This method is NOT secure. Additionally it has many callers that use it for pseudo-random purposes.
 + * @deprecated since 1.20; Please use MWCryptRand for security purposes and
 + * wfRandomString for pseudo-random strings
 + * @warning This method is NOT secure. Additionally it has many callers that
 + * use it for pseudo-random purposes.
   */
  function wfGenerateToken( $salt = '' ) {
        wfDeprecated( __METHOD__, '1.20' );