169

I have a PHP script that needs to determine if it's been executed via the command-line or via HTTP, primarily for output-formatting purposes. What's the canonical way of doing this? I had thought it was to inspect SERVER['argc'], but it turns out this is populated, even when using the 'Apache 2.0 Handler' server API.

Greg
  • 316,276
  • 54
  • 369
  • 333
Bobby Jack
  • 15,689
  • 15
  • 65
  • 97

5 Answers5

247

Use the php_sapi_name() function.

if (php_sapi_name() == "cli") {
    // In cli-mode
} else {
    // Not in cli-mode
}

Here are some relevant notes from the docs:

php_sapi_name — Returns the type of interface between web server and PHP

Although not exhaustive, the possible return values include aolserver, apache, apache2filter, apache2handler, caudium, cgi (until PHP 5.3), cgi-fcgi, cli, cli-server, continuity, embed, isapi, litespeed, milter, nsapi, phttpd, pi3web, roxen, thttpd, tux, and webjames.

In PHP >= 4.2.0, there is also a predefined constant, PHP_SAPI, that has the same value as php_sapi_name().

Andy Fleming
  • 7,655
  • 6
  • 33
  • 53
  • Thanks. I'm intrigued as to why the doc. example inspects the first 3 characters, whilst the description states the string should be exactly "cgi" but, other than that, I think this is perfect. – Bobby Jack Oct 06 '08 at 11:17
  • unless, of course, the returned string was 'cgi', which is also indicative of php being executed from the console. As in, whaddayaknow, my case. – Adriano Varoli Piazza Sep 28 '09 at 16:40
  • @Adriano: maybe in your case php-cgi is used to execute the script. –  Feb 23 '10 at 15:31
  • 3
    @Bobby, the example in the php.net docs actually matches both "cgi" and "cgi-fcgi" by just looking at the first three characters of the string ... that's why and it actually makes sense. If anything it's just to get back @hop for calling php no language for serious programmers :D – ChrisR Sep 30 '10 at 11:36
  • 1
    an interesting note here : http://php.net/manual/en/function.php-sapi-name.php is that depending on the actual binary called, you can run php from the command line and still get cgi-fgi – DAB Jun 24 '15 at 19:19
  • This snippet is not off-roader: when PHPis run as a CGI, the function `php_sapi_name` returns the same value in HTTP or command line (example : 'cgi-fcgi'). They are better solutions. – Skrol29 Apr 26 '18 at 10:32
  • (php_sapi_name() == "cli" || die("Command-Line only")); at the top of your script – relipse Nov 11 '19 at 22:29
23

This will always work. (If the PHP version is 4.2.0 or higher)

define('CLI', PHP_SAPI === 'cli');

Which makes it easy to use at the top of your scripts:

<?php PHP_SAPI === 'cli' or die('not allowed');
Xeoncross
  • 55,620
  • 80
  • 262
  • 364
  • 9
    Your second snippet seems like a non sequitur, I'd expect `CLI or die('not allowed');` – Madbreaks Jan 09 '13 at 04:35
  • 1
    @Madbreaks, I was stating two separate uses. I was assuming *either* one or the other - but if you use both then `CLI or die('not allowed');` is perfect. – Xeoncross Jan 09 '13 at 17:16
  • 10
    `Which makes it easy to use at the top of your scripts` doesn't really make it sound like two separate uses. Yes, I'm a necromancer. – George Dimitriadis Jun 08 '17 at 10:08
11

Here is Drupal 7 implementation: drupal_is_cli():

function drupal_is_cli() {
  return (!isset($_SERVER['SERVER_SOFTWARE']) && (php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)));
}

However Drupal 8 recommends using PHP_SAPI === 'cli'

ya.teck
  • 2,060
  • 28
  • 34
10

I think

$_SERVER['REMOTE_ADDR']

will not be populated from the CLI.

Also, all the HTTP_* keys in the $_SERVER superglobal won't be populated from the CLI, or do it the right way hop just mentioned :-)

Vinko Vrsalovic
  • 330,807
  • 53
  • 334
  • 373
5

The documentation page for php_sapi_name clearly states how it works:

Returns a lowercase string that describes the type of interface (the Server API, SAPI) that PHP is using....

Although not exhaustive, the possible return values include aolserver, apache, apache2filter, apache2handler, caudium, cgi (until PHP 5.3), cgi-fcgi, cli, continuity, embed, isapi, litespeed, milter, nsapi, phttpd, pi3web, roxen, thttpd, tux, and webjames.

I'm not sure why hop doesn't think that PHP is for serious programmers (I'm a serious programmer, and I use PHP daily), but if he wants to help clarify the documentation then perhaps he can audit all possible web servers that PHP can run on and determine the names of all possible interface types for each server. Just make sure to keep that list updated as new web servers and interfaces are added.

Also, Bobby said:

I'm intrigued as to why the doc. example inspects the first 3 characters, whilst the description states the string should be exactly "CGI"

The description for the example states:

This example checks for the substring cgi because it may also be cgi-fcgi.

Community
  • 1
  • 1
Steve
  • 91
  • 2
  • 5
  • Ah - either I was being incredibly unobservant that day, or the example has been updated since I made that comment. Wholeheartedly agree with your points about PHP, though; the bashing gets VERY tiring. – Bobby Jack Aug 09 '09 at 22:30