PHP - 检测 STDIO 输入

PHP - detect STDIO input

我想要的是能够可选地通过管道将 STDIO 连接到 PHP 脚本。如果没有,它将改为从文件中获取输入。所以有时我会简单地 运行 脚本,其他时候我会做类似

的事情
grep text logfile | php parseLog.php

我有一个非常像这样的循环,当 STDIO 存在时它工作正常:

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

当没有STDIO时,虽然它会停止等待,但它甚至不会进入循环。

我想做的是能够检测如果我是否有 STDIO 输入。有办法吗?

这是您要找的吗?如果我误解了,请原谅我,当没有输入 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;
}

上述解决方案对我不起作用。这是一个有效的方法。

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

    var_dump($args);

} else {
    echo 'No input';
}

注意:这将读取作为字符串传输到脚本的数据:echo "Hello World" | php test.php 将输出 string(12) "Hello World" (+末尾的新行...)因此,如果需要,您需要将数据进一步处理到数组中。 explode() 似乎是一种简单的方法。

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

对于 STDIN,如果无法读取任何内容,ftell() 将 return 错误。

看起来有些地方发生了变化,或者 none 这些答案曾经是正确的。您不能简单地 ftell(STDIN) 查看是否有从 STDIN

传递的数据
<?php

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

输出

-:4:
bool(false)

这来自 php -v 输出

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

当我尝试使用 STDIN 常量时,我​​得到了

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

考虑这样的脚本:

#!/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);

当没有提供 stdin 数据时,sript 输出:

$ ./test.php 
NULL

脚本在 stdin 提供数据时输出:

$ ./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);
"

重要的部分是使用严格比较 (===) 作为 ftell returns 指针位置,其值为 0 以防句柄刚刚被已初始化。

对于 PHP 7.3 和更早版本,必须使用稍微不同的方法:

#!/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);

使用posix_isatty()函数可能会简单一些。

<?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) 确定 STDIN 是否打开并连接到终端。因此,当从 STDIN 接收数据时,它将 return false.