문제

PHP로 Crontab 항목을 검증하는 가장 좋은 방법은 무엇입니까? Regex 또는 외부 라이브러리를 사용해야합니까? Crontab 파일에서 항목을 추가/제거하는 PHP 스크립트가 있지만 시간 간격 부분이 유효한 형식인지 확인하는 방법을 원합니다.

도움이 되었습니까?

해결책

흠, 흥미로운 문제.

실제로 검증하려면 Regex가 충분하지 않을 것입니다. 실제로 항목을 구문 분석하고 각 스케줄링 비트를 검증해야합니다. 각 비트가 숫자, 주 1 월/일, 범위 (2-7), 세트 (3, 4, 토요일), vixie cron 스타일 바로 가기 (60/5) 또는 모든 조합 일 수 있기 때문입니다. 위의 내용 중 하나는 단일 REGEX 접근 방식이 매우 털이 많고 빠르게 얻을 것입니다.

그냥 사용합니다 crontab Vixie Cron의 프로그램을 검증하는 프로그램은 충분하지 않습니다. 실제로 완전히 검증되지 않기 때문입니다! 나는 얻을 수있다 crontab 모든 종류의 불법적 인 것들을 받아들입니다.

Dave Taylor의 사악한 쿨 쉘 스크립트 (Google 도서 링크)는 부분 검증을 수행하는 SH 스크립트가 있으며 토론이 흥미로워졌습니다. 코드를 사용하거나 조정할 수도 있습니다.

또한 당신이 말하는 일을하는 두 개의 PHP 클래스에 대한 링크를 나타 냈습니다 (내가 평가하지 않은 품질) :

앱이해야 할 일에 따라 다른 접근 방식은 PHP가 Crontab 항목을 프로그래밍 방식으로 작성하고 삽입하는 것일 수 있으므로 신뢰할 수없는 문자열을 검증하려고 시도하는 대신 항상 유효하다는 것을 알 수 있습니다. 그런 다음 "Crontab 항목 빌드"UI를 만들면됩니다. 실제로 복잡한 스케줄링 조합이 필요하지 않은 경우 간단 할 수 있습니다.

다른 팁

정규 표현이 그렇게 할 수 없다고 누가 말했습니까?

내 고용주의 제공, salir.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 레코드의 특정 부분을 추출 할 수 있도록 비과전 괄호를 추가했습니다. 출력 regex를 테스트 할 때 사용할 캡처 그룹을 쉽게 알 수 있습니다.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*(' .
            '$' .
            '|#' .
            '|\w+\s*=' .
            "|$fields_re\s+" .
            "|($replacements)\s+" .
            ')' .
            '([^\\s]+)\\s+' .
            '(.*)$';
}

이 코드는 Regex를 생성합니다.

^\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+(.*)$

또는 @x 물건 없이이 Regex를 생성하기위한 Java 대안 : :

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("$")
            .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("(.*)$");

    return fieldsReSB.toString();
}

CRON 표현 검증에 사용할 수있는 멋진 PHP 라이브러리가 있습니다.

작곡가를 통해이 라이브러리를 설치하려면 :

composer require mtdowling/cron-expression

Cron 표현이 유효한지 확인하려면

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

Regex와 함께 쉽게 그렇게 할 수 있어야합니다. 사실, Google에서 기존 Regex를 찾을 수 있다면 놀라지 않을 것입니다. 이것은 테스트되지 않았지만 아마도 다음과 같은 것입니다.

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

Jordi Salvat I Alabart와 PH4R05 덕분에 감사합니다.

PHP에 게시 된 소규모 수정 된 기존 솔루션이 있습니다. Regex 생성을위한 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->{$_} 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