У меня есть сценарий, который предназначен для запуска как веб-страницы, так и через консоль.
Обнаружение того, какой метод использовался для вызова скрипта, выглядит довольно прямолинейно, но когда скрипт запускается с консоли, мне нужно знать, запускается ли сценарий в интерактивном режиме или нет (команды ввода пользователем или ввод, перенаправленный из файла) ,
php script.php
и php script.php < input_file
Это возможно?
Мне также понадобилось немного более гибкое решение, чем 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 – пробег может отличаться)
posix_isatty()
if (posix_isatty(0)) { // STDIN is a TTY } else { // STDIN is a pipe or has no associated TTY }
Очевидно, что это работает только на совместимых с POSIX операционных системах, где PHP имеет posix
расширение posix
. Я не знаю эквивалента Windoze.