Skip to content

Instantly share code, notes, and snippets.

@connordavison
Created July 13, 2018 09:52
Show Gist options
  • Save connordavison/0dff5d6439c082e3e75b49a548916898 to your computer and use it in GitHub Desktop.
Save connordavison/0dff5d6439c082e3e75b49a548916898 to your computer and use it in GitHub Desktop.
CronHelper
<?php
/**
* A helper class for cronjobs.
*
* @author C. Davison
*/
class CronHelper
{
/**
* Valid & unique date format strings for each type of cron part.
* @const MINUTE
* @const HOUR
* @const DAY_OF_MONTH
* @const MONTH
* @const DAY_OF_WEEK
* @see http://php.net/manual/en/function.date.php
*/
const MINUTE = 'i';
const HOUR = 'H';
const DAY_OF_MONTH = 'd';
const MONTH = 'm';
const DAY_OF_WEEK = 'N';
/**
* The default order of a cron, expressed as an array of datetime formats.
* @static array
*/
static $part_order = array(
self::MINUTE,
self::HOUR,
self::DAY_OF_MONTH,
self::MONTH,
self::DAY_OF_WEEK
);
/**
* Match a cron to a datetime.
*
* @param array $cron A list of valid cron expressions in the order given
* by $part_order.
* @param \DateTime $datetime The DateTime to be matched.
* @param array [$part_order=false] The order of the cron parts. If false,
* this defaults to CronHelper::$part_order.
* @see CronHelper::matchPart
* @see CronHelper::$part_order
*/
static function match(
array $cron,
\DateTime $datetime,
$part_order = false
) {
if (count($cron) !== count($part_order)) {
throw new \LengthException(
'Length of $cron does not match number of cron parts.'
);
}
// If no order is specified, use the default order
if (!$part_order) {
$part_order = self::$part_order;
}
// Run through the cron and attempt to match each part to its
// corresponding datetime part
for ($i = 0; $i < count($part_order); $i++) {
$cron_part = $cron[$i];
$part_type = $part_order[$i];
$datetime_part = $datetime->format($part_type);
// If the parts cannot be matched, the whole cron cannot be matched
if (!self::matchPart($cron_part, $datetime_part, $part_type)) {
return false;
}
}
return true;
}
/**
* Match a cron part to a part of a timestamp. This presently allows
* standard cron expressions including:
* - '*': matches all values
* - ',': for listing values (e.g., 5,10,20)
* - '-': for ranges (e.g. 2010-2015)
*
* @param mixed $cron_part The cron part to match.
* @param mixed $datetime_part The datetime part to match. This should be
* numerical, and not a textual representation.
*/
static function matchPart($cron_part, $datetime_part)
{
if ($cron_part === '*') return true;
$subparts = explode(',', $cron_part);
foreach ($subparts as $subpart) {
if ($subpart === '*') continue;
// If there's a hyphen in this subpart, it represents a range of
// values
if (strpos($subpart, '-') !== false) {
$subpart = explode('-', $subpart);
$end = $subpart[1];
$start = $subpart[0];
if ($datetime_part > $start && $datetime_part < $end) continue;
else return false;
}
if ($subpart === $datetime_part) continue;
// If we get here, the cron part has failed to match the datetime
// part
return false;
}
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment