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



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



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



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



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



Есть идеи?

681   20  

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();
}
getenv('TERM')

Прокладка для SO 30 char min.

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

В команде 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 перенаправлены (канал или файл)...

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

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

Крон сделал бы:

command ext_updates=1

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

command 

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

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

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

Comments

    Ничего не найдено.