Frage

Was ist der beste Weg, um einen crontab-Eintrag mit PHP zu validieren? Soll ich einen regulären Ausdruck oder eine externe Bibliothek verwenden? Ich habe einen PHP-Skript bekomme, das Hinzufügen / Entfernen von Einträgen aus einer crontab-Datei, will aber eine Möglichkeit haben, um sicherzustellen, dass das Zeitintervall Teil in einem gültigen Format ist.

War es hilfreich?

Lösung

Hmmm, interessantes Problem.

Wenn Sie vorhaben, es wirklich zu validieren, regex wird nicht genug sein, müssen Sie tatsächlich den Eintrag analysieren und jede der Scheduling-Bits zu validieren. Das ist, weil jedes Bit kann eine Zahl sein, ein Monat / Tag der Woche Schnur, ein Bereich (2-7), ein Satz (3, 4, Samstag), eine Vixie cron-style-Verknüpfung (60/5) oder ein beliebige Kombination der oben - jeder einzelner Regex Ansatz wird sehr haarig bekommen, schnell

.

Nur mit dem crontab Programm von Vixie Cron ist zur Validierung nicht ausreichend, weil es eigentlich nicht vollständig validiert! Ich kann crontab bekommen, um alle Arten von illegalen Dingen zu akzeptieren.

Dave Taylor Wicked Cool Shell Scripts ( Google Bücher verknüpfen ) hat ein sh-Skript, das Teil-Validierung der Fall ist, ich die Diskussion interessant fand. Vielleicht haben Sie auch den Code verwenden oder anpassen.

Ich drehte auch Links zu zwei PHP-Klassen auf, die tun, was Sie sagen, (deren Qualität ich habe nicht bewertet):

Ein weiterer Ansatz (je nachdem, was Ihre Anwendung tun muss) könnte sein, PHP, um den crontab-Eintrag konstruieren zu haben, programmatisch und setzen Sie sich, damit Sie wissen, es ist immer gültig, anstatt zu versuchen, eine nicht vertrauenswürdige Zeichenfolge zu validieren. Dann müssen Sie nur eine „Aufbau einen crontab-Eintrags“ UI zu machen, die einfach sein könnten, wenn Sie nicht wirklich kompliziert Scheduling-Kombinationen benötigen.

Andere Tipps

Wer hat gesagt, regulärer Ausdrücke kann das nicht tun?

Mit freundlicher Genehmigung von meinem Arbeitgeber, Salir.com , hier ist ein PHPUnit-Test, der eine solche Validierung der Fall ist. Fühlen Sie sich frei zu modifizieren und zu verteilen. Ich werde es begrüßen, wenn Sie die @author Ankündigung & Link zur Website halten.

<?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".
            ')';
    }
}

Dank Jordi Salvat i Alabart die große Lösung geschrieben.

Ich habe nur bestehende Lösung von Jordi Salvat i Alabart geschrieben geändert. Es funktionierte gut für mich, aber ich wollte bestimmte Teile durch die Erfassung Gruppen extrahieren. Ich habe nicht-Capturing Klammern hinzugefügt, um der Lage sein, bestimmte Teile von crontab Akte zu extrahieren. Es ist leicht, das Capture-Gruppe zu verwenden, um zu sehen, wenn Sie die Ausgabe regex Test an: 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+' .
            '(.*)$';
}

Dieser Code erzeugt 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+(.*)$

oder Java-Alternative diese regex zu erzeugen (ohne @X Sachen):

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();
}

Es gibt eine schöne PHP-Bibliothek, die für Cron Ausdruck Validierung verwendet werden kann:

Um diese Bibliothek über Komponisten zu installieren:

composer require mtdowling/cron-expression

Um zu überprüfen, ob Cron Ausdruck gültig ist

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

Es sollte möglich sein, dass relativ leicht mit Regex zu tun. In der Tat wäre ich nicht überrascht, wenn Sie einen vorhandenen Regex nur für diese auf Google finden können. Dies ist nicht getestet, aber vielleicht so etwas wie:

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

Dank Jordi Salvat i Alabart und ph4r05.

Ich habe kleine modifizierte bestehende Lösung auf PHP geschrieben. Perl Alternative zu erzeugen regex:

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+' .
         '(.*)$';
}

Verwenden Sie das Muster: /^((?:[1-9]?\d|\*)\s*(?:(?:[\/-][1-9]?\d)|(?:,[1-9]?\d)+)?\s*){5}$/

In 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);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top