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.
