【发布时间】:2009-06-01 02:26:42
【问题描述】:
我需要确定当前对 PHP 的调用是来自命令行 (CLI) 还是来自 Web 服务器(在我的例子中,是带有 mod_php 的 Apache)。
有什么推荐的方法吗?
【问题讨论】:
-
编辑并澄清了问题。
标签: php
我需要确定当前对 PHP 的调用是来自命令行 (CLI) 还是来自 Web 服务器(在我的例子中,是带有 mod_php 的 Apache)。
有什么推荐的方法吗?
【问题讨论】:
标签: php
php_sapi_name 是您要使用的函数,因为它返回接口类型的小写字符串。此外,还有 PHP 常量PHP_SAPI。
文档可以在这里找到:http://php.net/php_sapi_name
例如,要确定是否从 CLI 运行 PHP,您可以使用以下函数:
function isCommandLineInterface()
{
return (php_sapi_name() === 'cli');
}
【讨论】:
php-cgi 调用脚本,这将不起作用。反过来,它将返回cgi-fcgi String。如果您从浏览器将脚本作为网页加载,您将获得apache2handler。希望这可以帮助。我需要使用php-cgi 来引入$_GET 变量:php-cgi myscript.php arg1=one arg2=two。测试不等于apache2handler 对于apache 应该没问题。
"cli"。 $_SERVER 内部有许多不同的键可供选择,以更可靠地确定请求是否通过 HTTP 来。
这个功能我用了好几年了
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;
}
【讨论】:
php_sapi_name() 确实不是执行此检查的最佳方法,因为它依赖于检查许多可能的值。 php-cgi 二进制文件可以从命令行、shell 脚本或作为 cron 作业调用,并且(在大多数情况下)这些也应该被视为 'cli' 但php_sapi_name() 将为这些返回不同的值(注意普通版本的 PHP 不是这种情况,但您希望您的代码可以在任何地方工作,对吧?)。更不用说明年可能会有我们现在不可能知道的使用 PHP 的新方法。当我关心的只是天气时,我宁愿不去想它,我是否应该用 HTML 包装我的输出。
幸运的是,PHP 有办法专门检查这一点。只需使用不带任何参数的http_response_code(),如果从 Web 服务器类型环境运行,它将返回 TRUE,如果从 CLI 类型环境运行,它将返回 FALSE。代码如下:
$is_web=http_response_code()!==FALSE;
如果您在调用它之前不小心(?)从从 CLI(或类似 CLI 的东西)运行的脚本中设置了响应代码,这甚至会起作用。
【讨论】:
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 是一个安全的选择,但如果不是,您还需要检查其他指标。
我认为他的意思是是否正在调用 PHP CLI 或者它是来自 Web 请求的响应。最好的方法是使用php_sapi_name(),如果它正在运行一个 Web 请求,它会回显 Apache,如果它正在运行的话。
列举几个取自 php docs on php_sapi_name():
【讨论】:
这应该处理所有情况(包括php-cgi)
return (php_sapi_name() === 'cli' OR defined('STDIN'));
【讨论】:
function is_cli() {
return !http_response_code();
}
示例:
if (is_cli()) {
echo 'command line';
} else {
echo 'browser';
}
【讨论】:
http_response_code(200);...如果我现在调用http_response_code(),它将返回 200;
http_response_code();,它将始终返回 FALSE,而不管实际状态代码如何。我已经在我的回答中解释了这一点,但您也可以通过阅读“返回值”下的手册页或尝试它来发现这一点。
php -r 'http_response_code(200); echo http_response_code()."\n";' 输出 "200" 除非您可以保证某些库或无知的框架没有使用 http_response_code 设置响应代码(即使在 cli 环境中),那么这将起作用.就个人而言,我使用$isCli = \defined('STDIN') || isset($_SERVER['argv']) || \array_key_exists('REQUEST_METHOD', $_SERVER)
试试
isset($_SERVER['REQUEST_METHOD'])
如果已设置,则您在浏览器中。
或者,您可以检查是否
isset($_SERVER['argv'])
但在 Windows CLI、IDK 上可能不是这样。
【讨论】:
我用过这个:
php_sapi_name() == 'cli' || (is_numeric($_SERVER['argc']) && $_SERVER['argc'] > 0)
这是来自 Drush 代码库 environment.inc,他们在那里进行了类似的检查。
【讨论】:
register_argc_argv,那么传入任意数量的GET值都会导致argc不为0。
根据http://jp2.php.net/manual/en/features.commandline.php,有一些常量仅在从 CLI 运行时设置。这些常量是 STDIN、STDOUT 和 STDERR。测试其中一个会告诉你它是否处于 cli 模式
【讨论】:
joomla 方式
if (array_key_exists('REQUEST_METHOD', $_SERVER)) die();
【讨论】:
我建议检查 $_SERVER 数组的某些条目是否已设置。
例如:
if (isset($_SERVER['REQUEST_METHOD'])) {
print "HTTP request\n";
} else {
print "CLI invocation\n";
}
【讨论】:
php-cgi 命令行,它会将其设置为GET for:php-cgi -f file.php arg1=2
一种简单的方法是查询$argv 变量(无论如何,您可能会对命令行参数执行此操作)。即使没有参数$argv也返回一个空数组。
如果已设置,则使用 cli。然后,您可以假设所有其他调用都是通过某个 Web 服务器或其他。
例如:
if (isset($argv)) {
// Do the cli thing.
}
【讨论】:
这个问题的正确答案取决于它背后的真正意图:
如果前者给出的答案和编写的 cmets 足以找到可行的解决方案。
如果是后者,如果该工具作为 cronjob 或作为来自另一个守护程序的后台作业运行,此处给出的配方将失败 - 在这种情况下,我建议进一步测试 STDIN 是否是 TTY:
function at_tty() {
return defined("\STDIN") && posix_isatty(\STDIN);
}
【讨论】:
// Detect CLI calls
define("IS_CLI_CALL",( strcmp(php_sapi_name(),'cli') == 0 ));
if(IS_CLI_CALL){
//do you stuff here
}
【讨论】:
基于Silver Moon's answer above,我正在使用此函数返回正确的换行符:
/**
* 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>";
}
【讨论】:
如何,这么多复杂的解决方案。怎么样...
if($_SERVER['REQUEST_SCHEME']=="http" or $_SERVER['REQUEST_SCHEME']=="https"){
// must be browser :)
}
【讨论】:
官方的方式(正如许多人所说的)是将PHP_SAPI 作为常量,或将php_sapi_name() 作为函数,当您处于命令行情况时,它们都返回cli。他们是对的。
但是!...
考虑使用$_SERVER["argv"](在大多数情况下也是$argv),当您在浏览器中运行时为null,当您从命令行调用时使用数组。这种方法(或同时使用)的优点是您可以在浏览器中模拟终端运行,只需为 $argv / $_SERVER["argv"] 变量提供(假)值.当您在通常无法获得 SSH 访问权限的外部服务器(prod、staging 等)上进行测试时,这会派上用场。
最好的方法是记住你是否需要 CLI 模拟,并使用 $argv 和 PHP_SAPI 来协调这个 - 例如如果 PHP_SAPI 不是 "cli" 但 $argv 有值,您可能需要预先输出一个额外的 <pre> 标签。
【讨论】:
我的首选方法:
if (array_key_exists('SHELL', $_ENV)) {
echo "Console invocation";
}
else {
echo "HTTP invocation";
}
【讨论】:
我会尝试:
echo exec('whoami');
通常网络服务器在不同的用户名下运行,所以这应该能说明问题。
【讨论】: