Вопрос

Как лучше всего проверить запись crontab с помощью PHP?Должен ли я использовать регулярное выражение или внешнюю библиотеку?У меня есть PHP-скрипт, который добавляет/удаляет записи из файла crontab, но я хочу каким-то образом проверить, что часть временного интервала находится в допустимом формате.

Это было полезно?

Решение

Хм, интересная проблема.

Если вы действительно собираетесь проверить это, регулярного выражения будет недостаточно, вам придется фактически проанализировать запись и проверить каждый из битов планирования.Это потому, что каждый бит может быть числом, строкой месяца/дня недели, диапазоном (2–7), набором (3, 4, суббота), ярлыком в стиле Vixie cron (60/5) или любой комбинацией. из вышесказанного - любой подход с одним регулярным выражением быстро станет очень сложным.

Просто используя crontab программы Vixie cron для проверки недостаточно, потому что на самом деле она не выполняет полную проверку!я могу получить crontab принимать все виды незаконных вещей.

Wicked Cool Shell Scripts Дэйва Тейлора (Ссылка на книги Google) есть скрипт sh, который выполняет частичную проверку, обсуждение показалось мне интересным.Вы также можете использовать или адаптировать код.

Я также нашел ссылки на два класса PHP, которые делают то, что вы говорите (качество которых я не оценивал):

Другой подход (в зависимости от того, что нужно делать вашему приложению) может заключаться в том, чтобы PHP программно сконструировал запись crontab и вставил ее, чтобы вы знали, что она всегда действительна, вместо того, чтобы пытаться проверить ненадежную строку.Тогда вам просто нужно будет создать пользовательский интерфейс «создать запись crontab», который может быть простым, если вам не нужны действительно сложные комбинации планирования.

Другие советы

Кто сказал, что регулярные выражения не могут этого сделать?

С уважением моего работодателя. Салир.com, вот тест PHPUnit, который выполняет такую ​​проверку.Не стесняйтесь изменять и распространять.Я буду признателен, если вы сохраните уведомление @author и ссылку на веб-сайт.

<?php
/**
 * @author Jordi Salvat i Alabart - with thanks to <a href="www.salir.com">Salir.com</a>.
 */

abstract class CrontabChecker extends PHPUnit_Framework_TestCase {
    protected function assertFileIsValidUserCrontab($file) {
        $f= @fopen($file, 'r', 1);
        $this->assertTrue($f !== false, 'Crontab file must exist');
        while (($line= fgets($f)) !== false) {
            $this->assertLineIsValid($line);
        }
    }

    protected function assertLineIsValid($line) {
        $regexp= $this->buildRegexp();
        $this->assertTrue(preg_match("/$regexp/", $line) !== 0);
    }

    private function buildRegexp() {
        $numbers= array(
            'min'=>'[0-5]?\d',
            'hour'=>'[01]?\d|2[0-3]',
            'day'=>'0?[1-9]|[12]\d|3[01]',
            'month'=>'[1-9]|1[012]',
            'dow'=>'[0-7]'
        );

        foreach($numbers as $field=>$number) {
            $range= "($number)(-($number)(\/\d+)?)?";
            $field_re[$field]= "\*(\/\d+)?|$range(,$range)*";
        }

        $field_re['month'].='|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec';
        $field_re['dow'].='|mon|tue|wed|thu|fri|sat|sun';

        $fields_re= '('.join(')\s+(', $field_re).')';

        $replacements= '@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly';

        return '^\s*('.
                '$'.
                '|#'.
                '|\w+\s*='.
                "|$fields_re\s+\S".
                "|($replacements)\s+\S".
            ')';
    }
}

Спасибо Jordi Salvat i Alabart, который опубликовал отличное решение.

Я только изменил существующее решение, опубликованное Jordi Salvat i Alabart. Это сработало для меня хорошо, но я хотел извлечь отдельные части, захватив группы. Я добавил не захватывающие скобки, чтобы можно было извлечь отдельные части записи crontab. Легко увидеть, какую группу захвата использовать, когда вы тестируете выходное регулярное выражение в: http://www.regexplanet.com/advanced/java/index.html

<?php
/**
 * @author Jordi Salvat i Alabart - with thanks to <a href="www.salir.com">Salir.com</a>.
 */

function buildRegexp() {
    $numbers = array(
        'min' => '[0-5]?\d',
        'hour' => '[01]?\d|2[0-3]',
        'day' => '0?[1-9]|[12]\d|3[01]',
        'month' => '[1-9]|1[012]',
        'dow' => '[0-6]'
    );

    foreach ($numbers as $field => $number) {
        $range = "(?:$number)(?:-(?:$number)(?:\/\d+)?)?";
        $field_re[$field] = "\*(?:\/\d+)?|$range(?:,$range)*";
    }

    $field_re['month'].='|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec';
    $field_re['dow'].='|mon|tue|wed|thu|fri|sat|sun';

    $fields_re = '(' . join(')\s+(', $field_re) . ')';

    $replacements = '@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly';

    return '^\s*(' .
            '

Этот код генерирует регулярное выражение:

^\s*($|#|\w+\s*=|(\*(?:\/\d+)?|(?:[0-5]?\d)(?:-(?:[0-5]?\d)(?:\/\d+)?)?(?:,(?:[0-5]?\d)(?:-(?:[0-5]?\d)(?:\/\d+)?)?)*)\s+(\*(?:\/\d+)?|(?:[01]?\d|2[0-3])(?:-(?:[01]?\d|2[0-3])(?:\/\d+)?)?(?:,(?:[01]?\d|2[0-3])(?:-(?:[01]?\d|2[0-3])(?:\/\d+)?)?)*)\s+(\*(?:\/\d+)?|(?:0?[1-9]|[12]\d|3[01])(?:-(?:0?[1-9]|[12]\d|3[01])(?:\/\d+)?)?(?:,(?:0?[1-9]|[12]\d|3[01])(?:-(?:0?[1-9]|[12]\d|3[01])(?:\/\d+)?)?)*)\s+(\*(?:\/\d+)?|(?:[1-9]|1[012])(?:-(?:[1-9]|1[012])(?:\/\d+)?)?(?:,(?:[1-9]|1[012])(?:-(?:[1-9]|1[012])(?:\/\d+)?)?)*|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\s+(\*(?:\/\d+)?|(?:[0-6])(?:-(?:[0-6])(?:\/\d+)?)?(?:,(?:[0-6])(?:-(?:[0-6])(?:\/\d+)?)?)*|mon|tue|wed|thu|fri|sat|sun)\s+|(@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly)\s+)([^\s]+)\s+(.*)$

Или альтернатива Java для генерации этого регулярного выражения (без @X):

public static String buildRegex(){
    // numbers intervals and regex
    Map<String, String> numbers = new HashMap<String, String>();
    numbers.put("min", "[0-5]?\\d");
    numbers.put("hour", "[01]?\\d|2[0-3]");
    numbers.put("day", "0?[1-9]|[12]\\d|3[01]");
    numbers.put("month", "[1-9]|1[012]");
    numbers.put("dow", "[0-6]");

    Map<String, String> field_re = new HashMap<String, String>();

    // expand regex to contain different time specifiers
    for(String field : numbers.keySet()){
        String number = numbers.get(field);
        String range = "(?:"+number+")(?:-(?:"+number+")(?:\\/\\d+)?)?";
        field_re.put(field, "\\*(?:\\/\\d+)?|"+range+"(?:,"+range+")*");
    }

    // add string specifiers
    String monthRE = field_re.get("month");
    monthRE = monthRE + "|jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec";
    field_re.put("month", monthRE);

    String dowRE = field_re.get("dow");
    dowRE = dowRE + "|mon|tue|wed|thu|fri|sat|sun";
    field_re.put("dow", dowRE);

    StringBuilder fieldsReSB = new StringBuilder();
    fieldsReSB.append("^\\s*(")
            .append("<*>quot;)
            .append("|#")
            .append("|\\w+\\s*=")
            .append("|");        
            .append("(")
            .append(field_re.get("min")).append(")\\s+(")
            .append(field_re.get("hour")).append(")\\s+(")
            .append(field_re.get("day")).append(")\\s+(")
            .append(field_re.get("month")).append(")\\s+(")
            .append(field_re.get("dow"))
            .append(")")
            .append("\\s+)")
            .append("([^\\s]+)\\s+")
            .append("(.*)<*>quot;);

    return fieldsReSB.toString();
}
. '|#' . '|\w+\s*=' . "|$fields_re\s+" . "|($replacements)\s+" . ')' . '([^\\s]+)\\s+' . '(.*)

Этот код генерирует регулярное выражение:

<*>

Или альтернатива Java для генерации этого регулярного выражения (без @X):

<*>; }

Этот код генерирует регулярное выражение:

<*>

Или альтернатива Java для генерации этого регулярного выражения (без @X):

<*>

Существует хорошая библиотека PHP, которую можно использовать для проверки выражений Cron:

Чтобы установить эту библиотеку через композитор:

composer require mtdowling/cron-expression

Чтобы проверить, действительно ли выражение Cron

$isValid = Cron\CronExpression::isValidExpression($expression);

Вы должны быть в состоянии сделать это довольно легко с помощью регулярных выражений. На самом деле, я не удивлюсь, если вы найдете в Google существующее регулярное выражение. Это не проверено, но, возможно, что-то вроде:

/^((\*)|(\d+((-\d+)|(,\d+)+))\s+){5}/

Спасибо Джорди Сальват и Алабарт и ph4r05.

У меня есть небольшое модифицированное существующее решение, опубликованное на php. Альтернатива Perl для генерации регулярного выражения:

sub _BuildRegex {
    my $number = {
            'min'   =>      '[0-5]?\d',
            'hour'  =>      '[01]?\d|2[0-3]',
            'day'   =>      '0?[1-9]|[12]\d|3[01]',
            'month' =>      '[1-9]|1[012]',
            'dow'   =>      '[0-6]'
    };

    my $field_re = {};
    foreach my $nmb ( qw/min hour day month dow/ ) {
            my $range = "(?:$number->{$nmb})(?:-(?:$number->{$nmb})(?:\\/\\d+)?)?";
            $field_re->{$nmb} = "\\*(?:\\/\\d+)?|$range(?:,$range)*";
    }

    $field_re->{'month'} .='|[jJ]an|[fF]eb|[mM]ar|[aA]pr|[mM]ay|[jJ]un|[jJ]ul|[aA]ug|[sS]ep|[oO]ct|[nN]ov|[dD]ec';
    $field_re->{'dow'} .= '|[mM]on|[tT]ue|[wW]ed|[tT]hu|[fF]ri|[sS]at|[sS]un';

    my $ff = [];
    push @$ff, $field_re->{

Спасибо Джорди Сальват и Алабарт и ph4r05.

У меня есть небольшое модифицированное существующее решение, опубликованное на php. Альтернатива Perl для генерации регулярного выражения:

<*>} foreach ( qw/min hour day month dow/ ); my $fields_req = '(' . join(')\s+(', @$ff) . ')'; my $replacements = '@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly'; return '^\s*(' . ' . '|#' . '|\w+\s*=' . "|$fields_req\\s+" . "|($replacements)\\s+" . ')' . '([^\\s]+)\\s+' . '(.*); }

Используйте шаблон: <Код> / ^ ((: [1-9] \ d | \ *) \ S * ((: [\ / -] [1-9] \ d) | (????? [ 1-9]? \ d) +)? \ S *) {5} $ /

В PHP:

<?php 
$cron = "*/5 1-2 3 3,4,5 *"; 
$result = preg_match( "/^((?:[1-9]?\d|\*)\s*(?:(?:[\/-][1-9]?\d)|(?:,[1-9]?\d)+)?\s*){5}$/", $cron, $matches); 
print_r($matches);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top