7

In php there are several methods to execute a shell command:

  • system()
  • passthru()
  • shell_exec()
  • exec()

First two displays output but doesn't return it. Last two returns output but doesn't display it.

I want to run shell command which require a lot of time but it displays some output so I know it doesn't hang. However at the end I want to process this output in php. If I choose one of first two I won't get output so I will be unable to process it in php. If I run one of the last two I will be able to process output however my program will hang very long time without outputting anything.

Is there a way to run a shell command which will display output immediately and return it?

3
  • Does the second argument to the system() call not help? Commented Feb 27, 2012 at 16:10
  • Second argument is return status of the executed command e.g. 0 if everything was ok and 1 if there was error. I should mention I need this too - shell_exec() is the one which doesn't support that. Commented Feb 27, 2012 at 16:12
  • I don't think there's any PHP command that will execute shell code and print output to the screen before execution is finished. Commented Feb 27, 2012 at 16:17

2 Answers 2

2

Maybe this one will interest you? proc_open() - http://www.php.net/manual/en/function.proc-open.php

And here is a handy snippet which might work for you (it's copied from the comments on the site I gave you the link to):

<?php
/*
 * Execute and display the output in real time (stdout + stderr).
 *
 * Please note this snippet is prepended with an appropriate shebang for the 
 * CLI. You can re-use only the function.
 * 
 * Usage example:
 * chmod u+x proc_open.php
 * ./proc_open.php "ping -c 5 google.fr"; echo RetVal=$?
 */
define(BUF_SIZ, 1024);        # max buffer size
define(FD_WRITE, 0);        # stdin
define(FD_READ, 1);        # stdout
define(FD_ERR, 2);        # stderr

/*
 * Wrapper for proc_*() functions.
 * The first parameter $cmd is the command line to execute.
 * Return the exit code of the process.
 */
function proc_exec($cmd)
{
    $descriptorspec = array(
        0 => array("pipe", "r"),
        1 => array("pipe", "w"),
        2 => array("pipe", "w")
    );

    $ptr = proc_open($cmd, $descriptorspec, $pipes, NULL, $_ENV);
    if (!is_resource($ptr))
        return false;

    while (($buffer = fgets($pipes[FD_READ], BUF_SIZ)) != NULL 
            || ($errbuf = fgets($pipes[FD_ERR], BUF_SIZ)) != NULL) {
        if (!isset($flag)) {
            $pstatus = proc_get_status($ptr);
            $first_exitcode = $pstatus["exitcode"];
            $flag = true;
        }
        if (strlen($buffer))
            echo $buffer;
        if (strlen($errbuf))
            echo "ERR: " . $errbuf;
    }

    foreach ($pipes as $pipe)
        fclose($pipe);

    /* Get the expected *exit* code to return the value */
    $pstatus = proc_get_status($ptr);
    if (!strlen($pstatus["exitcode"]) || $pstatus["running"]) {
        /* we can trust the retval of proc_close() */
        if ($pstatus["running"])
            proc_terminate($ptr);
        $ret = proc_close($ptr);
    } else {
        if ((($first_exitcode + 256) % 256) == 255 
                && (($pstatus["exitcode"] + 256) % 256) != 255)
            $ret = $pstatus["exitcode"];
        elseif (!strlen($first_exitcode))
            $ret = $pstatus["exitcode"];
        elseif ((($first_exitcode + 256) % 256) != 255)
            $ret = $first_exitcode;
        else
            $ret = 0; /* we "deduce" an EXIT_SUCCESS ;) */
        proc_close($ptr);
    }

    return ($ret + 256) % 256;
}

/* __init__ */
if (isset($argv) && count($argv) > 1 && !empty($argv[1])) {
    if (($ret = proc_exec($argv[1])) === false)
        die("Error: not enough FD or out of memory.\n");
    elseif ($ret == 127)
        die("Command not found (returned by sh).\n");
    else
        exit($ret);
}
?>
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! There is no way I would ever deduce how to also get return status code:)
2

Maybe you can use popen(), that executes a program and reads its output through a file-handle, like so:

$handle = popen('/bin/ls', 'r');
while ($line = fread($handle, 100)){
    echo $line;
}
pclose($handle);

1 Comment

Thanks! This will work however I forgot to mention I need also return status of executed command so probably proc_open (which is similar) will allow me to do that - thanks anyway!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.