【问题标题】:PHP - detect STDIO inputPHP - 检测 STDIO 输入
【发布时间】:2015-02-17 21:08:16
【问题描述】:

我想要的是能够可选地将 STDIO 传送到 PHP 脚本。如果没有,它将改为从文件中获取输入。所以有时我会简单地运行脚本,有时我会做类似的事情

grep text logfile | php parseLog.php

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

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

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

我想做的是能够检测到如果我是否有 STDIO 输入。有没有办法做到这一点?

【问题讨论】:

    标签: php stdio


    【解决方案1】:
    if(FALSE !== ftell(STDIN))
    {
        while (FALSE !== ($line = fgets(STDIN)))
        {
            $customLogArr[]=$line;
        }
    }
    

    对于 STDIN,如果什么都无法读取,ftell() 将返回 false。

    【讨论】:

    • 上次我检查 STDIN 位置时从 STDIN 读取时从未归零,它始终是非负整数,因此 ftell 始终返回 integer
    • @DeDee 是的,你是对的。所以 false 只意味着当前进程没有 STDIN。
    • 正确,直到 STDIN 关闭。
    • php7 @ version 7 PHP 7.0.22-0ubuntu0.16.04.1 (cli) ( NTS ) 似乎抱怨没有定义标准输入。 PHP Notice: Use of undefined constant STDIN - assumed 'STDIN' in - on line 3
    【解决方案2】:

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

    【讨论】:

    • 奇怪,它对你不起作用,我从我的 OOP 项目中提取了它,它按照我描述的方式工作。
    • 我重新跑了,是的,但是:fread() expects exactly 2 parameters, 1 given
    • 哦,我假设第二个是一些默认值,在我的例子中我使用1,这是一个如何检索流内容的示例。编辑:固定fread
    • @ErickRobertson 在上面的评论中我说我是从我自己的项目中提取的。这是一个 Windows Apache 项目。它确实有效。
    • 我没有 Apache。我只有 Windows。它在 Windows 上不起作用。您需要 Apache 或 Linux。
    【解决方案3】:

    看起来有些事情发生了变化,或者这些答案都不是正确的。不能简单地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
    

    【讨论】:

      【解决方案4】:

      考虑这样的脚本:

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

      【讨论】:

        【解决方案5】:

        使用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

        【讨论】:

          【解决方案6】:

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

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

          【讨论】:

          • 但是当没有一个标准输入时它会挂起。这就是 OP 试图解决的问题。
          • 正确,不幸的是,当没有标准输入时,这将不起作用。我希望。 :)
          • 问题是试图在没有ftell($resource) 的情况下首先获取内容。如果您只知道自己在做什么以及为什么这样做,则此页面上的大多数代码都可以工作。
          猜你喜欢
          • 1970-01-01
          • 2015-05-24
          • 2016-08-08
          • 1970-01-01
          • 2014-11-25
          • 2014-04-18
          • 1970-01-01
          • 2016-10-04
          • 1970-01-01
          相关资源
          最近更新 更多