Может ли PHP определить, выполняется ли его запуск из задания cron или из командной строки?

Я ищу путь к PHP, чтобы определить, был ли сценарий запущен из ручного вызова в оболочке (я вхожу в систему и запускаю его), или если он был запущен из записи crontab.

У меня есть различные сценарии типа обслуживания, написанные на php, которые я установил для запуска в моем crontab. Иногда, и мне нужно запустить их вручную досрочно или если что-то не получилось / сломано, мне нужно запустить их пару раз.

Проблема заключается в том, что у меня также есть некоторые внешние уведомления, заданные в задачах (отправка сообщений в твиттер, отправка электронной почты и т. Д.), Которые я НЕ хочу делать каждый раз, когда запускаю скрипт вручную.

Я использую php5 (если это имеет значение), это довольно стандартная среда сервера linux.

Есть идеи?

Вместо того, чтобы обнаруживать, когда скрипт запускается из crontab, его, вероятно, легче обнаружить, когда вы запускаете его вручную.

Существует множество переменных среды (в массиве $ _ENV), которые задаются при запуске скрипта из командной строки. То, что это будет, будет зависеть от настройки вашего сервера и того, как вы входите в систему. В моей среде следующие переменные среды устанавливаются при запуске скрипта вручную, которого нет при запуске из cron:

  • СРОК
  • SSH_CLIENT
  • SSH_TTY
  • SSH_CONNECTION

Есть и другие. Например, если вы всегда используете SSH для доступа к этому полю, тогда следующая строка будет определять, работает ли скрипт cron:

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

Вы можете настроить дополнительный параметр или добавить строку в свой 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"; } 

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"; } 

Правильный подход состоит в том, чтобы использовать функцию posix_isatty (), например, дескриптор файла stdout, например:

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

Я считаю, что наиболее универсальным решением является добавление переменной окружения в команду 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 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. Кроме того, я не думаю, что есть «официальный» переключатель, который рассказывает вам, что произошло.

В моей среде я обнаружил, что TERM был установлен в $_SERVER если он запущен из командной строки, но не установлен, если он выполняется через Apache в качестве веб-запроса. Я поставил это в верхней части моего сценария, который я мог бы запустить из командной строки или получить доступ через веб-браузер:

 if (isset($_SERVER{'TERM'})) { class::doStuffShell(); } else { class::doStuffWeb(); } 

Жутко. Пытаться

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

вместо. PHP Client Binary не отправляет его. Term Type работает только тогда, когда PHP используется как модуль (т.е. apache), но при запуске php через интерфейс CGI используйте пример выше!

В команде cron добавьте ?source=cron в конец пути к скрипту. Затем в вашем скрипте проверьте $_GET['source'] .

EDIT: извините, это сценарий оболочки, поэтому нельзя использовать qs. Вы можете, я думаю, передать аргументы в форме php script.php arg1 arg2 а затем прочитать их с помощью $argv .

 getenv('TERM') 

Заполнение для SO 30 мин. Мин.

$_SERVER['SESSIONNAME'] содержит Console если она запущена из CLI. Может быть, это помогает.

Другой вариант – проверить определенную переменную среды, которая устанавливается, когда 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 перенаправляется (канал или файл) …

 if(!$_SERVER['HTTP_HOST']) { blabla(); } 

Я думаю, было бы лучше запустить комманд cron с дополнительной опцией в командной строке, которую вы не запускали вручную.

cron будет делать:

 command ext_updates=1 

руководство сделало бы:

 command 

Просто добавьте параметр в самом скрипте, чтобы параметр ext_updates имел значение false по умолчанию.

Это очень легко. Cron Daemons всегда экспортируют переменную окружения MAILTO . Проверьте, существует ли он и имеет непустое значение – тогда вы работаете из cron.

Это легко для меня … Просто count($_SERVER['argc']) и если у вас есть результат выше нуля, у него закончится сервер. Вам просто нужно добавить к своей переменной $_SERVER['argv'] вашу пользовательскую переменную, например "CronJob"=true;