Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect if a PHP script is being run interactively or not

Tags:

php

I have a script that is designed to be run both as a web page, and via the console.

Detecting which method was used to invoke the script seems pretty straight forward, but when the script is being run from the console, I need to know if the script is being run interactively or not (user typing commands, or input redirected from a file).

php script.php versus php script.php < input_file

Is this possible?

like image 563
Fania Avatar asked Jul 04 '12 10:07

Fania


3 Answers

I also needed a slightly more flexible solution than posix_isatty that could detect:

  • Is the script being run from the terminal
  • Is the script receiving data via a pipe or from a file
  • Is the output being redirected to a file

After a bit of experimenting and digging around through libc headers, I came up with a very simple class that can do all of the above and more.

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;

Some example usage, to show what it can detect.

Input:

$ 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

Output:

$ php io.php
// $io->stdout->isChr  == true

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

$ php io.php > outfile
// $io->stdout->isReg  == true

Error:

$ 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

I've not included examples for links, sockets, or block devices, but there's no reason they shouldn't work, as the device mode masks for them are in the class.

(Not tested on Windows - mileage may vary)

like image 190
Leigh Avatar answered Oct 08 '22 05:10

Leigh


posix_isatty()

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

Obviously this only works on POSIX compliant operating systems, where PHP has the posix extension installed. I am not aware of a Windoze equivalent.

like image 29
DaveRandom Avatar answered Oct 08 '22 05:10

DaveRandom


For Windows, you can use this:

$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

like image 3
Zombo Avatar answered Oct 08 '22 04:10

Zombo