How to wait for a process executed by proc_open() in php?

后端 未结 2 1653
悲哀的现实
悲哀的现实 2021-01-03 10:17

please after reading this question , do not say that it is copied.I have already searched on web but none of the solution worked for me.

Wha

2条回答
  •  孤街浪徒
    2021-01-03 11:01

    Here's my go at it (reading both stdout and stderr (hopefully) without deadlocks):

    class ExecResult {
        public $returnValue;
        public $stdoutBuffer;
        public $stderrBuffer;
    }
    
    class WtfPhpWhyIHaveToDoEverythingMyself {
        public static function exec($proc, $argv) {
            $cwd = getcwd();
            $env = [];
    
            $procAndArgv = count($argv) > 0 ?
                $proc . ' ' . implode(' ', self::escapeArgvs($argv)) :
                $proc;
    
            $pipes = null; // will get filled by proc_open()
    
            $result = new ExecResult();
    
            $processHandle = proc_open(
                $procAndArgv,
                [
                    0 => ['pipe', 'r'], // read/write is from child process's perspective
                    1 => ['pipe', 'w'],
                    2 => ['pipe', 'w']
                ],
                $pipes,
                $cwd,
                $env);
    
            $stdin = $pipes[0];
            $stdout = $pipes[1];
            $stderr = $pipes[2];
    
            fclose($stdin);
    
            stream_set_blocking($stdout, false);
            stream_set_blocking($stderr, false);
    
            $outEof = false;
            $errEof = false;
    
            do {
                $read = [ $stdout, $stderr ]; // [1]
                $write = null; // [1]
                $except = null; // [1]
    
                // [1] need to be as variables because only vars can be passed by reference
    
                stream_select(
                    $read,
                    $write,
                    $except,
                    1, // seconds
                    0); // microseconds
    
                $outEof = $outEof || feof($stdout);
                $errEof = $errEof || feof($stderr);
    
                if (!$outEof) {
                    $result->stdoutBuffer .= fgets($stdout);
                }
    
                if (!$errEof) {
                    $result->stderrBuffer .= fgets($stderr);
                }
            } while(!$outEof || !$errEof);
    
            fclose($stdout);
            fclose($stderr);
    
            $result->returnValue = proc_close($processHandle);
    
            return $result;
        }
    
        private static function escapeArgvs($argv) {
            return array_map(function ($item){
                return escapeshellarg($item);
            }, $argv);
        }
    }
    
    $result = WtfPhpWhyIHaveToDoEverythingMyself::exec('/var/www/html/hello.sh', [
        'arg 1',
        'arg 2',
    ]);
    
    var_dump($result);
    
    /*
    object(ExecResult)#1 (3) {
      ["returnValue"]=> int(0)
      ["stdoutBuffer"]=>
      string(45) "var1 = arg 1
    var2 = arg 2
    "
      ["stderrBuffer"]=>
      string(0) ""
    }
    */
    

    I am really disappointed that with PHP, you have to write all the plumbing yourself. For example node.js has got your back covered with simple child_process.spawn()

提交回复
热议问题