Getting Output and Exit Status from Shell_Exec()

getting output and exit status from shell_exec()

As you've already seen, when using shell_exec you have to chain your "real" command with echo $? to get the exit status:

 $output_including_status = shell_exec("command 2>&1; echo $?");

but if you want the clean way, then you want to use the exec function, which allows a 3rd agument explicitly for this purpose.

PHP reading shell_exec live output

To read the output of a process, popen() is the way to go. Your script will run in parallel with the program and you can interact with it by reading and writing it's output/input as if it was a file.

But if you just want to dump it's result straight to the user you can cut to the chase and use passthru():

echo '<pre>';
passthru($cmd);
echo '</pre>';

If you want to display the output at run time as the program goes, you can do this:

while (@ ob_end_flush()); // end all output buffers if any

$proc = popen($cmd, 'r');
echo '<pre>';
while (!feof($proc))
{
echo fread($proc, 4096);
@ flush();
}
echo '</pre>';

This code should run the command and push the output straight to the end user at run time.

More useful information

Note that if you are using sessions then having one of those running will prevent the user from loading other pages, as sessions enforce that concurrent requests cannot happen. To prevent this from being a problem, call session_write_close() before the loop.

If your server is behind a nginx gateway, then the nginx buffering may be disruptive to the desired behavior. Set the header header('X-Accel-Buffering: no'); to hint nginx that it shouldn't do that. As headers are sent first, this has to be called in the beginning of the script, before any data is sent.

PHP system(), exec(), and shell_exec() not returning output

I think that the issue is not that you not get the output of the executed command, but which fails to find mysql.
Using exec you can get the return status of your command, where 0 means successful, and other values indicate an error.

$output = exec($cmd, $output, $retval);
var_dump($output);
var_dump($retval);

If the $retval is 1 that would mean which doesn't find the mysql binary, and returns an empty line.

php system command with output and return code

Sounds like you're looking for output buffering:

ob_start();
system($command, $returnCode);
$output = ob_get_clean();

This should preserve all white-space characters at the end of each output line (exec as you wrote destroys these, so implode would not be an option).

Alternatively, you can open a process and aquire the pipes (standard output, STDOUT) and read the output out of these. But it's more complicated (but gives you more options). See proc_open.

Running shell_exec() in background AND getting its output afterwards

  • Solution for a similar problem: A few years ago I had a similar problem. I had to upload a file to a FTP server. I wondered how to communicate to the FTP server that the file was uploaded completely, so that the FTP server can perform some tasks on it. My solution was to rename the file to something like *.completed after it was uploaded completely. Then the process on the FTP server could look for *.completed files only.

  • Solution adjusted to your problem: I'd suggest you to rename your temp file after it was generated by your bash script. This way you can independently find out if the script was executed successfully. shell_exec() could look like this:

    shell_exec('<myscript> > tmp-file && mv tmp-file tmp-file.completed &');

    Be aware that this only redirects the channel STDOUT into the the tmp-file. If you also want to redirect STDERR into the tmp-file, try this:

    shell_exec('<myscript> &> tmp-file && mv tmp-file tmp-file.completed &');

Executing program in php - display and return output

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);
}
?>


Related Topics



Leave a reply



Submit