Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

getting the real exit code after proc_open

I'm using proc_open in php to launch a subprocess and send data back and forth.

At some point I'd like to wait for the process to end and retrieve the exit code.

The problem is that if the process has already finished, my call to proc_close returns -1. There is apparently much confusion over what proc_close does actually return and I haven't found a way to reliably determine the exit code of a process opened with proc_open.

I've tried using proc_get_status, but it seems to also return -1 when the process has already exited.


Update

I can't get proc_get_status to ever give me a valid exit code, no matter how or when it is called. Is it broken completely?.

like image 267
Daniel Beardsley Avatar asked Oct 04 '11 09:10

Daniel Beardsley


2 Answers

My understanding is that proc_close will never give you a legit exit code.

You can only grab the legit exit code the first time you run proc_get_status after the process has ended. Here's a process class that I stole off the php.net user contributed notes. The answer to your question is in the is_running() method:

<?php
class process {

    public $cmd = '';
    private $descriptors = array(
            0 => array('pipe', 'r'),
            1 => array('pipe', 'w'),
            2 => array('pipe', 'w')
        );
    public $pipes = NULL;
    public $desc = '';
    private $strt_tm = 0;
    public $resource = NULL;
    private $exitcode = NULL;

    function __construct($cmd = '', $desc = '')
    {
        $this->cmd = $cmd;
        $this->desc = $desc;

        $this->resource = proc_open($this->cmd, $this->descriptors, $this->pipes, NULL, $_ENV);

        $this->strt_tm = microtime(TRUE);
    }

    public function is_running()
    {
        $status = proc_get_status($this->resource);

        /**
         * proc_get_status will only pull valid exitcode one
         * time after process has ended, so cache the exitcode
         * if the process is finished and $exitcode is uninitialized
         */
        if ($status['running'] === FALSE && $this->exitcode === NULL)
            $this->exitcode = $status['exitcode'];

        return $status['running'];
    }

    public function get_exitcode()
    {
        return $this->exitcode;
    }

    public function get_elapsed()
    {
        return microtime(TRUE) - $this->strt_tm;
    }
}

Hope this helps.

like image 83
Chad Brogan Avatar answered Nov 14 '22 00:11

Chad Brogan


I also was getting unexpected results trying to get the return code via proc_get_status, until I realized I was getting the return code of the last command I had executed (I was passing a series of commands to proc_open, separated by ;).

Once I broke the commands into individual proc_open calls, I used the following loop to get the correct return code. Note that normally the code is executing proc_get_status twice, and the correct return code is being returned on the second execution. Also, the code below could be dangerous if the process never terminates. I'm just using it as an example:

$status = proc_get_status($process);
while ($status["running"]) {
  sleep(1);
  $status = proc_get_status($process);
}
like image 2
spcurry Avatar answered Nov 13 '22 23:11

spcurry