【问题标题】:Detect if a PHP script is being run interactively or not检测 PHP 脚本是否以交互方式运行
【发布时间】:2012-07-04 20:33:00
【问题描述】:

我有一个脚本,它既可以作为网页运行,也可以通过控制台运行。

检测用于调用脚本的方法似乎很简单,但是当从控制台运行脚本时,我需要知道脚本是否以交互方式运行(用户键入命令,或从一个文件)。

php script.php 相对 php script.php < input_file

这可能吗?

【问题讨论】:

    标签: php


    【解决方案1】:

    我还需要一个比posix_isatty 更灵活的解决方案,它可以检测到:

    • 脚本是否从终端运行
    • 脚本是通过管道还是从文件接收数据
    • 输出是否被重定向到文件

    在对 libc 头文件进行一些试验和挖掘之后,我想出了一个非常简单的类,它可以完成以上所有以及更多。

    class IOMode
    {
        public $stdin;
        public $stdout;
        public $stderr;
    
        private function getMode(&$dev, $fp)
        {
            $stat = fstat($fp);
            $mode = $stat['mode'] & 0170000; // S_IFMT
    
            $dev = new StdClass;
    
            $dev->isFifo = $mode == 0010000; // S_IFIFO
            $dev->isChr  = $mode == 0020000; // S_IFCHR
            $dev->isDir  = $mode == 0040000; // S_IFDIR
            $dev->isBlk  = $mode == 0060000; // S_IFBLK
            $dev->isReg  = $mode == 0100000; // S_IFREG
            $dev->isLnk  = $mode == 0120000; // S_IFLNK
            $dev->isSock = $mode == 0140000; // S_IFSOCK
        }
    
        public function __construct()
        {
            $this->getMode($this->stdin,  STDIN);
            $this->getMode($this->stdout, STDOUT);
            $this->getMode($this->stderr, STDERR);
        }
    }
    
    $io = new IOMode;
    

    一些示例用法,展示它可以检测到的内容。

    输入:

    $ php io.php
    // Character device as input
    // $io->stdin->isChr  == true
    
    $ echo | php io.php
    // Input piped from another command
    // $io->stdin->isFifo == true
    
    $ php io.php < infile
    // Input from a regular file (name taken verbatim from C headers)
    // $io->stdin->isReg  == true
    
    $ mkdir test
    $ php io.php < test
    // Directory used as input
    // $io->stdin->isDir  == true
    

    输出:

    $ php io.php
    // $io->stdout->isChr  == true
    
    $ php io.php | cat
    // $io->stdout->isFifo == true
    
    $ php io.php > outfile
    // $io->stdout->isReg  == true
    

    错误:

    $ php io.php
    // $io->stderr->isChr  == true
    
    $ php io.php 2>&1 | cat
    // stderr redirected to stdout AND piped to another command
    // $io->stderr->isFifo == true
    
    $ php io.php 2>error
    // $io->stderr->isReg  == true
    

    我没有包含链接、套接字或块设备的示例,但它们没有理由不工作,因为它们的设备模式掩码在类中。

    (未在 Windows 上测试 - 里程可能会有所不同)

    【讨论】:

    • 非常好,+1 - 在什么情况下S_IFLNKS_IFSOCK 会返回 true?
    • @DaveRandom:我从未真正发现(或需要它们),当我从 C 标头获取掩码时,我将它们包括在内以保持完整性。它们显然是相关的链接和套接字,但是当我进行实验时,我无法触发它们。
    • 非常感谢。这正是我想要的! :)
    • @DaveRandom:它们分别用于符号链接(当专门作为链接打开时)和 UNIX 套接字。对于已设置的STD* 流,这些不应该是正确的,它们适用于“正确的”文件流。块设备(通常是某种类型的硬盘)也是如此。
    • @LukasS 这可能是debians cron系统如何执行脚本的产物?您必须检查其来源。传统上 cron 输出是作为邮件发送的,所以它可以通过管道传送到 sendmail?
    【解决方案2】:

    posix_isatty()

    if (posix_isatty(0)) {
      // STDIN is a TTY
    } else {
      // STDIN is a pipe or has no associated TTY
    }
    

    显然这只适用于 POSIX 兼容的操作系统,其中 PHP 安装了 posix 扩展。我不知道 Windoze 等价物。

    【讨论】:

      【解决方案3】:

      对于 Windows,您可以使用:

      $b = stream_isatty(STDIN);
      if ($b) {
         echo "php script.php\n";
      } else {
         echo "php script.php < input_file\n";
      }
      

      https://php.net/function.stream-isatty

      【讨论】:

        猜你喜欢
        • 2010-11-15
        • 2010-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-11
        • 2016-09-10
        相关资源
        最近更新 更多