Skip to content

Commit 1130ae4

Browse files
committed
feat: add cron segment validator
1 parent 55450c9 commit 1130ae4

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

src/Validator.php

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
3+
namespace Ahc\Cron;
4+
5+
/**
6+
* Cron segment validator.
7+
*
8+
* This class checks if a cron segment is valid.
9+
*
10+
* @author Jitendra Adhikari <[email protected]>
11+
*/
12+
class Validator
13+
{
14+
public function inRange($value, $offset)
15+
{
16+
$parts = \explode('-', $offset);
17+
18+
return $parts[0] <= $value && $value <= $parts[1];
19+
}
20+
21+
public function inStep($value, $offset)
22+
{
23+
if (\strpos($offset, '*/') !== false || \strpos($offset, '0/') !== false) {
24+
$parts = \explode('/', $offset, 2);
25+
26+
return $value % $parts[1] === 0;
27+
}
28+
29+
$parts = \explode('/', $offset, 2);
30+
$subparts = \explode('-', $parts[0], 2) + [1 => $value];
31+
32+
return ($subparts[0] <= $value && $value <= $subparts[1] && $parts[1])
33+
? \in_array($value, \range($subparts[0], $subparts[1], $parts[1]))
34+
: false;
35+
}
36+
37+
/**
38+
* Check if month modifiers [L C W #] are satisfied.
39+
*
40+
* @internal
41+
*
42+
* @param string $value
43+
* @param array $time
44+
*
45+
* @return bool|null
46+
*/
47+
public function isValidMonthDay($value, $time)
48+
{
49+
if ($value == 'L') {
50+
return $time[2] == $time[6];
51+
}
52+
53+
if ($pos = \strpos($value, 'W')) {
54+
$value = \substr($value, 0, $pos);
55+
$month = \str_pad($time[8], 2, '0', \STR_PAD_LEFT);
56+
57+
return $this->isClosestWeekDay($value, $month, $time);
58+
}
59+
}
60+
61+
protected function isClosestWeekDay($value, $month, $time)
62+
{
63+
foreach ([0, -1, 1, -2, 2] as $i) {
64+
$incr = $value + $i;
65+
if ($incr < 1 || $incr > $time[6]) {
66+
continue;
67+
}
68+
69+
$incr = \str_pad($incr, 2, '0', \STR_PAD_LEFT);
70+
$parts = \explode(' ', \date('N m j', \strtotime("{$time[5]}-$month-$incr")));
71+
if ($parts[0] < 6 && $parts[1] == $month) {
72+
return $time[2] == $parts[2];
73+
}
74+
}
75+
76+
// @codeCoverageIgnoreStart
77+
return false;
78+
// @codeCoverageIgnoreEnd
79+
}
80+
81+
/**
82+
* Check if week modifiers [L C W #] are satisfied.
83+
*
84+
* @internal
85+
*
86+
* @param string $value
87+
* @param array $time
88+
*
89+
* @return bool|null
90+
*/
91+
public function isValidWeekDay($value, $time)
92+
{
93+
$month = \str_pad($time[8], 2, '0', \STR_PAD_LEFT);
94+
95+
if (\strpos($value, 'L')) {
96+
return $this->lastWeekDay($value, $month, $time);
97+
}
98+
99+
if (\strpos($value, '#')) {
100+
$value = \explode('#', \str_replace('0#', '7#', $value));
101+
102+
if ($value[0] < 0 || $value[0] > 7 || $value[1] < 1 || $value[1] > 5 || $time[9] != $value[0]) {
103+
return false;
104+
}
105+
106+
return \intval($time[7] / 7) == $value[1] - 1;
107+
}
108+
109+
// @codeCoverageIgnoreStart
110+
return false;
111+
// @codeCoverageIgnoreEnd
112+
}
113+
114+
protected function lastWeekDay($value, $month, $time)
115+
{
116+
$value = \explode('L', \str_replace('7L', '0L', $value));
117+
$decr = $time[6];
118+
119+
for ($i = 0; $i < 7; $i++) {
120+
$decr -= $i;
121+
if (\date('w', \strtotime("{$time[5]}-$month-$decr")) == $value[0]) {
122+
return $time[2] == $decr;
123+
}
124+
}
125+
126+
return false;
127+
}
128+
}

0 commit comments

Comments
 (0)