En ocasiones necesitamos que un script realice una tarea determinada cada cierto tiempo o a partir de un momento (fecha/hora) determinados.
En linux es fácil realizar esto mediante cron, sin embargo el programador de tareas de Windows es más farragoso de configurar para estos menesteres. Además puede que no nos interese/guste que el script esté continuamente arrancando/parando.
Hasta ahora realizaba este tipo de bucles para estas tareas:
do { // anything sleep($interval); } while (true);
En este caso es un bucle infinito, pero eso ahora no importa, el sleep($interval);
(línea 3) es el tiempo de espera entre dos ejecuciones del bucle… pero podemos encontrarnos con que si $interval = 300;
(segundos) luego a la hora de la verdad se nos irá añadiendo algún segundo que otro entre las ejecuciones del bucle… y esto puede no importar o todo lo contrario.
Ayer encontré una función maravillosa: time_sleep_until()
Tal y como dice la documentación esta función dejará el script en pausa hasta que llegue el momento determinado en la función:
$next = time(); do { // anything $next = strtotime('+5min', $next); time_sleep_until($next); } while (true);
El problema es que según parece esta función trabaja en microsegundos, y guarda el valor con un entero de 32 bits, lo que nos da un máximo de 2^32 microsegundos, unos 4295 segundos (1 hora, 11 minutos y 35 segundos). Para solventar esto se me ha ocurrido la misma solución que la que apunta “purdue” en la documentación:
while (time() < $next) time_sleep_until($next);
Y bueno, juntando algunas cosas más podemos hacer que el script realice una tarea cada cierto tiempo durante unas horas al día:
<?php $runfile = 'runfile.log'; $interval = '5min'; $start = '18:00:00'; $end = '22:00:00'; $time_start = strtotime($start); $time_end = strtotime($end); $next = $time_start; do { file_put_contents($runfile, date('Y-m-d H:i:s')); if ($time_end <= strtotime('+1sec')) { $time_start = strtotime('+1day', $time_start); $time_end = strtotime('+1day', $time_end); $next = $time_start; } while ($next <= strtotime('+1sec')) $next = strtotime($interval, $next); echo date('Y-m-d H:i:s', $next), HT, 'next', "\n"; while (time() < $next) time_sleep_until($next); // anything } while (file_exists($runfile));
En el ejemplo completo he hecho que el bucle se ejecute siempre y cuando exista un fichero “runfile”, cuando lo borremos el bucle se ejecutará una última vez y terminara.