开发者

PHP function that receive a cron string and return the next run timestamp

开发者 https://www.devze.com 2023-02-02 11:37 出处:网络
I need to devel开发者_高级运维op a task system that should be able to work on servers that doesn\'t support crontab.

I need to devel开发者_高级运维op a task system that should be able to work on servers that doesn't support crontab.

I'm asking if there is any existing code that can take a cron string (e.g. '0 0,12 1 */2 *' and return the timestamp of the next scheduled run.

If such a code couldn't be found then how should I start with that?


You could use this class PHP-Parse-cron-strings-and-compute-schedules

It'll also compute the last scheduled run


Use this function:

function parse_crontab($time, $crontab)
         {$time=explode(' ', date('i G j n w', strtotime($time)));
          $crontab=explode(' ', $crontab);
          foreach ($crontab as $k=>&$v)
                  {$time[$k]=intval($time[$k]);
                   $v=explode(',', $v);
                   foreach ($v as &$v1)
                           {$v1=preg_replace(array('/^\*$/', '/^\d+$/', '/^(\d+)\-(\d+)$/', '/^\*\/(\d+)$/'),
                                             array('true', $time[$k].'===\0', '(\1<='.$time[$k].' and '.$time[$k].'<=\2)', $time[$k].'%\1===0'),
                                             $v1
                                            );
                           }
                   $v='('.implode(' or ', $v).')';
                  }
          $crontab=implode(' and ', $crontab);
          return eval('return '.$crontab.';');
         }
var_export(parse_crontab('2011-05-04 02:08:03', '*/2,3-5,9 2 3-5 */2 *'));
var_export(parse_crontab('2011-05-04 02:08:03', '*/8 */2 */4 */5 *'));


You can try this: http://mtdowling.com/blog/2012/06/03/cron-expressions-in-php/ which use PHP Cron-Expression parser library, a php class https://github.com/mtdowling/cron-expression


I found diyism had a great answer, but found a crucial bug.

If you enter a cron time such as 0 * * * *, it'll run at 0 minute, 8th, minute and 9th minute. The code gives a conditional 08===0, which returns true, because PHP interprets numbers starting with 0 as octal, and 08 and 09 are not valid octal numbers so they're interpreted as 0. More information here.

How to prevent PHP from doing octal math in conditionals? (why does 08 === 0)

Here's a fixed and well commented version of diyism's code.

// Parse CRON frequency
function parse_crontab($time, $crontab) {
    // Get current minute, hour, day, month, weekday
    $time = explode(' ', date('i G j n w', strtotime($time)));
    // Split crontab by space
    $crontab = explode(' ', $crontab);
    // Foreach part of crontab
    foreach ($crontab as $k => &$v) {
        // Remove leading zeros to prevent octal comparison, but not if number is already 1 digit
        $time[$k] = preg_replace('/^0+(?=\d)/', '', $time[$k]);
        // 5,10,15 each treated as seperate parts
        $v = explode(',', $v);
        // Foreach part we now have
        foreach ($v as &$v1) {
            // Do preg_replace with regular expression to create evaluations from crontab
            $v1 = preg_replace(
                // Regex
                array(
                    // *
                    '/^\*$/',
                    // 5
                    '/^\d+$/',
                    // 5-10
                    '/^(\d+)\-(\d+)$/',
                    // */5
                    '/^\*\/(\d+)$/'
                ),
                // Evaluations
                // trim leading 0 to prevent octal comparison
                array(
                    // * is always true
                    'true',
                    // Check if it is currently that time, 
                    $time[$k] . '===\0',
                    // Find if more than or equal lowest and lower or equal than highest
                    '(\1<=' . $time[$k] . ' and ' . $time[$k] . '<=\2)',
                    // Use modulus to find if true
                    $time[$k] . '%\1===0'
                ),
                // Subject we are working with
                $v1
            );
        }
        // Join 5,10,15 with `or` conditional
        $v = '(' . implode(' or ', $v) . ')';
    }
    // Require each part is true with `and` conditional
    $crontab = implode(' and ', $crontab);
    // Evaluate total condition to find if true
    return eval('return ' . $crontab . ';');
}


I wrote a very powerful PHP class called CalendarEvent a long time ago:

https://github.com/cubiclesoft/php-misc/

It supports two different pattern syntaxes. Normal cron cannot handle certain complex patterns whereas the default CalendarEvent syntax handles any scheduling pattern you could ever need. The cron pattern syntax support is actually a fallback (prefix cron lines with cron and a space).

CalendarEvent was written mostly as a calendar event calculation class and just happened to support cron style "next trigger" mechanisms. It is actually designed to calculate an entire schedule for multiple months for the purpose of displaying a calendar to a user (hence the class name). I've also used the class as an intermediate solution to translate events between calendar platforms. That's the rarer scenario - I've more frequently utilized it for AddSchedule()/NextTrigger() cron-like solutions.


You can use the popular package PHP Cron Expression Parser: https://github.com/dragonmantank/cron-expression

This also is the built-in part of the Laravel Framework)


In the parse_crontab function:

Replace $time[$k] with intval($time[$k]) inside the preg_replace line
to compare two base10 numbers correctly.

0

精彩评论

暂无评论...
验证码 换一张
取 消