Запуск php по расписания windows

Запуск PHP скрипта по расписанию cron. Когда не всё так ясно

В этой статье я расскажу о некоторых тонкостях запуска php-скриптов на хостингах, незнание которых может попортить немало нервов и начинающим программистам, и мастерам средней руки.
Причина написания статьи: проблемы с запуском скриптов на хостингах с разными настройками. А поскольку настройки могут быть разными, информация приводимая для общих случаев могут не подходить и приводить в заблуждения.

Немного теории по этим ссылкам: тут и тут, для тех хочет освежить память.

Случай первый


В настройках операционной системы не указаны пути по умолчанию. Как следствие следующая команда в cron не будет выполнена.

Правильной командой будет второй вариант, где мы пропишем полный путь до интерпретатора php.

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

В команде для выполнения в cron прописывается путь к скрипту и только. В скрипте ставятся символы #!, а дальше просто пишем нужные нам команды на языке bash.

Случай второй


Выполнение скрипта при запросе из браузера приводит к выводу страницы в браузер. А при выполнении скрипта через cron приводит к выводу текста страницы в командную строку. Тут может быть несколько вариантов. Система может быть настроена на сохранение результатов вывода в консоль в виде файла. Причем файл этот может размешаться не в самом типичном месте. Постепенно это может забить всё пространство на диске. Часто под сайт дают место в 1 Гигабайт, 500 мегабайт. И даже встречались хостинги с 50 и 10 мегабайт под сайт.

Как вариант, вывод может быть перенаправлен на почтовый ящик, который заботливый хостер ненавязчиво подарил вам и прописал в настройках хостинга как email по умолчанию. При каждом выполнении скрипта весь текст, выводящийся в консоль, будет оформлен в письмо. Проблемы могут начаться неожиданно. Если задание cron выполняется часто, а у почты хостинга прописано ограничение на количество писем в день, почта просто ляжет (заблокируется провайдером как потенциальный спамер). И как неприятные последствия вы получите отказ в регистрации пользователей, уведомление пользователей и д.р., что подвязано на почту.

Решение старо как мир. Нужно сделать перенаправление вывода из консоли в пустоту. Делается это добавлением команды в конце команды крона.

Иногда админы хостинга берут на себя обязанность ненавязчиво поставить их за пользователя. Тут тоже может быть подводный камень.

Случай третий


Ситуация проста. Нужно отладить скрипт, запускаемый планировщиком. Можно попытаться сделать это средствами php, заставлять скрипт писать логии и т.п. Но есть способ куда проще, нужно перенаправить вывод в файл. Команда проста, дополнительный параметр к нашей команде:

Её надо добавить в конце команды:

Знак «>» указывает системе о перенаправлении вывода. Далее имя файла. В нашем случае указан абсолютный путь. Этот пример не составляет труда найти в интернете. Но тут нас может поджидать неприятность, вытекающая из второго случая. Заботливый хостер автоматически добавляет перенаправление вывода в конце нашей строки. И иногда маскирует это. В итоге получается команда вида:

Читайте также:  Emu 0204 windows drivers

В итоге вывод снова перенаправлен в пустоту и выходной файл будет пуст. Тут хостеру можно указать на его ошибку, что он уж слишком перехитрил с настройками. А можно сразу воспользоваться костылём. После команды перенаправления в файл закончить команду символами &&. Эти два символа используются в командной строке для объединения нескольких команд в одной строке. Они дают командной строке понять, что команда окончена и дальше идет следующая команда. К ней и применяется перенаправление в пустоту. В итоге и перенаправление в пустоту осталось и лог файл записан верно. Пример команды:

Случай четвёртый


Скрипт запустился, но работает не верно. Причиной тому — интерпретатор php при запуске из командной строки начинает работать в неправильно настроенном окружении, отличным от того, которое было бы при запуске через HTTP-сервер. Первый признак – скрипт не находит файлы, которые лежат с ним в одной директории, а начинает считать себя расположенным в корневой директории пользователя, которая на несколько папок выше чем корень сайта. Первое, что нужно проверить – переменное окружение и супер глобальный массив $_SERVER.

Первое, что находишь в интернете по этой проблеме – совет прописать в кроне команду смены директории:

Но в каких-то случаях это не помогает. Выход есть. Один из них взять всё в свои руки и задать недостающее окружение для работы скрипта. Информации про это в интернете уже больше.

Иногда просто хватает вписать следующий код в начале скрипта и пути снова становятся рабочими.

Как видите, всё прописано функциями и утруждаться настройками не надо.

Запуск php по расписания windows

Вопрос

Есть довольно много готовых PHP скриптов, которые раньше запускались по расписанию на Linux сервере через Crontab. Необходимо организовать их запуск на сервере IIS.

Как я понимаю в IIS мне нужно запускать их через «Планировщик заданий». Кто может помочь, как именно это делается ?

Ответы

webman2011, все верно — именно через планировщик заданий можно зашедулить команду выполнения php скриптов под нужное расписание и с нужными правами пользователя; а запустить выполнение php скрипта из-под cmd в простейшем случае можно так

естественно, с собственными путями. Тут php-cgi, т.к. на ОС Windows рекомендуется именно режим FastCGI для интерпретатора php, и, на всякий случай, тут http://blogs.iis.net/rickjames/archive/2007/10/16/fastcgi-debugging-quot-the-fastcgi-process-exited-unexpectedly-quot.aspx неплохой мануал о том, как можно осуществлять его отладку. Для гибкости про дополнительные ключи запуска php можно прочитать на официальном сайте или посмотреть на вывод команды с ключом -h.

Мнения, высказанные здесь, являются отражением моих личных взглядов, а не позиции корпорации Microsoft. Вся информация предоставляется «как есть» без каких-либо гарантий.

  • Предложено в качестве ответа Dmitry Davydov Moderator 24 февраля 2011 г. 8:58
  • Помечено в качестве ответа webman2011 26 февраля 2011 г. 9:41

webman2011, вот тут не совсем прозрачно — Вы же хотите зашедулить по расписанию выполнение php скриптов, т.е., если я правильно понимаю, задача состоит в автоматизации. Планировщик будет запускать процессы в фоновом режиме и это трудно стыкуется с тем, что вывод в браузер может быть полезен только в интерактивном случае. Предположу, что речь, наверное, идет о сохранении работы скрипта «для потомков». Так вывод из командной строки можно перенаправить сразу в файл, ну, например,

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

Читайте также:  Postgres mac os install

А, если уж нужен вывод именно в браузер, то попробовать можно пойти двумя путями: 1) также перенаправить вывод html в файл, а затем вызвать необходимый браузер с параметром на открытие только что сохраненной страницы или 2) вообще захостить Ваши скрипты на IIS, настроив на нем поддержку php, и просто запрашивать php по http как обычно, в желаемом браузере. Во втором случае выполнять скрипты будет уже вебсервер, хотя и используя все тот же php-cgi.

Мнения, высказанные здесь, являются отражением моих личных взглядов, а не позиции корпорации Microsoft. Вся информация предоставляется «как есть» без каких-либо гарантий.

kosenko_danila

Косенко Данила

Блог писателя и программиста

Побуду сегодня Капитаном Очевидность.

Итак, у вас есть Денвер (Джентльменский набор вэб-разработчика) и какой-либо скрипт script.php. Скрипт отлажен и нормально работает в браузере. Вы хотите запускать этот скрипт планировщиком винды. Запуск в планировщике браузера с путём к скрипту отвергается, чтобы не плодить окна.

Как все нормальные люди, вы сначала тренируетесь «на кошках».
Создаётся bat-файл с содержимым
C:\WebServers\usr\bin\php5.exe test.php
где в файле скрипта test.php одна строка

Запускаете его. Вас заваливает диалоговыми окнами с кнопкой ОК с жалобами, что не найдены пути к куче модулей.
И верно. В файле C:\Webservers\usr\local\php5\php.ini указаны относительные пути к расширениям PHP.

Идём в указанный файл. Коментируем строку
extension_dir = «/usr/local/php5/ext»
ставим в начале этой строки точку с зяпятой
;extension_dir = «/usr/local/php5/ext»

Ниже неё вставляем строку
extension_dir = «C:\Webservers\usr\local\php5\ext\»

Вновь запускаем bat-файл. Среди выведенного словестного мусора можно успеть разглядеть строку test. Окошко мелькает на экране на секунду и закрывается. Да, вы забыли вставить второй строчкой в bat-файле
pause
Именно она выводит строку «Для продолжения нажмите любую клавишу . . .».

Итак, мы видим в командной строке винды наш «test».

Кладём bat-файл рядом с «настоящим» файлом script.php, запускаем.

Очередной сюрприз. Ваш скрипт работает с файлами в соседней папке, однако не может найти эту папку. Ведь вы по привычке указали $_SERVER[‘DOCUMENT_ROOT’] как путь к текущей папке.
Однако, для консольного РНР не существует массива $_SERVER и переменной $_SERVER[‘DOCUMENT_ROOT’]. Правда, странно? 🙂 Поэтому отлаженный на сервере PHP-файл вместо на месте указанной переменной вставит не путь к текущему каталогу, а пустую строку. Юзайте относительные пути типа «../» и «./».
Пути поправили, добавляем задание в планировщик. Для проверки нажимаем «Выполнить» задание.
Выводятся ошибки, что не найден файл script.php. Почему? Он же лежит рядом с bat-файлом!
Всё дело в том, что в bat-файле мы может просто написать путь к интерпретатору C:\WebServers\usr\bin\php5.exe и имя скрипта script.php, который находится рядом с bat-файлом.
То есть
C:\WebServers\usr\bin\php5.exe script.php
В планировщике винды надо ставить полный абсолютный путь к выполняемому скрипту, как и в любом уважающем себя cron’е.
То есть, меняем строку на
C:\WebServers\usr\bin\php5.exe C:\WebServers\home\site.loc\www\script.p hp
Кто бы мог подумать! 🙂

Вам ещё не надоело? А может, нафиг это консольный РНР? 🙂 Столько очевидных вещей надо помнить! Не волнуйтесь, остался последний подводный камень.
Вы запускаете задание вновь.
Скрипт отрабатывает, но до кульминации дело не доходит. Из-за лимита на время выполнения скрипта. Вашему скрипту мало 30 секунд, которые выделяет сервер.
В начале скрипта script.php пишем
set_time_limit(0);

Вот теперь всё. Только не забудьте убрать
pause
из bat-файла. 🙂

Читайте также:  Снятие дампов процесса windows

Простой планировщик задач на PHP

В процессе эволюции более-менее крупного проекта может настать ситуация, когда количество запланированных задач (cron jobs) становится настолько большим, что поддержка их становится ночным кошмаром devops’ов. Для решения этой проблемы мне пришла в голову идея создать реализацию планировщика на PHP, тем самым сделав его частью проекта, а сами задачи — частью его конфигурации. В этом случае необходимое и достаточное количество cron jobs будет равно единице.

Некоторое время назад мне довелось разрабатывать модуль для планирования событий. Некое упрощенное подобие Google/Apple Calendar для пользователей приложения. Для хранения дат и правил повторения событий было решено использовать формат iCalendar (RFC 5545), позволяющий одной строкой описать график повторения какого-либо события с учетом дней недели, месяцев, количества повторений и многого другого. Несколько примеров:

FREQ=WEEKLY;BYDAY=SU,WE — Еженедельно в субботу и среду
FREQ=MONTHLY;COUNT=5 — Каждый месяц, пять раз
FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU — Каждый второй год в каждую субботу января

Как видите данный стандарт позволяет описать правила повторения события гораздо более гибко, чем предлагает cron.

Для работы с форматом iCalendar была найдена замечательная библиотека (не пожалейте звезду):
https://github.com/simshaun/recurr

Имея инструмент для работы с RRULE (Recurrence Rule) дело осталось за малым. Написать несколько классов, позволяющих планировать и запускать задачи (являющиеся каким угодно проявлением PHP callable типа).

Установка библиотеки:

composer require hutnikau/job-scheduler

Планирование и запуск задач:

\Scheduler\Job\Job — Класс, представляющий задачу

Для создания его экземпляра потребуется правило его повторения (RRULE) и экземпляр типа callable :

Альтернативный вариант — использовать \Scheduler\Job\Job::createFromString() :

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

Добавляем задачу в планировщик:

Так же можно передать массив задач в конструктор:

Запускаем запланированные задачи:

В данном примере будут выполнены все задачи, запланированные на указанный промежуток времени (10 минут). Таким образом вам потребуется всего один cron job, запускающий JobRunner .

Можно опустить параметр $to , таким образом будут выполнены все задачи, начиная от $from до текущего момента.

Последний параметр определяет, будут ли выполнены задачи, время выполнения которых попало точно на пограничные значения (‘2017-12-12 20:00:00’ и ‘2017-12-12 20:10:00’ из примера выше).

При запуске планировщика при помощи cron я советую сохранять время последнего запуска, и при следующем запуске передавать его в параметр $from прибавив одну секунду, так как точность cron’а не идеальна, и существует вероятность пропустить какие-либо задачи или выполнить их дважды.

$jobRunner->run(. ) возвращает массив результатов выполненных задач (массив объектов типа \Scheduler\Action\Report ).

Вызвав \Scheduler\Action\Report::getReport() можно получить результат выполнения callable (возвращенное им значение).

В случае, если при выполнении задачи было брошено исключение, \Scheduler\Action\Report::getReport() вернет то самое исключение.

Метод \Scheduler\Action\Report::getAction() вернет экземпляр типа \Scheduler\Action\ActionInterface , который описывает выполненное действие. Используя его можно узнать время выполнения действия или получить само действие (Job).

Так же стоит обратить внимание, что если запланированная задача должна была выполниться более одного раза (например если в RRULE был использован интервал MINUTELY , и разница между $from и $to , переданным в JobRunner 10 минут), то действие будет выполнено несколько раз. Другими словами они не будут сгруппированы.

Вот, пожалуй, и все. Библиотека действительно мала, но надеюсь окажется кому-либо полезной.
Конструктивная критика и помощь в развитии приветствуются.

Оцените статью