检测 PHP 脚本是否正在以交互方式运行

php
2022-08-30 21:45:54

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

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

php script.phpphp script.php < input_file

这可能吗?


答案 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 上进行测试 - 里程可能会有所不同)


答案 2

posix_isatty()

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

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


推荐