Allow wfShellExec() to use an array as a command prompt
[lhc/web/wiklou.git] / includes / GlobalFunctions.php
index cb5b7fd..6850734 100644 (file)
@@ -35,16 +35,6 @@ if ( !defined( 'MEDIAWIKI' ) ) {
  * PHP extensions may be included here.
  */
 
-if ( !function_exists( 'iconv' ) ) {
-       /**
-        * @codeCoverageIgnore
-        * @return string
-        */
-       function iconv( $from, $to, $string ) {
-               return Fallback::iconv( $from, $to, $string );
-       }
-}
-
 if ( !function_exists( 'mb_substr' ) ) {
        /**
         * @codeCoverageIgnore
@@ -2028,36 +2018,6 @@ function wfShowingResults( $offset, $limit ) {
        return wfMessage( 'showingresults' )->numParams( $limit, $offset + 1 )->parse();
 }
 
-/**
- * Generate (prev x| next x) (20|50|100...) type links for paging
- *
- * @param string $offset
- * @param int $limit
- * @param string $link
- * @param string $query Optional URL query parameter string
- * @param bool $atend Optional param for specified if this is the last page
- * @return string
- * @deprecated since 1.19; use Language::viewPrevNext() instead
- */
-function wfViewPrevNext( $offset, $limit, $link, $query = '', $atend = false ) {
-       wfDeprecated( __METHOD__, '1.19' );
-
-       global $wgLang;
-
-       $query = wfCgiToArray( $query );
-
-       if ( is_object( $link ) ) {
-               $title = $link;
-       } else {
-               $title = Title::newFromText( $link );
-               if ( is_null( $title ) ) {
-                       return false;
-               }
-       }
-
-       return $wgLang->viewPrevNext( $title, $offset, $limit, $query, $atend );
-}
-
 /**
  * @todo document
  * @todo FIXME: We may want to blacklist some broken browsers
@@ -2825,7 +2785,9 @@ function wfShellExecDisabled() {
  * Execute a shell command, with time and memory limits mirrored from the PHP
  * configuration if supported.
  *
- * @param string $cmd Command line, properly escaped for shell.
+ * @param string|string[] $cmd if string, a properly shell-escaped command line,
+ *   or an array of unescaped arguments, in which case each value will be escaped
+ *   Example:   [ 'convert', '-font', 'font name' ] would produce "'convert' '-font' 'font name'"
  * @param null|mixed &$retval Optional, will receive the program's exit code.
  *   (non-zero is usually failure). If there is an error from
  *   read, select, or proc_open(), this will be set to -1.
@@ -2874,6 +2836,15 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(),
                        $envcmd .= "$k=" . escapeshellarg( $v ) . ' ';
                }
        }
+       if ( is_array( $cmd ) ) {
+               // Command line may be given as an array, escape each value and glue them together with a space
+               $cmdVals = array();
+               foreach ( $cmd as $val ) {
+                       $cmdVals[] = wfEscapeShellArg( $val );
+               }
+               $cmd = implode( ' ', $cmdVals );
+       }
+
        $cmd = $envcmd . $cmd;
 
        $useLogPipe = false;
@@ -2950,19 +2921,28 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(),
                $fds[(int)$pipe] = $fd;
        }
 
-       while ( true ) {
-               $status = proc_get_status( $proc );
-               if ( !$status['running'] ) {
-                       break;
+       $running = true;
+       $timeout = null;
+       $numReadyPipes = 0;
+
+       while ( $running === true || $numReadyPipes !== 0 ) {
+               if ( $running ) {
+                       $status = proc_get_status( $proc );
+                       // If the process has terminated, switch to nonblocking selects
+                       // for getting any data still waiting to be read.
+                       if ( !$status['running'] ) {
+                               $running = false;
+                               $timeout = 0;
+                       }
                }
-               $status = false;
 
                $readyPipes = $pipes;
 
                // Clear last error
                // @codingStandardsIgnoreStart Generic.PHP.NoSilencedErrors.Discouraged
                @trigger_error( '' );
-               if ( @stream_select( $readyPipes, $emptyArray, $emptyArray, null ) === false ) {
+               $numReadyPipes = @stream_select( $readyPipes, $emptyArray, $emptyArray, $timeout );
+               if ( $numReadyPipes === false ) {
                        // @codingStandardsIgnoreEnd
                        $error = error_get_last();
                        if ( strncmp( $error['message'], $eintrMessage, strlen( $eintrMessage ) ) == 0 ) {
@@ -3010,7 +2990,7 @@ function wfShellExec( $cmd, &$retval = null, $environ = array(),
 
        // 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 ) {
+       if ( $running ) {
                $status = proc_get_status( $proc );
        }
 
@@ -3828,11 +3808,14 @@ function wfGetNull() {
  * in maintenance scripts, to avoid causing too much lag.  Of course, this is
  * a no-op if there are no slaves.
  *
- * @param int|bool $maxLag (deprecated)
+ * @param float|null $ifWritesSince Only wait if writes were done since this UNIX timestamp
  * @param string|bool $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 ) {
+function wfWaitForSlaves( $ifWritesSince = false, $wiki = false, $cluster = false ) {
+       // B/C: first argument used to be "max seconds of lag"; ignore such values
+       $ifWritesSince = ( $ifWritesSince > 1e9 ) ? $ifWritesSince : false;
+
        if ( $cluster !== false ) {
                $lb = wfGetLBFactory()->getExternalLB( $cluster );
        } else {
@@ -3842,7 +3825,13 @@ function wfWaitForSlaves( $maxLag = false, $wiki = false, $cluster = false ) {
        // bug 27975 - Don't try to wait for slaves if there are none
        // Prevents permission error when getting master position
        if ( $lb->getServerCount() > 1 ) {
+               if ( $ifWritesSince && !$lb->hasMasterConnection() ) {
+                       return; // assume no writes done
+               }
                $dbw = $lb->getConnection( DB_MASTER, array(), $wiki );
+               if ( $ifWritesSince && $dbw->lastDoneWrites() < $ifWritesSince ) {
+                       return; // no writes since the last wait
+               }
                $pos = $dbw->getMasterPos();
                // The DBMS may not support getMasterPos() or the whole
                // load balancer might be fake (e.g. $wgAllDBsAreLocalhost).