Может ли PHP определить, выполняется ли он из задания cron или из командной строки?
Я ищу способ PHP, чтобы определить, был ли скрипт запущен из ручного вызова на оболочке (я вошел в систему и запустил его), или если он был запущен из записи crontab.
У меня есть различные скрипты типа обслуживания, написанные на php, которые я установил для запуска в моей crontab. Иногда, и мне нужно запустить их вручную раньше графика или, если что-то не получилось/сломалось, мне нужно запустить их пару раз.
Проблема в том, что у меня также есть некоторые внешние уведомления, установленные в задачи (публикация в twitter, отправка электронной почты и т. д.), которые я не хочу выполнять каждый раз, когда я запускаю скрипт вручную.
Я использую php5 (если это имеет значение), это довольно стандартная серверная среда linux.
Есть идеи?
20 ответов:
Вместо того, чтобы обнаруживать, когда сценарий запускается из crontab, вероятно, проще обнаружить, когда вы запускаете его вручную.
Существует множество переменных окружения (в массиве $_ENV), которые задаются при запуске скрипта из командной строки. Что это такое, зависит от настроек вашего сервера и способа входа в систему. В моей среде при запуске сценария вручную задаются следующие переменные среды, отсутствующие при запуске из cron:
- термин
- SSH_CLIENT
- SSH_TTY
- SSH_CONNECTION
Есть и другие. Так, например, если вы всегда используете SSH для доступа к окну, то следующая строка определит, выполняется ли скрипт из cron:
$cron = !isset($_ENV['SSH_CLIENT']);
Можно задать дополнительный параметр или добавить строку в crontab, например:
CRON=runningА затем вы можете проверить переменные среды на наличие "CRON". Кроме того, попробуйте проверить переменную $SHELL, я не уверен, что/what cron устанавливает ее.
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"; }
Вот что я использую, чтобы узнать, откуда выполняется сценарий. Смотрите на функцию 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";
Правильный подход заключается в использовании функции posix_isatty (), например, на файловом дескрипторе stdout, например:
if (posix_isatty(STDOUT)) /* do interactive terminal stuff here */
Я не знаю о 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 или нет - вы можете забыть сделать это в своем интерактивном сеансе и все вещи вверх.
Насколько мне известно, нет - вероятно, самое простое решение-это предоставить дополнительный параметр самому, чтобы сообщить скрипту, как он был вызван.
Я бы заглянул в
$_ENV(var_dump () it) и проверил, замечаете ли вы разницу, когда вы запускаете его против того, когда его запускает cronjob. Кроме того, я не думаю, что существует "официальный" переключатель, который расскажет вам, что произошло.
Жутко. Попробуйте
if (!isset($_SERVER['HTTP_USER_AGENT'])) {Вместо этого. PHP-клиент Binary не отправляет его. Тип термина просто работает, когда PHP используется в качестве модуля (т. е. apache), но при запуске php через интерфейс CGI, используйте пример выше!
В моей среде я обнаружил, что
TERMзадается в$_SERVER, Если выполняется из командной строки, но не задается, если выполняется через Apache в качестве веб-запроса. Я поместил это в верхней части моего сценария, который я мог бы запустить из командной строки или получить доступ через веб-браузер:if (isset($_SERVER{'TERM'})) { class::doStuffShell(); } else { class::doStuffWeb(); }
В команде cron добавьте
?source=cronв конец пути скрипта. Затем, в вашем сценарии, проверьте$_GET['source'].EDIT: извините, это скрипт оболочки, поэтому он не может использовать qs. Вы можете, я думаю, передать аргументы в виде
php script.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Сравните различия и проверьте соответствующую переменную.
posix_isatty(STDOUT) return FALSEесли выходные данные вызова cli перенаправлены (канал или файл)...
Я думаю, что было бы лучше запустить cron commmand с дополнительной опцией в командной строке, которую вы не будете запускать вручную.
Крон сделал бы:
command ext_updates=1Руководство будет делать:
commandПросто добавьте опцию в самом скрипте, чтобы параметр ext_updates имел значение по умолчанию false.
Это очень просто. Демоны Cron всегда экспортируют переменную окружения
MAILTO. Проверьте, существует ли он и имеет ли непустое значение-тогда вы бежите от cron.
Для меня это легко... Просто
count($_SERVER['argc']), и если у вас есть результат выше нуля, он будет работать на сервере. Вам просто нужно добавить к вашей$_SERVER['argv']пользовательской переменной, например"CronJob"=true;
Comments