PHP - 检测 STDIO 输入

8
我希望能够将 STDIO 可选地 传输到 PHP 脚本中。如果不这样做,它将从文件中获取输入。因此,有时我只需运行脚本,而其他时候我会执行类似以下操作的操作:
grep text logfile | php parseLog.php

我有一个循环非常类似于这个,当STDIO存在时它可以正常工作:

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

当没有标准输入输出时,程序会停止等待输入,甚至不进入循环。

我想要做的是能够检测是否有标准输入输出。有什么方法可以实现吗?

6个回答

3

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接收数据时,它将返回false


2

看起来有些东西已经改变了,或者这些答案从来都不正确。你不能简单地使用 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

1

这是您要找的吗?如果我误解了,请原谅,当标准输入没有输入时,这不应该阻止您。

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;
}

奇怪,它对你不起作用,我从我的面向对象编程项目中提取出来的代码可以像我描述的那样工作。 - DeDee
我重新运行了,但是出现了以下错误:fread()需要2个参数,但只提供了1个 - AbraCadaver
哦,我假设第二个是一些默认值,在我的情况下我使用了1,这只是一个示例,说明流内容如何被检索。编辑:修复了fread - DeDee
@ErickRobertson 在上面的评论中,我说我从自己的项目中提取了它。那是一个Windows Apache项目。它确实起作用了。 - DeDee
我没有Apache,只有Windows。它在Windows上无法运行。你需要使用Apache或Linux。 - Erick Robertson
@ErickRobertson 不相关,Apache提供Web服务器环境。上述代码在Windows 7上的PHP CLI中运行正常。老实说,我不知道为什么要提到Apache。你知道你需要PHP CLI吗? - DeDee

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

对于标准输入(STDIN),如果无法读取任何内容,ftell() 函数将返回 false。


上次我检查时,从STDIN读取时STDIN位置从未归零,它始终是非负整数,因此ftell始终返回integer - DeDee
@DeDee 是的,你说得对。所以 false 只是表示当前进程没有 STDIN。 - grant sun
正确,直到 STDIN 被关闭。 - DeDee
1
php7 @ 版本 7 PHP 7.0.22-0ubuntu0.16.04.1 (cli) ( NTS ) 看起来抱怨没有定义 STDIN。PHP Notice: Use of undefined constant STDIN - assumed 'STDIN' in - on line 3 - MrMesees

0

考虑这样的脚本:

#!/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数据时会输出这个:
$ ./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返回指针位置,在句柄刚被初始化时它的值为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);

-1

上述解决方案对我无效。这是一个有效的解决方案。

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() 似乎是一个简单的方法。

但是当没有任何STDIN输入时,程序会挂起。这就是OP试图避免的问题。 - AbraCadaver
很遗憾,当没有标准输入时,这是行不通的。我希望能够实现。 :) - Arkandel
问题在于首先没有使用 ftell($resource) 获取内容。如果您知道自己在做什么以及原因,那么此页面上的大多数代码都可以正常工作。 - MrMesees

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接