Reputation: 349
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?
Upvotes: 8
Views: 1611
Reputation: 1224
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
.
Upvotes: 3
Reputation: 2673
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);
Upvotes: 0
Reputation: 1613
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
Upvotes: 2
Reputation: 120
if(FALSE !== ftell(STDIN))
{
while (FALSE !== ($line = fgets(STDIN)))
{
$customLogArr[]=$line;
}
}
For STDIN, if nothing can be read, ftell()
will return false.
Upvotes: 1
Reputation: 2002
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;
}
Upvotes: 1
Reputation: 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.
Upvotes: -1