Crontab başlıklar w / PHP doğrulanıyor

4 Cevap php

PHP ile bir crontab girişi doğrulamak için en iyi yolu nedir? Ben bir regex, veya harici bir kütüphaneyi kullanarak olmalıdır? Ben bir crontab dosyasındaki girdileri kaldırır / ekleyen bir PHP komut dosyası var, ama zaman aralığı kısmı biçimi geçerli olduğunu doğrulamak için bir yol istiyorum ettik.

4 Cevap

Hmmm, ilginç bir sorun.

Eğer gerçekten bunu doğrulamak için gidiyoruz eğer, regex aslında girişi ayrıştırmak ve zamanlama bit her doğrulamak gerekir, yeterli olacak değildir. Her bit bir dizi, bir ay / hafta dize gün, bir aralık (2-7), bir dizi (3, 4, Cumartesi), bir Vixie cron tarzı kısayol (60/5) veya herhangi bir kombinasyonu olabilir, çünkü o Yukarıda - tek bir regex yaklaşım hızlı, çok kıllı almak için gidiyor.

Aslında tamamen doğrulamak değil, çünkü sadece doğrulamak için Vixie cron'nun crontab programı kullanarak, yeterli değildir! I crontab illegal her türlü şeyi kabul alabilirsiniz.

Dave Taylor'un Wicked Serin Shell Script (Google books link) kısmi doğrulama yapan bir sh komut dosyası var, ben tartışma ilginç buldum. Da kullanabilir veya kodunu adapte olabilir.

Ben de size (olan kalite ben değerlendirilir değil) demek ne iki PHP sınıfları bağlantılar döndü:

(App yapmak gerekiyor ne bağlı) Başka bir yaklaşım PHP programlama crontab girdisi oluşturmak ve eklemek için olabilir, o yüzden her zaman geçerli olduğunu biliyorum, yerine güvenilmeyen bir dize doğrulamaya çalışın. Sonra sadece gerçekten karmaşık zamanlama kombinasyonları gerek yoksa basit olabilir, bir "bir crontab girdisi oluşturmak" UI, yapmak gerekir.

Kim düzenli ifadeler yapamam dedi?

Benim işveren izniyle, Salir.com, burada böyle doğrulama yapan bir PHPUnit test. Ve değiştirmek için çekinmeyin dağıtmak. Eğer @ yazar bildirimi tutmak ve ben takdir edeceksiniz web sitesine bağlantı.

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

Harika bir çözüm yayınlanmıştır Jordi Salvat i Alabart için teşekkürler.

I have only modified existing solution posted by Jordi Salvat i Alabart. It worked for me well, but I wanted to extract particular parts by capturing groups. I have added non-capturing parentheses to be able to extract particular parts of crontab record. It is easy to see which capture group to use when you test output regex at: 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+' .
            '(.*)$';
}

Bu kod regex oluşturur:

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

Veya Java alternatif (@ X şeyler olmadan) bu regex oluşturmak için:

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

Sen regex ile oldukça kolay bunu mümkün olmalıdır. Aslında, ben sadece bunu Google'da için varolan bir regex bulabiliriz eğer sürpriz olmaz. Bu denenmemiş, ama belki bir şey gibidir:

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