10

设置和背景

我正在处理需要运行的脚本,/usr/bin/php-cgi/usr/local/bin/php我无法检查stdin

如果我/usr/local/bin/php用作口译员,我可以做类似的事情

if defined('STDIN'){ ... }

这似乎不适用于 php-cgi - 看起来总是未定义。我检查了php-cgi 的手册页,但没有发现它很有帮助。另外,如果我理解正确,该STDIN常量是php://stdin. 我在某处读到常量不应该在php-cgi

要求

  • shebang 必须是#!/usr/bin/php-cgi -q
  • 脚本有时会传递参数
  • 该脚本有时会通过以下方式接收输入STDIN

当前脚本

#!/usr/bin/php-cgi -q
<?php

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

if($fh)
{

    while ($line = fgets( $fh )) {
            $stdin .= $line;
    }
    fclose($fh);

}

echo $stdin;

有问题的行为

这工作正常:

$ echo hello | ./myscript.php 
hello

这只是挂起:

./myscript.php 

这些东西对我不起作用:

  • 检查defined('STDIN')// 总是返回 false
  • 查看是否CONTENT_LENGTH已定义
  • 检查变量和常量

我已将此添加到脚本中并以两种方式运行:

print_r(get_defined_constants());
print_r($GLOBALS);
print_r($_COOKIE);
print_r($_ENV);
print_r($_FILES);
print_r($_GET);
print_r($_POST);
print_r($_REQUEST);
print_r($_SERVER);
echo shell_exec('printenv');

然后我对输出进行了比较,它是相同的。

如果脚本不存在,我不知道有任何其他方法可以在不锁定脚本的情况下检查/stdin通过。php-cgi

/usr/bin/php-cgi -v产量:PHP 5.4.17 (cgi-fcgi)

4

4 回答 4

7

您可以使用选择功能,例如:

$stdin = '';
$fh = fopen('php://stdin', 'r');
$read  = array($fh);
$write = NULL;
$except = NULL;
if ( stream_select( $read, $write, $except, 0 ) === 1 ) {
    while ($line = fgets( $fh )) {
            $stdin .= $line;
    }
}
fclose($fh);
于 2016-04-08T07:54:23.260 回答
2

关于您在没有输入时挂起的具体问题:默认情况下,php流读取是阻塞操作。您可以使用 更改该行为stream_set_blocking()。像这样:

$fh = fopen('php://stdin', 'r');
stream_set_blocking($fh, false);
$stdin = fgets($fh);
echo "stdin: '$stdin'";  // immediately returns "stdin: ''"

请注意,此解决方案不适用于该魔术文件句柄STDIN

于 2015-06-09T19:04:52.507 回答
1

stream_get_meta_data帮助过我 :)

正如Seth Battin stream_set_blocking($fh, false);在之前的回答中所提到的,效果很好

下一个代码从命令行读取数据(如果提供)并在没有提供时跳过。

例如: echo "x" | php render.phpphp render.php

在第一种情况下,我提供了来自另一个流的一些数据(我真的需要从 git 中查看更改的文件,例如git status | php render.php.

这是我的解决方案的一个例子:

$input = [];

$fp = fopen('php://stdin', 'r+');
$info = stream_get_meta_data($fp);

if (!$info['seekable'] && $fp) {
    while (false !== ($line = fgets($fp))) {
        $input[] = trim($line);
    }
    fclose($fp);
}
于 2020-05-13T11:16:25.093 回答
0

问题是您使用while($line = fgets($fh))代码中的部分创建了一个无限循环。

$stdin = '';
$fh = fopen('php://stdin','r');
if($fh) {
  // read *one* line from stdin upto "\r\n"
  $stdin = fgets($fh);
  fclose($fh);
}
echo $stdin;

如果您传递类似的参数,上述方法将起作用,echo foo=bar | ./myscript.php并且当您调用它时将读取一行./myscript.php 如果您想阅读更多行并保留原始代码,您可以发送退出信号CTRL + D

要获得传递的参数,./myscript.php foo=bar您可以检查$argv变量的内容,其中第一个参数始终是执行脚本的名称:

 ./myscript.php foo=bar

 // File: myscript.php
 $stdin = '';
 for($i = 1; $i < count($argv); i++) {
    $stdin .= $argv[$i];
 }

我不确定这是否可以解决任何问题,但也许它会给您一些想法。

于 2013-08-08T23:58:36.920 回答