Функция PHP, которая получает строку cron и возвращает метку времени следующего запуска - PullRequest
14 голосов
/ 03 января 2011

Мне нужно разработать систему задач, которая должна работать на серверах, которые не поддерживают crontab.

Я спрашиваю, существует ли какой-либо существующий код, который может принимать строку cron (например, '0 0,12 1 * / 2 * 'и верните метку времени следующего запланированного запуска.

Если такой код не может быть найден, то как мне начать с этого?

Ответы [ 6 ]

12 голосов
/ 03 января 2011

Вы можете использовать этот класс PHP-Parse-cron-strings-and-compute-schedule

Он также вычислит последний запланированный прогон

8 голосов
/ 20 апреля 2011

Используйте эту функцию:

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 *'));
3 голосов
/ 14 января 2013

Вы можете попробовать это: http://mtdowling.com/blog/2012/06/03/cron-expressions-in-php/, которые используют библиотеку синтаксического анализатора PHP Cron-Expression, класс php https://github.com/mtdowling/cron-expression

2 голосов
/ 30 декабря 2016

Я обнаружил, что у диизма был отличный ответ, но нашел решающую ошибку.

Если вы введете время cron, например 0 * * * *, оно будет работать в 0, 8, 9 и 9 минутах. Код дает условное 08===0, которое возвращает true, потому что PHP интерпретирует числа, начинающиеся с 0, как восьмеричные, а 08 и 09 не являются действительными восьмеричными числами, поэтому они интерпретируются как 0. Подробнее здесь.

Как запретить PHP выполнять восьмеричные вычисления в условных выражениях? (почему 08 === 0)

Вот исправленная и хорошо прокомментированная версия кода diyism.

// 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 . ';');
}
0 голосов
/ 07 апреля 2017

Я давно написал очень мощный PHP-класс CalendarEvent:

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

Он поддерживает два разных синтаксиса шаблона. Обычный cron не может обрабатывать определенные сложные шаблоны, в то время как синтаксис CalendarEvent по умолчанию обрабатывает любой шаблон планирования, который вам может понадобиться. Поддержка синтаксиса паттернов cron на самом деле является запасным вариантом (префиксные строки cron с cron и пробелом).

CalendarEvent был написан в основном как класс для вычисления событий календаря и, как оказалось, поддерживал механизмы cron в стиле «следующий триггер». На самом деле он предназначен для расчета всего расписания за несколько месяцев с целью отображения календаря пользователю (отсюда и название класса). Я также использовал этот класс в качестве промежуточного решения для перевода событий между календарными платформами. Это более редкий сценарий - я чаще использовал его для cron-подобных решений AddSchedule () / NextTrigger ().

0 голосов
/ 13 декабря 2014

В функции parse_crontab:

Заменить $time[$k] на intval($time[$k]) в строке preg_replace
правильно сравнить два base10 числа.

...