CRONの定義の数字部分の解析

  • ちょっと気になったので書いてみた
  • 下記は分を想定したサンプル -- 解析結果は60個の配列。対象の分の部分に1が入る
<?php
// vim: set et ts=4 sw=4 sts=4:

$s = '1,2,5-7,*/5,40-50/2';
$len = 60;
$r = cnv($s, $len);
var_dump(is_array($r) ? implode('', $r) : $r);

function cnv($s, $len)
{
    $res   = array_pad(array(), $len, 0);
    $items = explode(',', $s);
    foreach ($items as $item) {
        $stp = explode('/', $item);
        if (count($stp) > 2) {
            return false;
        }
        $step = (isset($stp[1]) && ctype_digit($stp[1]))
              ? (int)$stp[1]
              : 1;
        if (ctype_digit($stp[0])) {
            $st = (int)$stp[0];
            $ed = $st;
        } elseif ($stp[0] === '*') {
            $st = 0;
            $ed = $len - 1;
        } elseif (strpos($stp[0], '-') !== false) {
            $rng = explode('-', $stp[0]);
            if (count($rng) !== 2
                || !ctype_digit($rng[0])
                || !ctype_digit($rng[1])
            ) {
                return false;
            }
            $st = (int)$rng[0];
            $ed = (int)$rng[1];
        } else {
            return false;
        }
        for ($i = $st; $i <= $ed; $i += $step) {
            $res[$i] = 1;
        }
    }
    return $res;
}
  • なんかすっきりしなかったので別パターン
<?php
$s = '1,2,5-7,*/5,40-50/2';
$len = 60;
$r = cnv($s, $len);
var_dump(is_array($r) ? implode('', $r) : $r);

function cnv($s, $len)
{
    $res   = array_pad(array(), $len, 0);
    $items = explode(',', $s);
    foreach ($items as $item) {
        $stp = explode('/', $item);
        if (count($stp) > 2) {
            return false;
        }
        $step = (isset($stp[1]) && ctype_digit($stp[1]))
              ? (int)$stp[1]
              : 1;
        if ($stp[0] === '*') {
            $stp[0] = sprintf('0-%d', $len - 1);
        }
        $rng = explode('-', $stp[0]);
        if (count($rng) > 2
            || !ctype_digit($rng[0])
            || (isset($rng[1]) && !ctype_digit($rng[1]))
        ) {
            return false;
        }
        $st = (int)$rng[0];
        $ed = isset($rng[1]) ? (int)$rng[1] : $st;
        for ($i = $st; $i <= $ed; $i += $step) {
            $res[$i] = 1;
        }
    }
    return $res;
}
  • 1スタートを忘れてたので対応
  • 間隔を指定する際に数字だけだとフォーマットエラーぽいのでチェックも追加
<?php
$s = '1,2,5-7,*/5,40-50/2';
$len = 60;
$r = cnv($s, $len);
var_dump(is_array($r) ? implode('', $r) : $r);

function cnv($s, $len, $first = 0)
{
    $res   = array_pad(array(), $first + $len, 0);
    $items = explode(',', $s);
    foreach ($items as $item) {
        $stp = explode('/', $item);
        if (count($stp) > 2) {
            return false;
        }
        $step = (isset($stp[1]) && ctype_digit($stp[1]))
              ? (int)$stp[1]
              : 1;
        if ($stp[0] === '*') {
            $stp[0] = sprintf('%d-%d', $first, $len - (1 - $first));
        }
        $rng = explode('-', $stp[0]);
        if (count($rng) > 2
            || !ctype_digit($rng[0])
            || (isset($rng[1]) && !ctype_digit($rng[1]))
            || (!isset($rng[1]) && strpos($item, '/') !== false) 
        ) {
            return false;
        }
        $st = (int)$rng[0];
        $ed = isset($rng[1]) ? (int)$rng[1] : $st;
        for ($i = $st; $i <= $ed; $i += $step) {
            $res[$i] = 1;
        }
    }
    return array_slice($res, $first, $len);
}

参考

  • まぁ、あるよね -- https://github.com/mtdowling/cron-expression

  • Prev
  • CVE-2012-0053 Next