Я ищу путь к PHP, чтобы определить, был ли запущен script из ручного вызова в оболочке (я вхожу в систему и запускаю его), или если он был запущен из записи crontab.
У меня есть различные сценарии типа обслуживания, написанные на php, которые я установил для запуска в моем crontab. Иногда, и мне нужно запускать их вручную досрочно или если что-то не получилось/сломано, мне нужно запустить их пару раз.
Проблема заключается в том, что у меня также есть некоторые внешние уведомления, заданные в задачах (отправка в твиттер, отправка электронной почты и т.д.), которые я НЕ хочу делать каждый раз, когда я запускаю script вручную.
Я использую php5 (если это имеет значение), его довольно стандартная среда сервера linux.
Любые идеи?
Вместо обнаружения, когда script запускается из crontab, его, вероятно, легче обнаружить, когда вы запускаете его вручную.
Существует множество переменных среды (в массиве $_ENV), которые устанавливаются при запуске script из командной строки. Что это будет зависеть от настройки вашего сервера и того, как вы входите в систему. В моей среде следующие переменные среды устанавливаются при запуске script вручную, которые отсутствуют при запуске из cron:
Есть и другие. Так, например, если вы всегда используете SSH для доступа к этому полю, тогда следующая строка будет определять, выполняется ли script из cron:
$cron = !isset($_ENV['SSH_CLIENT']);
Вы можете настроить дополнительный параметр или добавить строку в свой crontab, возможно:
CRON=running
И затем вы можете проверить переменные среды для "CRON". Кроме того, попробуйте проверить переменную $SHELL, я не уверен, что /cron устанавливает ее.
Здесь я использую, чтобы узнать, где выполняется script. Посмотрите на функцию 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:
Если php_sapi_name()
не включает cli (может быть cli или cli_server), тогда мы проверяем, является ли $_SERVER['REMOTE_ADDR']
пустым. При вызове из командной строки это должно быть пустым.
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";
}
define( 'PHP_SAPI', ( php_sapi_name() == 'cli' ) ? ( isset( $_SERVER['TERM'] ) ? 1 : 2 ) : 0 );
Правильный подход заключается в использовании функции posix_isatty(), например. дескриптор файла stdout, например:
if (posix_isatty(STDOUT))
/* do interactive terminal stuff here */
PHP Warning: posix_isatty(): cannot seek on a pipe in /root/test.php on line 3
, поэтому Я использовал @
перед звонком, чтобы заставить замолчать предупреждение. Также обратите внимание, что этот метод будет обнаруживать вызовы в командной строке, которые передаются на что-то еще, как «не tty» - что в основном то, что я хотел, но YMMV.
Я думаю, что наиболее универсальным решением является добавление переменной среды в команду 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";
Я не знаю о PHP специально, но вы можете подойти к дереву процессов, пока не найдете либо init, либо cron.
Предполагая, что PHP может получить свой собственный идентификатор процесса и запустить внешние команды, необходимо выполнить ps -ef | grep pid
, где pid - ваш собственный идентификатор процесса и извлечение идентификатора родительского процесса (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 или нет - вы можете забыть сделать это в своем интерактивном сеансе и в других вещах вверх.
Не то, что я знаю - возможно, самым простым решением является предоставление дополнительного параметра самому, чтобы сообщить script, как он был вызван.
Я бы посмотрел на $_ENV
(var_dump() it) и посмотрел, заметили ли вы разницу, когда вы запускаете его, и когда запускается cronjob. Помимо этого, я не думаю, что есть "официальный" переключатель, который сообщает вам, что произошло.
Жуткие. Попробуйте
if (!isset($_SERVER['HTTP_USER_AGENT'])) {
вместо этого. PHP Client Binary не отправляет его. Тип Term работает только тогда, когда PHP используется как модуль (например, apache), но при запуске php через интерфейс CGI используйте пример выше!
В моей среде я обнаружил, что TERM
был установлен в $_SERVER
, если он запущен из командной строки, но не установлен, если выполняется через Apache в качестве веб-запроса. Я поставил это в верхней части моего script, который я мог бы запустить из командной строки, или может получить доступ через веб-браузер:
if (isset($_SERVER{'TERM'}))
{
class::doStuffShell();
}
else
{
class::doStuffWeb();
}
getenv('TERM')
Заполнение для SO 30 char мин.
В команде cron добавьте ?source=cron
в конец пути script. Затем в script выберите $_GET['source']
.
EDIT: извините, это оболочка script, поэтому не может использовать qs. Вы можете, я думаю, передать аргументы в форме PHP скрипт.php arg1 arg2
, а затем прочитать их с помощью $argv
.
Другой вариант - проверить определенную переменную среды, которая устанавливается, когда php файл вызывается через Интернет и не устанавливается, если он запускается с помощью командной строки.
На моем веб-сервере я тестирую, если переменная среды APACHE_RUN_DIR установлена следующим образом:
if (isset($_ENV["APACHE_RUN_DIR"])) {
// I'm called by a web user
}
else {
// I'm called by crontab
}
Чтобы убедиться, что он будет работать на вашем веб-сервере, вы можете поместить фиктивный php файл на свой веб-сервер с помощью этого единственного оператора:
<?php var_dump($_ENV); ?>
Затем 1) загрузите его в свой веб-браузер и 2) загрузите его из командной строки следующим образом
/usr/bin/php /var/www/yourpath/dummy.php
Сравните различия и проверьте соответствующую переменную.
$_SERVER['SESSIONNAME']
содержит Console
, если выполняется из CLI. Возможно, это помогает.
Это очень просто. Cron Daemons всегда экспортируют переменную среды MAILTO
. Проверьте, существует ли он и имеет непустое значение - тогда вы работаете из cron.
posix_isatty(STDOUT) return FALSE
, если вывод вызова cli перенаправляется (канал или файл)...
Я думаю, было бы лучше запустить cron commmand с дополнительной опцией в командной строке, которую вы не запускали вручную.
cron сделает:
command ext_updates=1
руководство будет делать:
command
Просто добавьте параметр в script, чтобы параметр ext_updates имел значение false по умолчанию.
if(!$_SERVER['HTTP_HOST']) {
blabla();
}
Это легко для меня... Просто count($_SERVER['argc'])
, и если у вас есть результат выше нуля, он будет работать на сервере. Вам просто нужно добавить в свою $_SERVER['argv']
свою настраиваемую переменную, например "CronJob"=true;