Примеры
// Создаём и запускаем таймер, который сработает через 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 ;
>);
?php
Пример #3 Периодический таймер. Использование callback-функции для перезадания интервала
// Срабатывает раз в 10.5 секунд
?php
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 ;
>);
?php
Пример #5 Ждём, пока STDIN не станет читаемым
// Ждём, пока STDIN не станет читаемым
$w = new EvIo ( STDIN , Ev :: READ , function ( $watcher , $revents ) echo «STDIN is readable\n» ;
>);
?php
Пример #6 Используем асинхронный ввод/вывод для доступа к сокету
/* Используем асинхронный ввод/вывод для доступа к сокету */
?php
// Модуль `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 ;
?php
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 ;
?php
if (! $socket_loop ) $socket_loop = $loop ;
>
// теперь используем $socket_loop для всех сокетов, а $loop для всего остального
?>
Пример #9 Перехватываем сигнал SIGTERM
$w = new EvSignal ( SIGTERM , function ( $watcher ) echo «Получен сигнал SIGTERM\n» ;
$watcher -> stop ();
>);
?php
Пример #10 Отслеживаем изменение /var/log/messages
// Используем интервал опроса в 10 секунд
$w = new EvStat ( «/var/log/messages» , 8 , function ( $w ) echo «/var/log/messages изменён\n» ;
?php
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 ();
?php
// 1 секунду после последнего изменения файла
printf ( «Текущий размер: %ld\n» , $stat -> attr ()[ ‘size’ ]);
>);
$stat = new EvStat ( «/var/log/messages» , 0. , function () use ( $timer ) // Сбрасываем наблюдателя $timer
$timer -> again ();
>);
Пример #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 );
>
?>
Таймер обратного отсчета для сайта на PHP+Javascript
Говоря о таймере обратного отсчета следует учесть тот факт, что таймеры делятся на два вида, точнее сказать, их употребление бывает разное. В одном случае счетчику задается конечная дата, в другом же задается количество времени, отсчет ведется для каждого пользователя отдельно (этот вариант подходит для тех, кто проводит какие-то акции или скидки).
1. HTML
Для разметки построим контейнер блоков, каждый элемент которого будет отвечать за определенную часть времени, то есть секунды, минуты, часы, дни и недели.
недель: 00дней: 00часов: 00минут: 00секунд: 00
2. CSS
Все вложенные блоки сделаем невидимыми и показывать будем только те, которые включены в настройках.
Сначала подключим свой шрифт с Google Fonts:
@import url(//fonts.googleapis.com/css?family=Open+Sans+Condensed:300&subset=latin,cyrillic);
Задаем стандартные параметры для документа:
Остается написать классы для самого счетчика. Блок с таймером выровняем по центру и укажем auto-размер. Точные размеры будем задавать с помощью скрипта.
#countdown < margin:0px auto; width:auto; padding:20px 20px 20px 10px; position:relative; border:#222 2px solid; background:#eee; >#countdown div < margin:0px 0px 0px 10px; float:left; width:88px; >#countdown div span < display:block; height:53px; background:#000; border-bottom:#f00 1px solid; color:#eee; font-size: 24pt; padding-top: 4px; padding-left: 16px; letter-spacing: 31px; /* Последние 4 параметра отвечают за размер текста и его выравнивание на циферблате */ >#countdown #week,#countdown #day,#countdown #hour,#countdown #minute,#countdown #second < display:none; >.clear
3. PHP
Как и говорилось ранее, в таймере предусмотрим два варианта, это отсчет времени к определенной дате (например, 1 мая 2018 года) и таймер по заданному времени (например, 12 часов). Этот выбор мы сделаем в настройках скрипта.
$countdown_setting = array( "type" => "date", /* date или time, date - отсчет до указанной даты, time - отсчет указанного времени */ "cookie" => true, /* true или false, запоминать время, только для режима time */ "position" => "vertical", /* horizontal или vertical, положение блока */ "date" => array( "year" => 2014, "month" => 4, "day" => 15, "hour" => 12, "minute" => 0, "second" => 0 ), /* указывается конечная дата, для режима date */ "time" => array( "week" => 0, "day" => 2, "hour" => 10, "minute" => 0, "second" => 0 ), /* указывается время, для режима time */ "visible" => array( "week" => array("none","недель:"), "day" => array("block","дней:"), "hour" => array("block","часов:"), "minute" => array("block","минут:"), "second" => array("block","секунд:") ) /* настройка отображения блоков, block - показывать соответствующий блок, none - не показывать; второй параметр - заголовок блока */ );
Поскольку видимость блоков (дни, минуты и т.д.) задается в конфиге, необходимо сделать генерацию html-кода:
$script = ''; $countdown_txt = ''; $block_count = 0; /* Генерация html кода таймера */ foreach($countdown_setting['visible'] AS $i => $v) < $countdown_txt .= ''.$v[1].' 00'; $script .= ''; if($v[0] == 'block') $block++; > if($countdown_setting['position'] == 'vertical') $block = 1; $script .= '';
Обработку времени будем делать на PHP с учетом серверного времени, чтобы время не зависело от настроек времени конечного пользователя, как это бывает при использовании Javascript:
/* обработка, когда указано время отсчета */ if($countdown_setting['type'] == 'time') < $time_value = $countdown_setting['time']['week']*7*60*60*24+$countdown_setting['time']['day']*60*60*24+$countdown_setting['time']['hour']*60*60+$countdown_setting['time']['minute']*60+$countdown_setting['time']['second']; $time_new = $time+$time_value; /* обработка кукисов */ if($countdown_setting['cookie']) < $time_cookie = (int) $_COOKIE['time']; if($time_cookie==0) < setcookie("time",$time_new); >else < $time_value = $time_cookie-$time; >> $script .= ''; > elseif ($countdown_setting['type'] == 'date') < /* обработка, когда указана конечная дата */ $time_value = mktime($countdown_setting['date']['hour'],$countdown_setting['date']['minute'],$countdown_setting['date']['second'],$countdown_setting['date']['month'],$countdown_setting['date']['day'],$countdown_setting['date']['year']); $time_value = $time_value-$time; $script .= ''; >
4. Javascript
Первое что нам необходимо, это подключить фреймворк jQuery (о способах подключения можно почитать здесь)
Опишем функцию countdown_go(), она будет отвечать за вывод времени в блоки. При знаниях JS, функцию можно оптимизировать.
function countdown_go() < timeleft_func = timeleft; if(countdown_week=='block') < timevalue = Math.floor(timeleft_func/(7*24*60*60)); timeleft_func -= timevalue*7*24*60*60; if(timevalue<10) timevalue = '0'+timevalue; $("#week span").html(timevalue); >if(countdown_day=='block') < timevalue = Math.floor(timeleft_func/(24*60*60)); timeleft_func -= timevalue*24*60*60; if(timevalue<10) timevalue = '0'+timevalue; $("#day span").html(timevalue); >if(countdown_hour=='block') < timevalue = Math.floor(timeleft_func/(60*60)); timeleft_func -= timevalue*60*60; if(timevalue<10) timevalue = '0'+timevalue; $("#hour span").html(timevalue); >if(countdown_minute=='block') < timevalue = Math.floor(timeleft_func/(60)); timeleft_func -= timevalue*60; if(timevalue<10) timevalue = '0'+timevalue; $("#minute span").html(timevalue); >if(countdown_second=='block') < timevalue = Math.floor(timeleft_func/1); timeleft_func -= timevalue*1; if(timevalue<10) timevalue = '0'+timevalue; $("#second span").html(timevalue); >timeleft-=1; return false; >
Последнее, что осталось, это запустить таймер, здесь используем стандартную функцию setInterval().
Как установить на сайт?
Если вы не хотите разбираться и устанавливать, можете просто скачать исходники, создать на сайте папку countdown и залить туда файлы. А далее на сайт вставить через фрейм:
Советую обратить внимание на более усовершенствованный, бесплатный таймер с админпанелью и видеоинструкцией, скачать можно здесь.
Вот и все, остались вопросы — задаем в комментариях.