我需要确定当前对PHP的调用是来自命令行(CLI)还是来自web服务器(在我的情况下,使用mod_php的Apache)。

有什么推荐方法吗?


当前回答

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.

幸运的是,PHP有一种方法可以检查这一点。只需使用http_response_code(),不带任何参数,如果从web服务器类型环境运行,它将返回TRUE,如果从CLI类型环境运行,则返回FALSE。代码如下:

$is_web=http_response_code()!==FALSE;

即使您在调用之前不小心(?)从从CLI(或类似CLI的东西)运行的脚本设置了响应代码,这也可以工作。

其他回答

有这么多复杂的解决方案。……怎么样?

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

我已经使用这个函数好几年了

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;
}

我喜欢的方法是:

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

一个实用的提示

官方的方式(正如许多人所说)是PHP_SAPI作为一个常量,或php_sapi_name()作为一个函数,当您在命令行情况下,它们都返回cli。他们是对的。

但是!…

考虑使用$_SERVER["argv"](在大多数情况下也是$argv),当你在浏览器中运行时它是空的,当你从命令行调用时它是一个数组。这种方法(或两者都使用)的优点是,通过给$argv / $_SERVER["argv"]变量赋一个(假的)值,可以模拟在浏览器中运行的终端。当您在通常无法获得SSH访问的外部服务器(prod、staging等)上进行测试时,这非常方便。

做到这一点的最好方法是记住你是否需要CLI模拟,并使用$argv和PHP_SAPI来协调这一点-例如,如果PHP_SAPI不是“CLI”,而$argv有一个值,你可能需要事先输出一个额外的<pre>标签。

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

例子:

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