Shameem
Shameem

Reputation: 14339

PHP - how to best determine if the current invocation is from CLI or web server?

I need to determine whether the current invocation of PHP is from the command line (CLI) or from the web server (in my case, Apache with mod_php).

Any recommended methods?

Upvotes: 231

Views: 113184

Answers (20)

Ali Hesari
Ali Hesari

Reputation: 1939

I did some research about it. The reliability is paramount, so you may consider additional checks or techniques to ensure the script's context is indeed CLI. php_sapi_name() and PHP_SAPI behave similarly across different Server API (SAPI) types, including custom SAPIs, web servers with CGI/FastCGI, PHP-CLI aliases, and PHP-FPM.

To create a function that detects whether your PHP script is running in the Command Line Interface (CLI) and returns consistent results across all web servers, you can use the $_SERVER superglobal to check if certain environment variables are set. Here's a function that accomplishes this:

function isCLI() {
    return (php_sapi_name() === 'cli' || defined('STDIN') || (empty($_SERVER['REMOTE_ADDR']) && !isset($_SERVER['HTTP_USER_AGENT']) && count($_SERVER['argv']) > 0));
}

if (isCLI()) {
    echo "Running from the command line (CLI)";
} else {
    echo "Not running from the command line (not CLI)";
}

Upvotes: 0

krowe2
krowe2

Reputation: 237

php_sapi_name() is really not the best way to perform this check because it depends on checking against many possible values. The php-cgi binary can be called from the command line, from a shell script or as a cron job and (in most cases) these should also be treated as 'cli' but php_sapi_name() will return different values for these (note that this isn't the case with the plain version of PHP but you want your code to work anywhere, right?). Not to mention that next year there may be new ways to use PHP that we can't possibly know now. I'd rather not think about it when all I care about is weather I should wrap my output in HTML or not.

Fortunately, PHP has a way to check for this specifically. Just use http_response_code() without any parameters and it'll return TRUE if ran from a web server type environment and FALSE if ran from a CLI type environment. Here is the code:

$is_web=http_response_code()!==FALSE;

This will even work if you accidentally(?) set a response code from a script running from the CLI (or something like the CLI) before you call this.

Upvotes: 43

dkellner
dkellner

Reputation: 9896

A practical hint

The official way (as told by many) is PHP_SAPI as a constant, or php_sapi_name() as a function, they both return cli when you're in a command line situation. They're right.

But!...

Consider using $_SERVER["argv"] (also $argv in most cases) which is null when you run in a browser, and an array when you've been called from command line. The advantage of this approach (or using both) is that you can simulate a terminal run in a browser, by just giving a (fake) value to the $argv / $_SERVER["argv"] variable. This comes in handy when you test on an outside server (prod, staging, etc) where you typically won't get SSH access.

The best way to do this is keeping in mind whether you may or may not need a CLI simulation, and use both $argv and PHP_SAPI to coordinate this - e.g. you may need to output an extra <pre> tag beforehand if PHP_SAPI is not "cli" but $argv has a value.

Upvotes: 0

adrianTNT
adrianTNT

Reputation: 4082

How, so many complicated solutions. How about ...

if($_SERVER['REQUEST_SCHEME']=="http" or $_SERVER['REQUEST_SCHEME']=="https"){
    // must be browser :)
}

Upvotes: 1

Prashant Pugalia
Prashant Pugalia

Reputation: 1101

I have been using this function for a few years

function is_cli()
{
    if ( defined('STDIN') )
    {
        return true;
    }

    if ( php_sapi_name() === 'cli' )
    {
        return true;
    }

    if ( array_key_exists('SHELL', $_ENV) ) {
        return true;
    }

    if ( empty($_SERVER['REMOTE_ADDR']) and !isset($_SERVER['HTTP_USER_AGENT']) and count($_SERVER['argv']) > 0) 
    {
        return true;
    } 

    if ( !array_key_exists('REQUEST_METHOD', $_SERVER) )
    {
        return true;
    }

    return false;
}

Upvotes: 53

user594138
user594138

Reputation:

The correct answer to this question depends on the real intent behind it:

  • Is the SAPI the deciding factor (web-context or not)?
  • Or is the information interpreted as 'running in a tty'?

If the former the answers given and comments written are enough to find a solution that works.

If the latter, the recipes given here will fail if the tool is run as cronjob, or as background-job from another daemon -- in that case I suggest to further test if STDIN is a TTY:

function at_tty() {
    return defined("\STDIN") && posix_isatty(\STDIN);
}

Upvotes: 1

a20
a20

Reputation: 5641

Based off Silver Moon's answer above, I'm using this function for returning correct linebreaks:

/**
* Linebreak function
* @return "/n" if cli, else return <br>
*/
protected static function lb(){

    return (defined('STDIN') || php_sapi_name() === 'cli' || isset($_ENV['SHELL']) ||
    (empty($_SERVER['REMOTE_ADDR']) && !isset($_SERVER['HTTP_USER_AGENT']) && count($_SERVER['argv']) > 0) ||
    !isset($_SERVER['REQUEST_METHOD'])) ? "\n" : "<br>";

}

Upvotes: 0

Terry Lin
Terry Lin

Reputation: 2599

function is_cli() {
    return !http_response_code();
}

example:

if (is_cli()) {
    echo 'command line';
} else {
    echo 'browser';
}

Upvotes: 8

lucsan
lucsan

Reputation: 850

An easy way is to interrogate the $argv variable, (Which you will probably do for command line parameters anyway). Even if there are no parameters $argv returns an empty array.

If it is set, then cli was used. You may then assume all other invocations are via some web server or other.

eg:

if (isset($argv)) {
  // Do the cli thing.
}

Upvotes: 1

Marc Towler
Marc Towler

Reputation: 705

I think he means if PHP CLI is being invoked or if it is a response from a web request. The best way would be to use php_sapi_name() which if it was running a web request would echo Apache if that is what it was running.

To list of a few taken from the php docs on php_sapi_name():

  • aolserver
  • apache
  • apache2filter
  • apache2handler
  • caudium
  • cgi (until PHP 5.3)
  • cgi-fcgi
  • cli
  • cli-server (Built-in web server as of PHP 5.4)
  • continuity
  • embed
  • fpm-fcgi
  • isapi
  • litespeed
  • milter
  • nsapi
  • phttpd
  • pi3web
  • roxen
  • thttpd
  • tux
  • webjames

Upvotes: 25

Sander
Sander

Reputation: 1

joomla way

if (array_key_exists('REQUEST_METHOD', $_SERVER)) die();

Upvotes: 2

rbawaskar
rbawaskar

Reputation: 1045

This should handle all the cases (including php-cgi)

return (php_sapi_name() === 'cli' OR defined('STDIN'));

Upvotes: 13

Hắc Huyền Minh
Hắc Huyền Minh

Reputation: 1035

// Detect CLI calls
define("IS_CLI_CALL",( strcmp(php_sapi_name(),'cli') == 0 ));

if(IS_CLI_CALL){
   //do you stuff here

}

Upvotes: 0

Ranjan
Ranjan

Reputation: 448

I used this:

php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)

This is from Drush codebase, environment.inc where they have similar check to make.

Upvotes: 3

Jordan S. Jones
Jordan S. Jones

Reputation: 13883

php_sapi_name is the function you will want to use as it returns a lowercase string of the interface type. In addition, there is the PHP constant PHP_SAPI.

Documentation can be found here: http://php.net/php_sapi_name

For example, to determine if PHP is being run from the CLI, you could use this function:

function isCommandLineInterface()
{
    return (php_sapi_name() === 'cli');
}

Upvotes: 365

Travis Beale
Travis Beale

Reputation: 5644

My preferred method:

if (array_key_exists('SHELL', $_ENV)) {
  echo "Console invocation";
}
else {
  echo "HTTP invocation";
}

Upvotes: -1

Jonathan Fingland
Jonathan Fingland

Reputation: 57157

According to https://www.php.net/manual/en/features.commandline.php There are a number of constants set only when running from the CLI. These constants are STDIN, STDOUT and STDERR. Testing for one of those will tell you if it is in cli mode

Upvotes: 2

rodion
rodion

Reputation: 6115

I would suggest to check if some of the entries of the $_SERVER array are set.

E.g.:

if (isset($_SERVER['REQUEST_METHOD'])) {
        print "HTTP request\n";
} else {
        print "CLI invocation\n";
}

Upvotes: 2

gnud
gnud

Reputation: 78528

Try

isset($_SERVER['REQUEST_METHOD'])

if it's set, you're in a browser.

Alternatlely, you could check if

isset($_SERVER['argv'])

but that might not be true on windows CLI, IDK.

Upvotes: 8

Stefan Mai
Stefan Mai

Reputation: 23929

I'd try:

echo exec('whoami');

Usually webservers are run under a different username, so that should be telling.

Upvotes: -21

Related Questions