Озадачили меня тут написать демона на PHP. Т.е. скрипт, который будет заданное количество раз в заданное количество часов в случайное время (всегда случайное) выполнять определенные действия, и все это без использования cron'a.
До этого никогда не заморачивался, а тут после постановки задачи, начал было думать что так нельзя, что php скрипт надо вызывать браузером…ну задача то поставлена, надо выполнять.
Первая мысль — отключить ограничение времени выполнения скрипта. Запрещено хостером.
Вторая мысль — яваскриптом повторять аякс-запрос периодически (да хоть раз в секунду). — нельзя (требование заказчика).
Выяснилось, собственно, что и браузер открыт не должен быть, и крон нельзя использовать, и работать скрипт должен независимо от пользователя, бесконечно долго. Естественно, он должен минимум грузить систему.
1. Пачка сигарет, ночь, гугл, доки, книги, мануалы….
goto 1…
На выходе получаю:
Задача_1:
Реализовать генератор времен выполнения скрипта, исходя из заданных количества раз и количества часов. Хранить где-то эти времена.
Задача_2:
Работать после закрытия браузера
Задача_3:
Не вылетать после окончания ограничения времени выполнения скрипта
Задача_4:
Выполнять в нужное время какие-то действия.
Итак…
Пишем в конфиге исходные данные:
Далее пишем функцию, которая поможет нам сгенерировать времена запуска.
В ней мы генерируем случайное число от 0 до количества секунд в исходном интервале.
Далее сгенерируем и запишем в сессию массив времен запуска. Предварительно отсортируем массив по возрастанию, чтобы сначала шло раннее время (машину времени я еще не успел создать).
Теперь надо заставить скрипт работать, не обращая внимания на максимальное время выполнения, установленное сервером.
Принцип таков:
1) Определяем время начала работы скрипта;
2) Определяем установленное ограничение на время выполнения.
3) Запускаем цикл, внутри которого считаем текущее время и вычисляем общее время работы скрипта, сверяем текущее время со значениями в массиве времен запуска, и если совпадение есть, выполняем заданные действия (у меня они в файле exec.php). Для запуска файлов используем сокеты.
4) Повторяем цикл пока время работы скрипта не приблизится к максимально разрешенному. Я поставил — пока до максимального времени не останется 5 секунд.
Итак… считаем начальные данные по времени:
Собственно, цикл. Комментарии в коде.
Ну и, если разрешенное время подходит к концу, то завершаем цикл и благополучно запускаем этот же скрипт другие процессом (в 5 секунд точно уложимся)
Собственно, готово.
Далее у меня много заморочек было в выполнении тех самых действий — там надо было робота написать для поиска ссылок по заданным ссылкам.
Когда дописал все, озадачился полезным применением…Использовать его можно как службу. Он может следить за чем-то в сети и уведомлять Вас, например, по почте. И не надо никаких cron'ов.
Скрипт можно еще оптимизировать — доработкой не занимался.
Кстати, вот от чего я не смог оторваться — браузер все же придется открыть, чтобы изначально запустить скрипт.
До этого никогда не заморачивался, а тут после постановки задачи, начал было думать что так нельзя, что 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 < = $num_starts); sort($time_to_start, SORT_NUMERIC); $_SESSION["num_st"] = $time_to_start; }
Теперь надо заставить скрипт работать, не обращая внимания на максимальное время выполнения, установленное сервером.
Принцип таков:
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'ов.
Скрипт можно еще оптимизировать — доработкой не занимался.
Кстати, вот от чего я не смог оторваться — браузер все же придется открыть, чтобы изначально запустить скрипт.
