Search code examples
phpbashstdin

How to check if bash input is being redirect to PHP script?


I'm writing a PHP script and I would like to be able to optionally use a file as the script input. This way:

$ php script.php < file.txt

I'm, actually, able to do that using file_get_contents:

$data = file_get_contents('php://stdin');

However, if I don't pass a file to the input, the scripts hangs indefinetelly, waiting for an input.

I tried the following, but it didn't work:

$data = '';
$in = fopen('php://stdin', 'r');
do {
    $bytes = fread($in, 4096);
    // Maybe the input will be empty here?! But no, it's not :(
    if (empty($bytes)) {
        break;
    }
    $data .= $bytes;
} while (!feof($in));

The script waits for fread to return a value, but it never returns. I guess it waits for some input the same way file_get_contents does.

Another attempt was made by replacing the do { ... } while loop by a while { ... }, checking for the EOF before than trying to read the input. But that also didn't work.

Any ideas on how can I achieve that?


Solution

  • You can set STDIN to be non-blocking via the stream_set_blocking() function.

    function stdin()
    {
        $stdin = '';
        $fh = fopen('php://stdin', 'r');
        stream_set_blocking($fh, false);
        while (($line = fgets($fh)) !== false) {
            $stdin .= $line;
        }
        return $stdin;
    }
    
    $stdin = stdin(); // returns the contents of STDIN or empty string if nothing is ready
    

    Obviously, you can change the use of line-at-a-time fgets() to hunk-at-a-time fread() as per your needs.