Запуск функции по времени php

Запуск PHP скриптов по расписанию Cron

Представлен простой пример запуска php скрипта по расписанию Cron с разными вариациями записи результатов выполнения в логи, передачей параметров и отслеживанием времени выполнения скрипта.

@set_time_limit(0); //@ignore_user_abort(true); ini_set('memory_limit', '1024M'); $path = realpath(__DIR__); //$consoleExec = 'php -c /etc/php/8.2/cli/php.ini '; $consoleExec = '/usr/bin/php '; $logPath = $path . '/runtime/'; if (!is_dir($logPath)) mkdir($logPath); try < if (php_sapi_name() === 'cli') < error_log(date('Y/m/d H:i:s') . ': Application start' . PHP_EOL, 3, $logPath . '/app.log'); // Code . $name = 'John Smith'; // Строка выполнения с параметром `name` и выводом в файл `CommandExecutionResult` $command = $consoleExec . " /var/www/html/command.php --name='$name' >CommandExecutionResult.log 2>&1 &"; exec($command); > else < throw new Exception('Скрипт запускается Не из консоли!'); >> catch (Exception $exception) < die($exception->getMessage()); >
// Отслеживаем время выполнения скрипта и размер потребляемой памяти $start = microtime(true); $memory = memory_get_usage(); // Записываем в лог $log = __DIR__ . '/runtime/log.txt'; $date = date('Y/m/d H:i:s'); echo 'Старт службы. ' . PHP_EOL; $startMessage = $date . ' Запись в лог: Служба запустилась. '; file_put_contents($log, $startMessage . PHP_EOL, FILE_APPEND); // Принимаем параметры $name = substr($argv[1], 7); for ($i = 1; $i $endMessage = $date . ' Запись в лог: Служба остановилась. '; file_put_contents($log, $endMessage . PHP_EOL, FILE_APPEND); $memory = memory_get_usage() - $memory; $name = ['байт', 'КБ', 'МБ']; $i = 0; while (floor($memory / 1024) > 0) < $i++; $memory /= 1024; >echo 'Время выполнения скрипта: ' . (microtime(true) - $start) . ' sec.' . PHP_EOL; echo 'Использовано памяти: ' . round($memory, 2) . ' ' . $name[$i] . PHP_EOL; echo 'Служба остановлена. ' . PHP_EOL;
# Запускать в 10:00 с понедельника по пятицу 0 10 * * 1-5 /usr/bin/php /var/www/html/index.php >/dev/null 2>&1

Источник

Фоновое выполнение скрипта на PHP без crontab

Озадачили меня тут написать демона на PHP. Т.е. скрипт, который будет заданное количество раз в заданное количество часов в случайное время (всегда случайное) выполнять определенные действия, и все это без использования cron’a.

Читайте также:  Reentrantlock in java example

До этого никогда не заморачивался, а тут после постановки задачи, начал было думать что так нельзя, что php скрипт надо вызывать браузером…ну задача то поставлена, надо выполнять.

Первая мысль — отключить ограничение времени выполнения скрипта. Запрещено хостером.

Вторая мысль — яваскриптом повторять аякс-запрос периодически (да хоть раз в секунду). — нельзя (требование заказчика).

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

1. Пачка сигарет, ночь, гугл, доки, книги, мануалы….
goto 1…

На выходе получаю:
Задача_1:
Реализовать генератор времен выполнения скрипта, исходя из заданных количества раз и количества часов. Хранить где-то эти времена.

Задача_2:
Работать после закрытия браузера

Задача_3:
Не вылетать после окончания ограничения времени выполнения скрипта

Задача_4:
Выполнять в нужное время какие-то действия.

Итак…
Пишем в конфиге исходные данные:

session_start(); // Старт сессии $num_starts = 120; // Количество запусков скрипта за промежуток времени $hours = 1; // Количество часов, в течение которых нужно запускать скрипт $num_starts раз. $time_sec = $hours*3600; // Количество секунд в цикле запусков $time_to_start = array(); // Собственно, массив с временами запусков ignore_user_abort(1); // Игнорировать обрыв связи с браузером 

Далее пишем функцию, которая поможет нам сгенерировать времена запуска.
В ней мы генерируем случайное число от 0 до количества секунд в исходном интервале.

 /****** * @desc Генерируем интервал между запусками. */ function add_time2start() < global $time_sec, $time_to_start; $new_time = time()+rand(0, $time_sec); if (!in_array($new_time, $time_to_start)) < // Если такого времени в массиве нет - добавим $time_to_start[] = $new_time; >else < add_time2start(); // Если такое время уже есть - генерируем заново. >>

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

$k = 1; if ($_SESSION["num_st"] == "" || $_SESSION["num_st"][$num_starts-1] < time()) < // проверка, что в сессию не записаны данные и что эти данные не устарели. do < add_time2start($k); $k++; >while ($k

Теперь надо заставить скрипт работать, не обращая внимания на максимальное время выполнения, установленное сервером.
Принцип таков:
1) Определяем время начала работы скрипта;
2) Определяем установленное ограничение на время выполнения.
3) Запускаем цикл, внутри которого считаем текущее время и вычисляем общее время работы скрипта, сверяем текущее время со значениями в массиве времен запуска, и если совпадение есть, выполняем заданные действия (у меня они в файле exec.php). Для запуска файлов используем сокеты.
4) Повторяем цикл пока время работы скрипта не приблизится к максимально разрешенному. Я поставил — пока до максимального времени не останется 5 секунд.

Итак… считаем начальные данные по времени:

$start_time = microtime(); // Узнаем время запуска скрипта $start_array = explode(" ",$start_time); // Разделяем секунды и миллисекунды $start_time = $start_array[1]; // получаем стартовое время скрипта $max_exec = ini_get("max_execution_time"); //Получаем максимально возможное время работы скрипта 

Собственно, цикл. Комментарии в коде.

do < $nowtime = time(); // Текущее время //// Если текущее время есть в массиве с временами выполнения скрипта. if (in_array($nowtime, $_SESSION["num_st"])) < // Сокетом цепляемся к файлу с основным содержанием действий $http = fsockopen('test.ru',80); /// заодно передаем ему данные сессии и время когда он должен сработать fputs($http, "GET http://test.ru/exec.php?".session_name()."=".session_id()."&nowtime=$nowtime HTTP/1.0\r\n"); fputs($http, "Host: test.ru\r\n"); fputs($http, "\r\n"); fclose($http); >//// выполнили заданное действие // Узнаем текущее время чтобы проверить, дальше ли вести цикл или перезапустить $now_time = microtime(); $now_array = explode(" ",$now_time); $now_time = $now_array[1]; // вычитаем из текущего времени начальное начальное $exec_time = $now_time - $start_time+$exec_time; /// тормозимся на секунду usleep(1000000); //Остановка скрипта, работающего в фоновом режиме. Я другого способа не придумал. if (file_exists("stop.txt")) exit; //Проверяем время работы, если до конца работы скрипта //осталось менее 5 секунд, завершаем работу цикла. > while($exec_time < ($max_exec - 5));

Ну и, если разрешенное время подходит к концу, то завершаем цикл и благополучно запускаем этот же скрипт другие процессом (в 5 секунд точно уложимся)

// Запускаем этот же скрипт новым процессом и завершаем работу текущего $http = fsockopen('test.ru',80); fputs($http, "GET http://test.ru/index.php?".session_name()."=".session_id()."&bu=$max_exec HTTP/1.0\r\n"); fputs($http, "Host: test.ru\r\n"); fputs($http, "\r\n"); fclose($http); 

Собственно, готово.
Далее у меня много заморочек было в выполнении тех самых действий — там надо было робота написать для поиска ссылок по заданным ссылкам.

Когда дописал все, озадачился полезным применением…Использовать его можно как службу. Он может следить за чем-то в сети и уведомлять Вас, например, по почте. И не надо никаких cron'ов.

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

Источник

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

image

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

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

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


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

php /var/www/LOGIN/data/www/SITE/cron.php 

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

/usr/bin/php /var/www/LOGIN/data/www/SITE/cron.php 

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

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

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


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

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

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

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

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


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

> /var/www/LOGIN/data/www/SITE/log.html 

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

/usr/bin/php /var/www/LOGIN/data/www/SITE/cron.php > /var/www/LOGIN/data/www/SITE/log.html 

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

/usr/bin/php /var/www/LOGIN/data/www/SITE/cron.php > /var/www/LOGIN/data/www/SITE/log.html >/dev/null 2>&1 

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

/usr/bin/php /var/www/LOGIN/data/www/SITE/cron.php > /var/www/LOGIN/data/www/SITE/log.html && >/dev/null 2>&1 
Случай четвёртый


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

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

cd /var/www/LOGIN/data/www/SITE/ 

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

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

$path_parts = pathinfo($_SERVER['SCRIPT_FILENAME']); // определяем директорию скрипта chdir($path_parts['dirname']); // задаем директорию выполнение скрипта 

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

Заключение


На этом всё. Проблемы и решения не тривиальны и вообще такое сочетание неудачных настроек встречается редко. Удачи вам при развертывании своих проектов и при переездах.

Источник

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