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


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

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

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

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

Есть идеи?

 47
Author: Uberfuzzy, 2008-10-10

20 answers

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

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

  • ТЕРМИН
  • SSH_CLIENT
  • SSH_TTY
  • SSH_СОЕДИНЕНИЕ

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

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

 40
Author: Paul Stone, 2008-10-10 13:31:35

Вы можете настроить дополнительный параметр или добавить строку в свой кронтаб, например:

CRON=running

А затем вы можете проверить свои переменные среды на наличие "CRON". Кроме того, попробуйте проверить переменную $SHELL, я не уверен, что/какой cron устанавливает ее значение.

 29
Author: Matthew Scharley, 2008-10-10 10:47:28
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";   
}
 28
Author: MingalevME, 2012-03-19 09:44:39

Вот что я использую, чтобы узнать, откуда выполняется скрипт. Посмотрите на функцию 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'] пустым. При вызове из командной строки это поле должно быть пустым.

 24
Author: davethebrave, 2015-05-14 13:05:11

Я думаю, что наиболее универсальным решением является добавление переменной среды в команду 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";
 15
Author: agi, 2011-10-23 19:46:09

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

if (posix_isatty(STDOUT))
    /* do interactive terminal stuff here */
 14
Author: Wouter Bolsterlee, 2010-03-11 22:15:59

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

Предполагая, что PHP может получить свой собственный идентификатор процесса и запускать внешние команды, необходимо выполнить ps -ef | grep pid, где pid - ваш собственный идентификатор процесса, и извлечь из него идентификатор родительского процесса (PPID).

Затем сделайте то же самое с этим идентификатором PPID, пока вы не достигнете cron в качестве родителя или инициализации в качестве родителя.

Например, это мое дерево процессов, и вы можете смотрите цепочку владения, 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 или нет - вы можете забыть сделать это в своем интерактивном сеансе и все остальное.

 6
Author: paxdiablo, 2008-10-10 11:10:44

Насколько я знаю, нет - вероятно, самое простое решение - предоставить дополнительный параметр самостоятельно, чтобы сообщить сценарию, как он был вызван.

 5
Author: Dominic Rodger, 2008-10-10 10:39:58

Я бы заглянул в $_ENV (var_dump()) и проверил, заметили ли вы разницу при запуске по сравнению с когда его запускает закадычный друг. Кроме того, я не думаю, что существует "официальный" переключатель, который расскажет вам, что произошло.

 4
Author: Till, 2008-10-10 10:43:53

Жутко. Попробуйте

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

Вместо этого. Двоичный файл PHP-клиента не отправляет его. Тип термина работает только тогда, когда PHP используется в качестве модуля (т. Е. apache), но при запуске php через интерфейс CGI используйте пример выше!

 4
Author: PeterDerMeter, 2011-11-14 16:43:29

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

if (isset($_SERVER{'TERM'}))
{
    class::doStuffShell();
}
else
{
    class::doStuffWeb();
}
 3
Author: Drew Stephens, 2009-05-01 22:59:03
getenv('TERM')

Заполнение для SO составляет 30 минут.

 2
Author: , 2013-08-23 20:27:13

$_SERVER['SESSIONNAME'] содержит Console, если выполняется из командной строки. Может быть, это поможет.

 1
Author: bouke, 2011-11-14 16:44:20

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

РЕДАКТИРОВАТЬ: извините, это сценарий оболочки, поэтому я не могу использовать qs. Я думаю, вы можете передать аргументы в форме php script.php arg1 arg2, а затем прочитать их с помощью $argv.

 1
Author: Adam Hopkinson, 2011-11-14 16:44:46

Другим вариантом было бы протестировать определенную переменную среды, которая устанавливается при вызове 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

Сравните различия и проверьте соответствующую переменную.

 1
Author: eosphere, 2014-03-03 15:54:02

posix_isatty(STDOUT) return FALSE если вывод вызова командной строки перенаправлен (канал или файл)...

 0
Author: Daniel, 2011-08-25 04:26:07
if(!$_SERVER['HTTP_HOST']) {
 blabla();
}
 0
Author: Jason Plank, 2011-11-14 16:43:05

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

Cron сделал бы:

command ext_updates=1

Руководство будет делать:

command 

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

 0
Author: Jason Plank, 2011-11-14 16:44:04

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

 0
Author: Gabor Garami, 2012-06-23 05:49:35

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

 -4
Author: Kurausu, 2011-11-14 16:43:49