我正在寻找PHP的方法来检测脚本是从shell上的手动调用(我登录并运行它)运行,还是从crontab条目运行.
我有各种用PHP编写的维护类型脚本,我已设置在我的crontab中运行.偶尔,我需要提前手动运行它们,或者如果出现故障/损坏,我需要运行它们几次.
这个问题是我也有一些外部通知设置到任务(发布到Twitter,发送电子邮件等),我不想每次手动运行脚本时发生.
我正在使用php5(如果它很重要),它是一个相当标准的Linux服务器环境.
有任何想法吗?
而不是检测脚本何时从crontab运行,它可能更容易检测您何时手动运行它.
从命令行运行脚本时,会设置许多环境变量(在$ _ENV数组中).这些将根据您的服务器设置和您的登录方式而有所不同.在我的环境中,手动运行脚本时设置以下环境变量,这些变量在从cron运行时不存在:
术语
SSH_CLIENT
SSH_TTY
SSH_CONNECTION
还有其他人.因此,例如,如果您始终使用SSH访问该框,则以下行将检测脚本是否从cron运行:
$cron = !isset($_ENV['SSH_CLIENT']);
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"; }
您可以设置一个额外的参数,或在crontab中添加一行,也许:
CRON=running
然后,您可以检查环境变量"CRON".另外,尝试检查$ SHELL变量,我不确定cron是否设置了它.
这是我用来发现脚本执行位置的方法.查看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"; }
编辑:
如果php_sapi_name()
不包括cli(可能是cli或cli_server),那么我们检查是否$_SERVER['REMOTE_ADDR']
为空.从命令行调用时,该值应为空.
我认为最通用的解决方案是在cron命令中添加一个环境变量,并在代码中查找它.它适用于每个系统.
如果cron执行的命令是,例如:
"/usr/bin/php -q /var/www/vhosts/myuser/index.php"
将其更改为
"CRON_MODE=1 /usr/bin/php -q /var/www/vhosts/myuser/index.php"
然后你可以在代码上检查它:
if (!getenv('CRON_MODE')) print "Sorry, only CRON can access this script";
正确的方法是在例如stdout文件描述符上使用posix_isatty()函数,如下所示:
if (posix_isatty(STDOUT)) /* do interactive terminal stuff here */
我不知道具体的PHP,但你可以走上进程树,直到找到init或cron.
假设PHP可以获得它自己的进程ID和运行外部命令,它应该是执行的问题ps -ef | grep pid
,其中PID是你自己的进程ID,并从中提取父进程ID(PPID).
然后对该PPID执行相同的操作,直到您将cron作为父级或init作为父级.
例如,这是我的进程树,您可以看到所有权链,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
在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
这种"走上进程树"解决方案意味着您不必担心引入一个人工参数来指示您是否在cron下运行 - 您可能忘记在交互式会话中执行此操作并填充内容.
不是我所知道的 - 可能最简单的解决方案是自己提供一个额外的参数来告诉脚本它是如何被调用的.
爬行。尝试
if (!isset($_SERVER['HTTP_USER_AGENT'])) {
代替。PHP Client Binary不发送它。仅当PHP用作模块(即apache)时,术语类型才有效,但通过CGI接口运行php时,请使用上面的示例!