PHP-如何最好地确定当前调用是来自CLI还是Web服务器?


Answers:


308

php_sapi_name是您要使用的函数,因为它返回接口类型的小写字符串。另外,还有PHP常量PHP_SAPI

可以在这里找到文档:http : //php.net/php_sapi_name

例如,要确定是否正在从CLI运行PHP,可以使用以下函数:

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

11
更直接的方法:return php_sapi_name() == 'cli';
Savageman 2010年

11
我进行了一项研究:如果您php-cgi以此调用脚本,将无法正常工作。反过来,它将返回cgi-fcgiString。如果从浏览器将脚本加载为网页,则会得到apache2handler。希望这可以帮助。我需要使用php-cgi来引入$_GET变量:php-cgi myscript.php arg1=one arg2=two。测试不等于apache2handler应该可以apache
塞巴斯蒂安

3
关于此方法的一个小警告:从cron作业运行时,它不会返回"cli"。从内部有许多od differents键可供选择,$_SERVER以更可靠地确定请求是否通过HTTP发出。
omn​​inonsense 2016年

2
我用PHP 7.2.7测试了@omninonsense,它返回cli。
Jose Nobile '18

38

我已经使用此功能几年了

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

10
array_key_exists('REQUEST_METHOD', $_SERVER) return true;WAT?
biziclop '16

@biziclop,检查array_key_exists('REQUEST_METHOD', $_SERVER)是否正确,以帮助检测请求来源。在CLI中$_SERVERSuper Global数组将“ 具有键” REQUEST_METHOD,只有在通过Web发出请求时,它才存在,因此,在检查该请求时,作者绝对是目标。
Julio Marchi

1
@JulioMarchi:但不应该是return false;或做if ( ! array_key_exists(…)) return true;
biziclop

2
@biziclop,您完全正确!!!!我怎么会错过如此巨大的小细节???对我感到羞耻... :)。当然,如果钥匙'REQUEST_METHOD'不是找到,则函数应该返回FALSE指示“CLI”。我很抱歉没有注意函数本身的范围...作者应该修复它,因为函数实际上起作用了!
Julio Marchi

在我的情况下,此函数有效,而不是php_sapi_name(),因为我需要区分Web请求和cronjob执行,并且在两种情况下php_sapi_name()的结果均为“ php-cgi”。
luis.ap.uyen

35

php_sapi_name()确实不是执行此检查的最佳方法,因为它取决于检查许多可能的值。可以从命令行,shell脚本或cron作业中调用php-cgi二进制文件,并且(在大多数情况下)这些也应被视为“ cli”,但它们php_sapi_name()将返回不同的值(请注意,这是“普通版本的PHP就是这种情况,但是您希望代码可以在任何地方工作,对吗?)。更不用说明年可能会有我们现在可能不知道的使用PHP的新方法。当我只关心天气时,我宁愿不考虑它,而应该将输出包装为HTML。

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

$is_web=http_response_code()!==FALSE;

如果您在调用此函数之前意外地(?)设置了从CLI(或类似CLI)运行的脚本的响应代码,这甚至可以工作。


4
我回答时这个问题已经很老了。投票表决该答案可能比发布另一个重复的答案更为有用,除非没有说明。
krowe2

关于“这甚至可以有效,如果您在调用此命令之前意外地(?)设置了从CLI([...])运行的脚本中的响应代码。”:(至少)从PHP 7.4.3开始,这是不对。http_response_code()从CLI运行时设置代码/返回设置代码。已通过验证<?php function t() { echo var_export(http_response_code(), true) . ' -> ' . (http_response_code() !== false ? 'web' : 'cli') . "\n"; } t(); http_response_code(200); t(); http_response_code(false); t();。因此,如果http_response_code()===false确定采用CLI,那是安全的选择,但是如果没有,您还需要检查其他指标。
塞巴斯蒂安·B。

23

我认为他的意思是正在调用PHP CLI还是来自Web请求的响应。最好的方法是使用php_sapi_name()一个正在运行的请求,如果它正在运行一个Web请求,它将回显Apache。

列出以下摘自php 文档的php_sapi_name()列表:

  • 辅助服务器
  • 阿帕奇
  • apache2filter
  • apache2handler
  • au
  • cgi(直到PHP 5.3)
  • cgi-fcgi
  • cli
  • cli-server(自PHP 5.4起的内置Web服务器
  • 连续性
  • 嵌入
  • fpm-fcgi
  • 伊萨皮
  • 精速
  • 米尔特
  • 纳斯皮
  • phttpd
  • pi3web
  • 罗克森
  • thttpd
  • 晚礼服
  • 网络詹姆斯

13

这应该处理所有情况(包括php-cgi)

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

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

例:

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

2
在手册中,“如果未提供response_code且未在Web服务器环境中调用(例如,从CLI应用程序中,则将返回FALSE。如果提供response_code而未在Web服务器中调用它,则将返回TRUE。环境(但仅当未设置先前的响应状态时)”。您的逻辑倒退了。
krowe2

1
+1。惊人。经过多年的无成果研究……我特此授予您PHPics诺贝尔奖,与@ krowe2分享,感谢他为使之真正发挥作用做出了宝贵贡献。恭喜你!
Sz。

可能已经设置了响应代码 http_response_code(200);……如果我现在调用http_response_code()它,它将返回200;
布拉德·肯特

@BradKent仅当您从Web环境中调用此方法时,并且在这种情况下,只要您未将状态代码设置为零(无论如何都是无效的HTTP状态代码),此检查仍将起作用。我的版本即使在那种情况下也可以使用,因为它专门针对FALSE进行了检查。如果http_response_code();从CLI环境中调用,则无论实际状态代码如何,它将始终返回FALSE。我已经在回答中对此进行了解释,但是您也可以通过阅读“返回值”下的手册页或尝试一下来找到答案。
krowe2

@ krowe2 php -r 'http_response_code(200); echo http_response_code()."\n";' 输出“ 200”,除非您可以保证某些库或无知框架未设置响应代码http_response_code(即使在cli env中),也可以使用。我个人使用$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
Brad Kent

4

我用这个:

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

这是从Drush代码库environment.inc中获得的,他们需要进行类似的检查。


4
如果register_argc_argv被设置,则传入GET值的任何量将导致argc不为0。

3

尝试

isset($_SERVER['REQUEST_METHOD'])

如果已设置,则说明您在浏览器中。

另外,您可以检查是否

isset($_SERVER['argv'])

但是在Windows CLI,IDK上可能并非如此。


1
尽管这不是“正确”的答案,但它可能更可靠
短讯


2

joomla方式

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

0

我建议检查是否$ _SERVER的某些条目已设置数组的。

例如:

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

这不适用于php-cgi命令行,它将设置GET为:php-cgi -f file.php arg1=2
Sebastian

0

我的首选方法:

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

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

if(IS_CLI_CALL){
   //do you stuff here

}

0

一种简单的方法是查询$argv变量(无论如何,您可能仍会使用命令行参数)。即使没有参数$argv返回一个空数组。

如果设置,则使用cli。然后,您可以假定所有其他调用都是通过某个Web服务器或其他服务器进行的。

例如:

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

0

基于上述Silver Moon的答案,我正在使用此函数返回正确的换行符:

/**
* 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>";

}

0

该问题的正确答案取决于其背后的真实意图:

  • SAPI是决定因素(是否是网络环境)?
  • 还是信息被解释为“在tty中运行”?

如果前者给出的答案和书面评论足以找到可行的解决方案。

如果是后者,则该工具作为cronjob或另一个守护程序的后台作业运行时,此处给出的配方将失败–在这种情况下,我建议进一步测试是否STDIN为TTY:

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

-1

如何,那么多复杂的解决方案。怎么样 ...

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

-17

我会尝试:

echo exec('whoami');

通常,Web服务器在不同的用户名下运行,这应该可以说明。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.