8

What I want is being able to optionally pipe STDIO to a PHP script. If not, it'll take input from a file instead. So sometimes I'll simply run the script, other times I'll do something like

grep text logfile | php parseLog.php

I have a loop very much like this and it works fine when STDIO exists:

while (FALSE !== ($line = fgets(STDIN)))
{
        $customLogArr[]=$line;
}

When there's no STDIO though it halts waiting for some, it doesn't even enter the loop.

What I'd like to do is be able to detect if I have STDIO input or not. Is there a way to do that?

0

6 Answers 6

3

Using posix_isatty() function might be a little simpler.

<?php

/**
 * parseLog.php
 */

echo (posix_isatty(STDIN)) ? 'no stdin' . PHP_EOL : file_get_contents('php://stdin');

$ echo 'foo' > ./logfile.txt

$ cat logfile.txt | php parseLog.php
foo

$ php parseLog.php
no stdin

posix_isatty(STDIN) determines if the STDIN is open AND connected to a terminal. Thus, while receiving data from the STDIN, it will return false.

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

Comments

2

looks like something has changed or none of these answers were ever correct. You cannot simply ftell(STDIN) to see if there is data passed from STDIN

<?php

$stdin = fopen('php://stdin', 'r');
var_dump(ftell($stdin));

outputs

-:4:
bool(false)

This is from php -v with output

PHP 7.0.22-0ubuntu0.16.04.1 (cli) ( NTS )
Copyright (c) 1997-2017 The PHP Group
Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies
    with Zend OPcache v7.0.22-0ubuntu0.16.04.1, Copyright (c) 1999-2017, by Zend Technologies
    with Xdebug v2.4.0, Copyright (c) 2002-2016, by Derick Rethans

when I try to use STDIN constant I get

PHP Notice:  Use of undefined constant STDIN - assumed 'STDIN' in - on line 3

Comments

1
if(FALSE !== ftell(STDIN))
{
    while (FALSE !== ($line = fgets(STDIN)))
    {
        $customLogArr[]=$line;
    }
}

For STDIN, if nothing can be read, ftell() will return false.

4 Comments

Last time I checked STDIN position never zeroed on read from STDIN and it was always a non-negative integer so ftell always returns integer.
@DeDee Yes,you are right. So false only mean No STDIN for current process.
Correct, until STDIN is closed.
php7 @ version 7 PHP 7.0.22-0ubuntu0.16.04.1 (cli) ( NTS ) seems to complain there is no STDIN defined. PHP Notice: Use of undefined constant STDIN - assumed 'STDIN' in - on line 3
1

Is this what you're looking for? Forgive me if I misunderstood, this should not hold you when there's no input on STDIN.

stream_set_blocking(STDIN, 1);

function CheckSTDIN() {
    $read = array(STDIN);
    $wrte = NULL;
    $expt = NULL;
    $a = stream_select($read, $wrte, $expt, 0);
    if ($a && in_array(STDIN, $read)) {
        // you can read from STDIN now, it'll only be available if there is anything in STDIN
        // you can return the value or pass it to global or class variable
        return fread(STDIN, 255); // set your desired string length
    } else return false;
}

while (FALSE !== ($line = CheckSTDIN())) {
        $customLogArr[]=$line;
}

6 Comments

Strange it does not work for you, I extracted it from my OOP project for which it works the way I described.
I reran, yes but: fread() expects exactly 2 parameters, 1 given
Oh, I assumed second one is some default, I use 1 in my case, it's an example though of how the stream content can be retrieved. EDIT: fixed fread.
@ErickRobertson In the comment above I said I extracted it from my own project. It was a Windows Apache project. It sure worked.
I don't have Apache. I just have Windows. It doesn't work on Windows. You need either Apache or Linux.
|
0

Consider a script like this:

#!/usr/bin/env php                                                              
<?php                                                                           
                                                                                
$fhandle = fopen("php://stdin", 'r');                                           
$stdinData = ftell($fhandle) === false // strict comparison required                             
    ? null                                                                      
    : stream_get_contents($fhandle);                                            
var_dump($stdinData);

The sript outputs this when no stdin data provided:

$ ./test.php 
NULL

The sript outputs this when stdin data provided:

$ ./test.php < ./test.php 
string(173) "#!/usr/bin/env php
<?php

$fhandle = fopen("php://stdin", 'r');
$stdinData = ftell($fhandle) === false // strict comparison required
    ? null
    : stream_get_contents($fhandle);
var_dump($stdinData);
"

The important part is to use strict comparison (===) as ftell returns pointer position that has a value of 0 in case the handle has just been initialized.

For PHP 7.3 and earlier slightly different approach has to be utilized:

#!/usr/bin/env php
<?php

stream_set_blocking(STDIN, 0);
$stdinData = ftell(STDIN) === false // strict comparison required
    ? null
    : stream_get_contents(STDIN);
var_dump($stdinData);

Comments

-1

The above solution didn't work for me. This is one that works.

if ($args = stream_get_contents(fopen("php://stdin", "r"))) {

    var_dump($args);

} else {
    echo 'No input';
}

Note: This will read the data piped to the script as a string: echo "Hello World" | php test.php will output string(12) "Hello World" (+ the new line at the end...) So you need to further process the data to an array if that is required. explode() seems to be a simple approach.

3 Comments

But it hangs when nothing is one STDIN. That's what OP is trying to get around.
Correct, this won't work when there's no STDIN unfortunately. I wish. :)
The problem is trying to get contents without ftell($resource) first. Most of the code on this page works if you just know what you are doing and why.

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.