如何检查PHP中是否存在stdin(php-cgi)?

时间:2013-08-08 23:31:25

标签: shell stdin php

设置和背景

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

如果我使用/usr/local/bin/php作为翻译,我可以做类似

的事情
if defined('STDIN'){ ... }

这似乎不适用于php-cgi - 看起来总是未定义。我检查了man page for 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 个答案:

答案 0 :(得分:3)

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

$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);

答案 1 :(得分:1)

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

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

请注意this solution does not work with that magic file handle STDIN.

答案 2 :(得分: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);
}

答案 3 :(得分: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];
 }

我不确定这会解决任何问题,但也许会给你一些想法。