PHP 可以检测它是从 cron 作业还是从命令行运行?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/190759/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 21:52:33  来源:igfitidea点击:

Can PHP detect if its run from a cron job or from the command line?

phpcron

提问by Uberfuzzy

I'm looking for way to PHP to detect if a script was run from a manual invocation on a shell (me logging in and running it), or if it was run from the crontab entry.

我正在寻找 PHP 的方法来检测脚本是从 shell 上的手动调用运行的(我登录并运行它),还是从 crontab 条目运行。

I have various maintenance type scripts written in php that i have set to run in my crontab. Occasionally, and I need to run them manually ahead of schedule or if something failed/broken, i need to run them a couple times.

我有各种用 php 编写的维护类型脚本,我已将它们设置为在我的 crontab 中运行。有时,我需要提前手动运行它们,或者如果出现故障/损坏,我需要运行它们几次。

The problem with this is that I also have some external notifications set into the tasks (posting to twitter, sending an email, etc) that I DONT want to happen everytime I run the script manually.

问题在于,我还在任务中设置了一些外部通知(发布到 Twitter、发送电子邮件等),我不想在每次手动运行脚本时发生这些通知。

I'm using php5 (if it matters), its a fairly standard linux server environment.

我正在使用 php5(如果重要的话),它是一个相当标准的 linux 服务器环境。

Any ideas?

有任何想法吗?

采纳答案by Paul Stone

Instead of detecting when the script is run from the crontab, it's probably easier to detect when you're running it manually.

与检测脚本何时从 crontab 运行不同,当您手动运行它时可能更容易检测。

There are a lot of environment variables (in the $_ENV array) that are set when you run a script from the command line. What these are will vary depending on your sever setup and how you log in. In my environment, the following environment variables are set when running a script manually that aren't present when running from cron:

当您从命令行运行脚本时,会设置许多环境变量(在 $_ENV 数组中)。这些将根据您的服务器设置和登录方式而有所不同。 在我的环境中,手动运行脚本时设置了以下环境变量,从 cron 运行时不存在这些环境变量:

  • TERM
  • SSH_CLIENT
  • SSH_TTY
  • SSH_CONNECTION
  • 学期
  • SSH_客户端
  • SSH_TTY
  • SSH_CONNECTION

There are others too. So for example if you always use SSH to access the box, then the following line would detect if the script is running from cron:

还有其他人。因此,例如,如果您始终使用 SSH 访问该框,那么以下行将检测脚本是否从 cron 运行:

$cron = !isset($_ENV['SSH_CLIENT']);

$cron = !isset($_ENV['SSH_CLIENT']);

回答by MingalevME

if (php_sapi_name() == 'cli') {   
   if (isset($_SERVER['TERM'])) {   
      echo "The script was run from a manual invocation on a shell";   
   } else {   
      echo "The script was run from the crontab entry";   
   }   
} else { 
   echo "The script was run from a webserver, or something else";   
}

回答by Matthew Scharley

You can setup an extra parameter, or add a line in your crontab, perhaps:

你可以设置一个额外的参数,或者在你的 crontab 中添加一行,也许:

CRON=running

And then you can check your environment variables for "CRON". Also, try checking the $SHELL variable, I'm not sure if/what cron sets it to.

然后您可以检查“CRON”的环境变量。另外,尝试检查 $SHELL 变量,我不确定是否/什么 cron 将它设置为。

回答by davethebrave

Here's what I use to discover where the script is executed from. Look at the php_sapi_name function for more information: http://www.php.net/manual/en/function.php-sapi-name.php

这是我用来发现脚本从哪里执行的内容。查看 php_sapi_name 函数以获取更多信息:http://www.php.net/manual/en/function.php-sapi-name.php

$sapi_type = php_sapi_name();
if(substr($sapi_type, 0, 3) == 'cli' || empty($_SERVER['REMOTE_ADDR'])) {
    echo "shell";
} else {
    echo "webserver";
}

EDIT:If php_sapi_name()does not include cli(could be clior cli_server) then we check if $_SERVER['REMOTE_ADDR']is empty. When called from the command line, this should be empty.

编辑:如果php_sapi_name()不包括cli(可能是clicli_server),那么我们检查是否$_SERVER['REMOTE_ADDR']为空。当从命令行调用时,它应该是空的。

回答by agi

I think that the most universal solution is to add an environment variable to the cron command, and look for it on the code. It will work on every system.

我认为最通用的解决方案是在cron命令中添加一个环境变量,并在代码中查找。它适用于每个系统。

If the command executed by the cron is, for example:

如果cron执行的命令是,例如:

"/usr/bin/php -q /var/www/vhosts/myuser/index.php"

Change it to

将其更改为

"CRON_MODE=1 /usr/bin/php -q /var/www/vhosts/myuser/index.php"

Then you can check it on the code:

然后你可以在代码上检查它:

if (!getenv('CRON_MODE'))
    print "Sorry, only CRON can access this script";

回答by Wouter Bolsterlee

The right approach is to use the posix_isatty() function on e.g. the stdout file descriptor, like so:

正确的方法是在 stdout 文件描述符上使用 posix_isatty() 函数,如下所示:

if (posix_isatty(STDOUT))
    /* do interactive terminal stuff here */

回答by paxdiablo

I don't know about PHP specifically but you could walk up the process tree until you found either init or cron.

我对 PHP 一无所知,但您可以沿着进程树向上走,直到找到 init 或 cron。

Assuming PHP can get it's own process ID and run external commands, it should be a matter of executing ps -ef | grep pidwhere pidis your own process ID and extract the parent process ID (PPID) from it.

假设PHP可以获得它自己的进程ID和运行外部命令,它应该是执行的问题ps -ef | grep pid,其中PID是你自己的进程ID,并从中提取父进程ID(PPID)。

Then do the same to that PPID until you either reach cron as a parent or init as a parent.

然后对该 PPID 执行相同的操作,直到您作为父级访问 cron 或作为父级访问 init。

For example, this is my process tree and you can see the ownership chain, 1 -> 6386 -> 6390 -> 6408.

例如,这是我的流程树,您可以看到所有权链,1 -> 6386 -> 6390 -> 6408。

UID     PID  PPID  C  STIME  TTY        TIME  CMD
root      1     0  0  16:21  ?      00:00:00  /sbin/init
allan  6386     1  0  19:04  ?      00:00:00  gnome-terminal --geom...
allan  6390  6386  0  19:04  pts/0  00:00:00  bash
allan  6408  6390  0  19:04  pts/0  00:00:00  ps -ef

The same processes run under cron would look like:

在 cron 下运行的相同进程如下所示:

UID     PID  PPID  C  STIME  TTY        TIME  CMD
root      1     0  0  16:21  ?      00:00:00  /sbin/init
root   5704     1  0  16:22  ?      00:00:00  /usr/sbin/cron
allan  6390  5704  0  19:04  pts/0  00:00:00  bash
allan  6408  6390  0  19:04  pts/0  00:00:00  ps -ef

This "walking up the process tree" solution means you don't have to worry about introducing an artificial parameter to indicate whether you're running under cron or not - you may forget to do it in your interactive session and stuff things up.

这种“走上进程树”的解决方案意味着您不必担心引入人工参数来指示您是否在 cron 下运行 - 您可能会忘记在交互式会话中执行此操作并将事情搞砸。

回答by PeterDerMeter

Creepy. Try

爬行。尝试

if (!isset($_SERVER['HTTP_USER_AGENT'])) {

instead. PHP Client Binary dont send it. Term Type just works when PHP is used as module (ie apache) but when running php through CGI interface, use the example above!

反而。PHP 客户端二进制文件不发送。Term Type 只在 PHP 用作模块(即 apache)时有效,但当通过 CGI 接口运行 php 时,请使用上面的示例!

回答by Dominic Rodger

Not that I know of - probably the simplest solution is providing an extra parameter yourself to tell the script how it was invoked.

不是我所知道的 - 可能最简单的解决方案是自己提供一个额外的参数来告诉脚本它是如何被调用的。

回答by Till

I would look into $_ENV(var_dump() it) and check if you notice a difference when you run it vs. when the cronjob runs it. Aside from that I don't think there is an "official" switch that tells you what happened.

我会查看$_ENV(var_dump() it) 并检查您在运行它时是否注意到与 cronjob 运行它时的区别。除此之外,我认为没有“官方”开关可以告诉您发生了什么。