3

I'm trying to execute a bash script from php and getting its output in real time.

I am applying the answers found here:

However they are not working for me.

When I invoke the .sh script on this way, it works fine:

<?php
  $output = shell_exec("./test.sh");
  echo "<pre>$output</pre>";
?>

However, when doing:

<?php
  echo '<pre>';
  passthru(./test.sh);
  echo '</pre>';
?>

or:

<?php
  while (@ ob_end_flush()); // end all output buffers if any
  $proc = popen(./test.sh, 'r');
  echo '<pre>';
  while (!feof($proc))
    {
    echo fread($proc, 4096);
    @ flush();
    }
  echo '</pre>';
?>

I have no output in my browser.

I also tried to call the variable instead of the script in both cases, I mean:

<?php
  $output = shell_exec("./test.sh");
  echo '<pre>';
  passthru($output);
  echo '</pre>';
?>

This is my test.sh script:

#!/bin/bash
whoami
sleep 3
dmesg
2
  • the filename should be quoted - passthru("./test.sh"); - it doesn't work even like this? Commented Feb 27, 2017 at 13:04
  • @ewcz It does work with my test.sh example, thanks. However it doesn't work for the actual script I want to use. At least this is a beginning and I can analyze further from now on. If you write your comment as answer I will validate it. Commented Feb 27, 2017 at 13:26

1 Answer 1

5

Use the following:

<?php
ob_implicit_flush(true);
ob_end_flush();

$cmd = "bash /path/to/test.sh";

$descriptorspec = array(
   0 => array("pipe", "r"),   // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),   // stdout is a pipe that the child will write to
   2 => array("pipe", "w")    // stderr is a pipe that the child will write to
);


$process = proc_open($cmd, $descriptorspec, $pipes, realpath('./'), array());

if (is_resource($process)) {

    while ($s = fgets($pipes[1])) {
        print $s;

    }
}

?>

Change test.sh to:

#!/bin/bash
whoami
sleep 3
ls /

Explanation:

dmesg requires permissions. You need to grant webserver's user permissions for that. In my case apache2 is being run via www-data user.

ob_implicit_flush(true): Turns implicit flushing on. Implicit flushing will result in a flush operation after every output call, so that explicit calls to flush() will no longer be needed.

ob_end_flush(): Turns off output buffering, so we see results immediately.

Sign up to request clarification or add additional context in comments.

1 Comment

stream_select() + stream_get_contents() are better suited for the job, since fgets() stops reading when a newline comes (which is very likely to happen). Check my previous answer here: stackoverflow.com/a/37526704/1957951

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.