Как сделать таймер php
Перейти к содержимому

Как сделать таймер php

  • автор:

Как реализовать таймер на php?

Приветствую. Есть скрипт-демон, который работает бесконечно. Как можно сделать, чтобы раз в сутки один массив внутри этого скрипта обнулялся? И чтобы это минимально повлияло на остальную работу демона.

  • Вопрос задан более трёх лет назад
  • 8700 просмотров

Комментировать
Решения вопроса 0
Ответы на вопрос 4

riky

$startTime = time(); $arr = []; // . while(1) < // main loop //. if (time() >$startTime + 24*60*60) < $startTime = time(); $arr = []; >>

Ответ написан более трёх лет назад
Комментировать
Нравится 2 Комментировать
Евгений Вольф @Wolfnsex Куратор тега PHP
Если не хочешь быть первым — не вставай в очередь!
ну так на вскидку, решение в лоб:

$nullFlag = true; if($time > 12:00 && < 13:00 && $nullFlag) < //обнуляем массив $nullFlag = false; >elseif ($time > 13:00)

но это прям такое, топорное решение (код — условный, иллюстрирует исключительно идею).

Можно ещё создавать файл на диске где-то, по cron’у (раз в сутки) и делать например так:

$file_path = "/home/daemon/clear_array.do"; if(file_exists($file_path)) < //Очивщаем массив unlink($file_path); >

Основная проблема в том, что я не могу придумать так вот сходу, как расшарить данные во вне, с работающего нон-стоп скрипта, на PHP. Это всё-таки не С++.

Ещё можно попробовать хранить этот массив в Redis, или memcached, и вычищать его оттуда раз в сутки, и при каждой необходимости — считывать его (массив) оттуда. Или сериализовывать его и сохранять на диск.

Если кто-то подскажет, как кусок памяти на ПХП расшарить, я думаю, будет более оптимальное решение.

Можно ещё попробовать вебсокет на ПХП открыть, и при поступлении соотв. команды — очищать массив. Но я сам веб-сокеты в ПХП-реализации не пробовал и не могу к сожалению, подсказать Вам, как это будет выглядеть.

P.S. Реализацию с файлом, можно заменить на запись в БД или в Redis/Memcached. Т.е. проверять не наличие файла, а наличие записи. Кстати да, Redis имеет такой параметр как «срок хранения кэша», в этом случае, даже CRON будет не нужен. Наверняка, что-то такое и в memcached есть.

Таймер на PHP как реализовать?

Я хочу создать функцию, которая будет запрещать флудить, то есть, чтобы можно было писать сообщение раз в 5 секунд, к примеру. Хочу понять сам принцип, а не попросить вас решить мою конкретную проблему. Например функция отправки сообщения выглядит так:

function sendMessage($User, $Message) < if( validate_spam() < 5000 ) < /* Если в функция возвращает меньше число чем 5 секунд */ return json_encode(["error"=>"Прекратите флудить"]); > else < validate_spam(0) // Это, типа, что-то вроде запуска таймера >> 

То как должна выглядеть function validate_spam($param) ?

Отслеживать

1,638 2 2 золотых знака 12 12 серебряных знаков 24 24 бронзовых знака

задан 13 сен 2018 в 23:08

Roman Kashirov Roman Kashirov

45 6 6 бронзовых знаков

Объективный таймер обратного отсчёта на PHP

Недавно мы разобрались с тем, как можно показывать новые данные на странице без перезагрузки, а до этого — как использовать PHP-скрипты. Сегодня объединим это в один проект и сделаем таймер обратного отсчёта на PHP.

В чём идея

Допустим, у нас есть какое-то событие, которое заканчивается 16 октября 2022 года в 14:00 — например распродажа. Нам нужно вывести таймер на страницу, который будет отсчитывать время до этого события.

При этом нам важно, чтобы отсчёт не зависел от пользователя: например, если он переставит дату на календаре своего компьютера на 1 сентября, то чтобы у него не появилось 9 дополнительных дней распродажи. Поэтому мы не можем использовать дату и время с компьютера пользователя, нам нужно брать их с сервера.

Получается, что алгоритм будет работать так:

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

Раз у нас дата лежит на сервере, то и отдавать мы будем её при помощи PHP-скрипта. Но раз сервер всё равно нам что-то отдаёт, то пусть это сразу будет готовый таймер с текстом, а мы его встроим на страницу. Это значит, что нам нужен такой скрипт, который просто будет постоянно через PHP получать с сервера данные и отправлять их в нужное место на странице.

Что понадобится

Единственное, что нам нужно от сервера, — чтобы он мог выполнять PHP-скрипты. Это умеет делать практически любой веб-сервер в интернете, поэтому, если у вас есть хостинг и на хостинге можно размещать сайты, — скрипт тоже будет там работать.

Если хостинга с сайтом нет, то можно сделать так: установить MAMP и получить рабочий сервер с PHP у себя на компьютере.

Добавляем на странице место для таймера

Так как всю работу будут делать скрипты, то нам нужно просто указать место на странице, куда отправить результат. Возьмём наш учебный сайт mihailmaximov.ru и перед разделом с контактами добавим блок для таймера:

Этого будет достаточно, чтобы скрипт показал таймер в выбранном месте.

Пишем скрипт на странице

Первым делом подключаем jQuery — это позволит нам работать с AJAX-скриптом и вызывать его самым простым способом.

Теперь в раздел добавляем простой скрипт на JavaScript. Его задача — периодически обращаться к серверу и обновлять данные на странице. Благодаря AJAX он сможет это делать без перезагрузки, работая с отдельным блоком:

  

Готовим PHP-скрипт

Мы уже работали с PHP-скриптами, когда делали форму обратной связи, и там же рассказывали, как загрузить этот скрипт на сервер. Если пропустили этот цикл — будет полезно:

Примеры

// Создаём и запускаем таймер, который сработает через 2 секунды, после чего будет срабатывать
// раз в секунду, пока вы его вручную не остановите
$w2 = new EvTimer ( 2 , 1 , function ( $w ) echo «вызывается раз в секунду, первое срабатывание через 2 секунды\n» ;
echo «итерация color: #007700″>, Ev :: iteration (), PHP_EOL ;

// Останавливаем наблюдателя через 5 итераций
Ev :: iteration () == 5 and $w -> stop ();
// Остановливаем наблюдателя, если следующий вызов приведёт к десятой (или больше) итерации
Ev :: iteration () >= 10 and $w -> stop ();
>);

// Создаём остановленный таймер. Он будет неактивен, пока мы его не запустим
$w_stopped = EvTimer :: createStopped ( 10 , 5 , function( $w ) echo «Callback-функция таймера, созданного остановленным\n» ;

// Останавливаем наблюдателя через 2 итерации
Ev :: iteration () >= 2 and $w -> stop ();
>);

// Запускаем событийный цикл, пока работает хотя бы один наблюдатель или пока не вызван Ev::stop()
Ev :: run ();

// Запускаем и смотрим, как он работает
$w_stopped -> start ();
echo «Запускаем одну итерацию\n» ;
Ev :: run ( Ev :: RUN_ONCE );

echo «Перезапускаем второго наблюдателя и пытаемся отловить те же события, но не блокируем\n» ;
$w2 -> again ();
Ev :: run ( Ev :: RUN_NOWAIT );

$w = new EvTimer ( 10 , 0 , function() <>);
echo «Запускаем блокирующий цикл\n» ;
Ev :: run ();
echo «END\n» ;
?>

Результатом выполнения данного примера будет что-то подобное:

2 секунды прошло вызывается раз в секунду, первое срабатывание через 2 секунды итерация = 1 вызывается раз в секунду, первое срабатывание через 2 секунды итерация = 2 вызывается раз в секунду, первое срабатывание через 2 секунды итерация = 3 вызывается раз в секунду, первое срабатывание через 2 секунды итерация = 4 вызывается раз в секунду, первое срабатывание через 2 секунды итерация = 5 Запускаем одну итерацию Функция обратного вызова таймера, созданного остановленным Перезапускаем второго наблюдателя и пытаемся отловить те же события, но не блокируем Запускаем блокирующий цикл вызывается раз в секунду, первое срабатывание через 2 секунды итерация = 8 вызывается раз в секунду, первое срабатывание через 2 секунды итерация = 9 вызывается раз в секунду, первое срабатывание через 2 секунды итерация = 10 END

Пример #2 Периодический таймер. Срабатывает раз в 10.5 секунд

$w = new EvPeriodic ( 0. , 10.5 , NULL , function ( $w , $revents ) echo time (), PHP_EOL ;
>);

Пример #3 Периодический таймер. Использование callback-функции для перезадания интервала

// Срабатывает раз в 10.5 секунд

function reschedule_cb ( $watcher , $now ) return $now + ( 10.5 . — fmod ( $now , 10.5 ));
>

$w = new EvPeriodic ( 0. , 0. , «reschedule_cb» , function ( $w , $revents ) echo time (), PHP_EOL ;
>);

Пример #4 Периодический таймер. Срабатывает каждые 10.5 секунд, начиная с текущего момента

// Срабатывает раз в 10.5 секунд начиная с текущего момента
$w = new EvPeriodic ( fmod ( Ev :: now (), 10.5 ), 10.5 , NULL , function ( $w , $revents ) echo time (), PHP_EOL ;
>);

Пример #5 Ждём, пока STDIN не станет читаемым

// Ждём, пока STDIN не станет читаемым
$w = new EvIo ( STDIN , Ev :: READ , function ( $watcher , $revents ) echo «STDIN is readable\n» ;
>);

Ev :: run ( Ev :: RUN_ONCE );
?>

Пример #6 Используем асинхронный ввод/вывод для доступа к сокету

/* Используем асинхронный ввод/вывод для доступа к сокету */

// Модуль `sockets’ продолжит логировать предупреждения
// для EINPROGRESS, EAGAIN/EWOULDBLOCK etc.
error_reporting ( E_ERROR );

$e_nonblocking = array ( /*EAGAIN или EWOULDBLOCK*/ 11 , /*EINPROGRESS*/ 115 );

// Получаем порт для сервиса WWW
$service_port = getservbyname ( ‘www’ , ‘tcp’ );

// Получаем IP-адрес целевого хоста
$address = gethostbyname ( ‘google.co.uk’ );

// Создаём сокет TCP/IP
$socket = socket_create ( AF_INET , SOCK_STREAM , SOL_TCP );
if ( $socket === FALSE ) echo «Ошибка при вызове socket_create(): причина: »
. socket_strerror ( socket_last_error ()) . «\n» ;
>

// Устанавливаем флаг O_NONBLOCK
socket_set_nonblock ( $socket );

// Прерываем по превышению времени ожидания
$timeout_watcher = new EvTimer ( 10.0 , 0. , function () use ( $socket ) socket_close ( $socket );
Ev :: stop ( Ev :: BREAK_ALL );
>);

// Посылаем запрос HEAD когда сокет доступен для записи
$write_watcher = new EvIo ( $socket , Ev :: WRITE , function ( $w )
use ( $socket , $timeout_watcher , $e_nonblocking )
// Останавливаем наблюдателя $timeout_watcher
$timeout_watcher -> stop ();
// Останавливаем наблюдателя $write_watcher
$w -> stop ();

$in = «HEAD / HTTP/1.1\r\n» ;
$in .= «Host: google.co.uk\r\n» ;
$in .= «Connection: Close\r\n\r\n» ;

if (! socket_write ( $socket , $in , strlen ( $in ))) trigger_error ( «Ошибка записи $in в сокет» , E_USER_ERROR );
>

$read_watcher = new EvIo ( $socket , Ev :: READ , function ( $w , $re )
use ( $socket , $e_nonblocking )
// Сокет доступен для чтения. Читаем 20 байт в неблокирующем режиме
$ret = socket_recv ( $socket , $out , 20 , MSG_DONTWAIT );

if ( $ret ) echo $out ;
> elseif ( $ret === 0 ) // Все прочтено
$w -> stop ();
socket_close ( $socket );
return;
>

// Ловим EINPROGRESS, EAGAIN или EWOULDBLOCK
if ( in_array ( socket_last_error (), $e_nonblocking )) return;
>

$w -> stop ();
socket_close ( $socket );
>);

$result = socket_connect ( $socket , $address , $service_port );

Результатом выполнения данного примера будет что-то подобное:

HTTP/1.1 301 Moved Permanently Location: http://www.google.co.uk/ Content-Type: text/html; charset=UTF-8 Date: Sun, 23 Dec 2012 16:08:27 GMT Expires: Tue, 22 Jan 2013 16:08:27 GMT Cache-Control: public, max-age=2592000 Server: gws Content-Length: 221 X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN Connection: close

Пример #7 Встраиваем один цикл в другой

/*
* Пытаемся получить встраиваемый цикл и встроить его в событийный цикл по умолчанию.
* Если это невозможно — используем цикл по умолчанию. Цикл по умолчанию
* хранится в $loop_hi, а встраиваемый в $loop_lo (который будет равен $loop_hi в случае
* если мы не будем использовать встраиваемый цикл).
*
* Пример взят из
* http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Examples_CONTENT-9
*/
$loop_hi = EvLoop :: defaultLoop ();
$loop_lo = NULL ;
$embed = NULL ;

if ( $loop_lo ) $embed = new EvEmbed ( $loop_lo , function () <>);
> else $loop_lo = $loop_hi ;
>
?>

Пример #8 Встраивание цикла, созданного с помощью kqueue в цикл по умолчанию

/*
* Проверяем, что бэкенд kqueue доступен, но не рекомендован, и создаём его для
* работы с сокетами (которые обычно работают с любой реализацией kqueue).
* Сохраняем событийный цикл kqueue/socket-only в loop_socket. (Можно опционально
* использовать флаг EVFLAG_NOENV)
*
* Пример взят из
* http://pod.tst.eu/http://cvs.schmorp.de/libev/ev.pod#Examples_CONTENT-9
*/
$loop = EvLoop :: defaultLoop ();
$socket_loop = NULL ;
$embed = NULL ;

if (! $socket_loop ) $socket_loop = $loop ;
>

// теперь используем $socket_loop для всех сокетов, а $loop для всего остального
?>

Пример #9 Перехватываем сигнал SIGTERM

$w = new EvSignal ( SIGTERM , function ( $watcher ) echo «Получен сигнал SIGTERM\n» ;
$watcher -> stop ();
>);

Пример #10 Отслеживаем изменение /var/log/messages

// Используем интервал опроса в 10 секунд
$w = new EvStat ( «/var/log/messages» , 8 , function ( $w ) echo «/var/log/messages изменён\n» ;

if ( $attr [ ‘nlink’ ]) printf ( «Текущий размер: %ld\n» , $attr [ ‘size’ ]);
printf ( «Текущее значение atime: %ld\n» , $attr [ ‘atime’ ]);
printf ( «Текущее значение mtime: %ld\n» , $attr [ ‘mtime’ ]);
> else fprintf ( STDERR , «файл `messages` отсутствует!» );
$w -> stop ();
>
>);

Пример #11 Отслеживаем изменение /var/log/messages. Избегаем пропуска обновлений с помощью задержки в одну секунду

$timer = EvTimer :: createStopped ( 0. , 1.02 , function ( $w ) $w -> stop ();

// 1 секунду после последнего изменения файла
printf ( «Текущий размер: %ld\n» , $stat -> attr ()[ ‘size’ ]);
>);

$stat = new EvStat ( «/var/log/messages» , 0. , function () use ( $timer ) // Сбрасываем наблюдателя $timer
$timer -> again ();
>);

$timer -> data = $stat ;

Пример #12 Отслеживаем изменения статуса процесса

if ( $pid == — 1 ) fprintf ( STDERR , «pcntl_fork failed\n» );
> elseif ( $pid ) $w = new EvChild ( $pid , FALSE , function ( $w , $revents ) $w -> stop ();

printf ( «Процесс %d вышел с кодом %d\n» , $w -> rpid , $w -> rstatus );
>);

// Защита от зомби процессов
pcntl_wait ( $status );
> else // Порождённый потомок
exit( 2 );
>
?>

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *