phpbashshellshell-exec

Bash script live output executed from PHP


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

Solution

  • 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.