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
Community
  • 1
  • 1
Zumo de Vidrio
  • 2,021
  • 2
  • 15
  • 33
  • the filename should be quoted - `passthru("./test.sh");` - it doesn't work even like this? – ewcz Feb 27 '17 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. – Zumo de Vidrio Feb 27 '17 at 13:26

1 Answers1

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.

Farhad Farahi
  • 35,528
  • 7
  • 73
  • 70
  • 1
    `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: http://stackoverflow.com/a/37526704/1957951 – Gergely Lukacsy Feb 27 '17 at 15:08