#!/usr/bin/env php
<?php

class CrontabChecker {
    /**
     * @author Jordi Salvat i Alabart - with thanks to <a href="www.salir.com">Salir.com</a>.
     */
    public function checkCronFile($file) {
        $f = @fopen($file, 'rb', 1);
        $i = 0;
        while (($line= fgets($f)) !== false) {
            $i++;
            if (!$this->checkLine($line)) {
                return [false, $i];
            }
        }
        return [true];
    }

    protected function checkLine($line) {
        $regexp= $this->buildRegexp();
        return 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".
            ')';
    }
}

echo "Crontab Checker searches project root and ./deploy/* for files prefixed with .crontab and validates syntax. \n";

$checker = new CrontabChecker();
$files = array_merge(glob('./.crontab*'),glob("./deploy/{,*/,*/*/,*/*/*/}.crontab*", GLOB_BRACE));

foreach ($files as $file) {
    echo 'Checking file: ' . $file . "\n";
    $result = $checker->checkCronFile($file);
    if ($result[0]) {
        echo "Crontab validation passed! \n";
    } else {
        echo 'Crontab ERROR: line #'. $result[1] . "\n";
        exit(1);
    }
}
