testPngNativetZtxt requires zlib extension
[lhc/web/wiklou.git] / includes / GlobalFunctions.php
index 9779cb8..2292e31 100644 (file)
@@ -1235,11 +1235,15 @@ function wfLogProfilingData() {
  *
  * @param $key String
  * @param $count Int
+ * @return void
  */
 function wfIncrStats( $key, $count = 1 ) {
        global $wgStatsMethod;
 
        $count = intval( $count );
+       if ( $count == 0 ) {
+               return;
+       }
 
        if( $wgStatsMethod == 'udp' ) {
                global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgAggregateStatsID;
@@ -2437,7 +2441,7 @@ define( 'TS_ISO_8601_BASIC', 9 );
  * @param $outputtype Mixed: A timestamp in one of the supported formats, the
  *                    function will autodetect which format is supplied and act
  *                    accordingly.
- * @param $ts Mixed: the timestamp to convert or 0 for the current timestamp
+ * @param $ts Mixed: optional timestamp to convert, default 0 for the current time
  * @return Mixed: String / false The same date in the format specified in $outputtype or false
  */
 function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) {
@@ -2767,12 +2771,13 @@ function wfEscapeShellArg( ) {
  *                 (non-zero is usually failure)
  * @param $environ Array optional environment variables which should be
  *                 added to the executed command environment.
- * @param $limits Array optional array with limits(filesize, memory, time)
+ * @param $limits Array optional array with limits(filesize, memory, time, walltime)
  *                 this overwrites the global wgShellMax* limits.
  * @return string collected stdout as a string (trailing newlines stripped)
  */
 function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array() ) {
-       global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime;
+       global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime,
+               $wgMaxShellWallClockTime;
 
        static $disabled;
        if ( is_null( $disabled ) ) {
@@ -2820,14 +2825,19 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(), $limits = array
 
        if ( php_uname( 's' ) == 'Linux' ) {
                $time = intval ( isset($limits['time']) ? $limits['time'] : $wgMaxShellTime );
+               if ( isset( $limits['walltime'] ) ) {
+                       $wallTime = intval( $limits['walltime'] );
+               } elseif ( isset( $limits['time'] ) ) {
+                       $wallTime = $time;
+               } else {
+                       $wallTime = intval( $wgMaxShellWallClockTime );
+               }
                $mem = intval ( isset($limits['memory']) ? $limits['memory'] : $wgMaxShellMemory );
                $filesize = intval ( isset($limits['filesize']) ? $limits['filesize'] : $wgMaxShellFileSize );
 
-               if ( $time > 0 && $mem > 0 ) {
-                       $script = "$IP/bin/ulimit4.sh";
-                       if ( is_executable( $script ) ) {
-                               $cmd = '/bin/bash ' . escapeshellarg( $script ) . " $time $mem $filesize " . escapeshellarg( $cmd );
-                       }
+               if ( $time > 0 || $mem > 0 || $filesize > 0 || $wallTime > 0 ) {
+                       $cmd = '/bin/bash ' . escapeshellarg( "$IP/bin/ulimit5.sh" ) .
+                               " $time $mem $filesize $wallTime " . escapeshellarg( $cmd );
                }
        }
        wfDebug( "wfShellExec: $cmd\n" );
@@ -2936,7 +2946,7 @@ function wfMerge( $old, $mine, $yours, &$result ) {
        fclose( $yourtextFile );
 
        # Check for a conflict
-       $cmd = $wgDiff3 . ' -a --overlap-only ' .
+       $cmd = wfEscapeShellArg( $wgDiff3 ) . ' -a --overlap-only ' .
                wfEscapeShellArg( $mytextName ) . ' ' .
                wfEscapeShellArg( $oldtextName ) . ' ' .
                wfEscapeShellArg( $yourtextName );
@@ -2950,7 +2960,7 @@ function wfMerge( $old, $mine, $yours, &$result ) {
        pclose( $handle );
 
        # Merge differences
-       $cmd = $wgDiff3 . ' -a -e --merge ' .
+       $cmd = wfEscapeShellArg( $wgDiff3 ) . ' -a -e --merge ' .
                wfEscapeShellArg( $mytextName, $oldtextName, $yourtextName );
        $handle = popen( $cmd, 'r' );
        $result = '';
@@ -3179,84 +3189,97 @@ function wfDoUpdates( $commit = '' ) {
  * Supports base 2 through 36; digit values 10-36 are represented
  * as lowercase letters a-z. Input is case-insensitive.
  *
- * @param $input String: of digits
- * @param $sourceBase Integer: 2-36
- * @param $destBase Integer: 2-36
- * @param $pad Integer: 1 or greater
- * @param $lowercase Boolean
- * @return String or false on invalid input
- */
-function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = true ) {
-       $input = strval( $input );
-       if( $sourceBase < 2 ||
+ * @param string $input Input number
+ * @param int $sourceBase Base of the input number
+ * @param int $destBase Desired base of the output
+ * @param int $pad Minimum number of digits in the output (pad with zeroes)
+ * @param bool $lowercase Whether to output in lowercase or uppercase
+ * @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' ) {
+       if(
+               $sourceBase < 2 ||
                $sourceBase > 36 ||
                $destBase < 2 ||
                $destBase > 36 ||
-               $pad < 1 ||
-               $sourceBase != intval( $sourceBase ) ||
-               $destBase != intval( $destBase ) ||
-               $pad != intval( $pad ) ||
-               !is_string( $input ) ||
-               $input == '' ) {
+               $sourceBase != (int) $sourceBase ||
+               $destBase != (int) $destBase ||
+               $pad != (int) $pad ||
+               !preg_match( "/^[" . substr( '0123456789abcdefghijklmnopqrstuvwxyz', 0, $sourceBase ) . "]+$/i", $input )
+       ) {
                return false;
        }
-       $digitChars = ( $lowercase ) ? '0123456789abcdefghijklmnopqrstuvwxyz' : '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
-       $inDigits = array();
-       $outChars = '';
 
-       // Decode and validate input string
-       $input = strtolower( $input );
-       for( $i = 0; $i < strlen( $input ); $i++ ) {
-               $n = strpos( $digitChars, $input[$i] );
-               if( $n === false || $n > $sourceBase ) {
-                       return false;
+       static $baseChars = array (
+               10 => 'a', 11 => 'b', 12 => 'c', 13 => 'd', 14 => 'e', 15 => 'f',
+               16 => 'g', 17 => 'h', 18 => 'i', 19 => 'j', 20 => 'k', 21 => 'l',
+               22 => 'm', 23 => 'n', 24 => 'o', 25 => 'p', 26 => 'q', 27 => 'r',
+               28 => 's', 29 => 't', 30 => 'u', 31 => 'v', 32 => 'w', 33 => 'x',
+               34 => 'y', 35 => 'z',
+
+               '0' => 0,  '1' => 1,  '2' => 2,  '3' => 3,  '4' => 4,  '5' => 5,
+               '6' => 6,  '7' => 7,  '8' => 8,  '9' => 9,  'a' => 10, 'b' => 11,
+               'c' => 12, 'd' => 13, 'e' => 14, 'f' => 15, 'g' => 16, 'h' => 17,
+               'i' => 18, 'j' => 19, 'k' => 20, 'l' => 21, 'm' => 22, 'n' => 23,
+               'o' => 24, 'p' => 25, 'q' => 26, 'r' => 27, 's' => 28, 't' => 29,
+               'u' => 30, 'v' => 31, 'w' => 32, 'x' => 33, 'y' => 34, 'z' => 35
+       );
+
+       if( extension_loaded( 'gmp' ) && ( $engine == 'auto' || $engine == 'gmp' ) ) {
+               $result = gmp_strval( gmp_init( $input, $sourceBase ), $destBase );
+       } elseif( extension_loaded( 'bcmath' ) && ( $engine == 'auto' || $engine == 'bcmath' ) ) {
+               $decimal = '0';
+               foreach( str_split( strtolower( $input ) ) as $char ) {
+                       $decimal = bcmul( $decimal, $sourceBase );
+                       $decimal = bcadd( $decimal, $baseChars[$char] );
                }
-               $inDigits[] = $n;
-       }
 
-       // Iterate over the input, modulo-ing out an output digit
-       // at a time until input is gone.
-       while( count( $inDigits ) ) {
-               $work = 0;
-               $workDigits = array();
+               for( $result = ''; bccomp( $decimal, 0 ); $decimal = bcdiv( $decimal, $destBase, 0 ) ) {
+                       $result .= $baseChars[bcmod( $decimal, $destBase )];
+               }
 
-               // Long division...
-               foreach( $inDigits as $digit ) {
-                       $work *= $sourceBase;
-                       $work += $digit;
+               $result = strrev( $result );
+       } else {
+               $inDigits = array();
+               foreach( str_split( strtolower( $input ) ) as $char ) {
+                       $inDigits[] = $baseChars[$char];
+               }
 
-                       if( $work < $destBase ) {
-                               // Gonna need to pull another digit.
-                               if( count( $workDigits ) ) {
-                                       // Avoid zero-padding; this lets us find
-                                       // the end of the input very easily when
-                                       // length drops to zero.
-                                       $workDigits[] = 0;
-                               }
-                       } else {
-                               // Finally! Actual division!
-                               $workDigits[] = intval( $work / $destBase );
+               // Iterate over the input, modulo-ing out an output digit
+               // at a time until input is gone.
+               $result = '';
+               while( $inDigits ) {
+                       $work = 0;
+                       $workDigits = array();
 
-                               // Isn't it annoying that most programming languages
-                               // don't have a single divide-and-remainder operator,
-                               // even though the CPU implements it that way?
-                               $work = $work % $destBase;
+                       // Long division...
+                       foreach( $inDigits as $digit ) {
+                               $work *= $sourceBase;
+                               $work += $digit;
+
+                               if( $workDigits || $work >= $destBase ) {
+                                       $workDigits[] = (int) ( $work / $destBase );
+                               }
+                               $work %= $destBase;
                        }
-               }
 
-               // All that division leaves us with a remainder,
-               // which is conveniently our next output digit.
-               $outChars .= $digitChars[$work];
+                       // All that division leaves us with a remainder,
+                       // which is conveniently our next output digit.
+                       $result .= $baseChars[$work];
+
+                       // And we continue!
+                       $inDigits = $workDigits;
+               }
 
-               // And we continue!
-               $inDigits = $workDigits;
+               $result = strrev( $result );
        }
 
-       while( strlen( $outChars ) < $pad ) {
-               $outChars .= '0';
+       if( !$lowercase ) {
+               $result = strtoupper( $result );
        }
 
-       return strrev( $outChars );
+       return str_pad( $result, $pad, '0', STR_PAD_LEFT );
 }
 
 /**