‪TYPO3CMS  ‪main
NormalizeCommand.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * This file is part of the TYPO3 CMS project.
5  *
6  * It is free software; you can redistribute it and/or modify it under
7  * the terms of the GNU General Public License, either version 2
8  * of the License, or any later version.
9  *
10  * For the full copyright and license information, please read the
11  * LICENSE.txt file that was distributed with this source code.
12  *
13  * The TYPO3 project - inspiring people to share!
14  */
15 
17 
19 
28 {
40  public static function ‪normalize($cronCommand)
41  {
42  $cronCommand = trim($cronCommand);
43  $cronCommand = ‪self::convertKeywordsToCronCommand($cronCommand);
44  $cronCommand = ‪self::normalizeFields($cronCommand);
45  return $cronCommand;
46  }
47 
55  protected static function ‪convertKeywordsToCronCommand($cronCommand)
56  {
57  switch ($cronCommand) {
58  case '@yearly':
59  case '@annually':
60  $cronCommand = '0 0 1 1 *';
61  break;
62  case '@monthly':
63  $cronCommand = '0 0 1 * *';
64  break;
65  case '@weekly':
66  $cronCommand = '0 0 * * 0';
67  break;
68  case '@daily':
69 
70  case '@midnight':
71  $cronCommand = '0 0 * * *';
72  break;
73  case '@hourly':
74  $cronCommand = '0 * * * *';
75  break;
76  }
77  return $cronCommand;
78  }
79 
86  protected static function ‪normalizeFields($cronCommand)
87  {
88  $fieldArray = ‪self::splitFields($cronCommand);
89  $fieldArray[0] = ‪self::normalizeIntegerField($fieldArray[0], 0, 59);
90  $fieldArray[1] = ‪self::normalizeIntegerField($fieldArray[1], 0, 23);
91  $fieldArray[2] = ‪self::normalizeIntegerField($fieldArray[2], 1, 31);
92  $fieldArray[3] = ‪self::normalizeMonthAndWeekdayField($fieldArray[3], true);
93  $fieldArray[4] = ‪self::normalizeMonthAndWeekdayField($fieldArray[4], false);
94  $normalizedCronCommand = implode(' ', $fieldArray);
95  return $normalizedCronCommand;
96  }
97 
105  protected static function ‪splitFields($cronCommand)
106  {
107  ‪$fields = explode(' ', $cronCommand);
108  if (count(‪$fields) !== 5) {
109  throw new \InvalidArgumentException('Unable to split given cron command to five fields.', 1291227373);
110  }
111  return ‪$fields;
112  }
113 
121  protected static function ‪normalizeMonthAndWeekdayField($expression, $isMonthField = true)
122  {
123  if ((string)$expression === '*') {
124  $fieldValues = '*';
125  } else {
126  // Fragment expression by , / and - and substitute three letter code of month and weekday to numbers
127  $listOfCommaValues = explode(',', $expression);
128  $fieldArray = [];
129  foreach ($listOfCommaValues as $listElement) {
130  if (str_contains($listElement, '/')) {
131  [$left, $right] = explode('/', $listElement);
132  if (str_contains($left, '-')) {
133  [$leftBound, $rightBound] = explode('-', $left);
134  $leftBound = ‪self::normalizeMonthAndWeekday($leftBound, $isMonthField);
135  $rightBound = ‪self::normalizeMonthAndWeekday($rightBound, $isMonthField);
136  $left = $leftBound . '-' . $rightBound;
137  } else {
138  if ((string)$left !== '*') {
139  $left = ‪self::normalizeMonthAndWeekday($left, $isMonthField);
140  }
141  }
142  $fieldArray[] = $left . '/' . $right;
143  } elseif (str_contains($listElement, '-')) {
144  [$left, $right] = explode('-', $listElement);
145  $left = ‪self::normalizeMonthAndWeekday($left, $isMonthField);
146  $right = ‪self::normalizeMonthAndWeekday($right, $isMonthField);
147  $fieldArray[] = $left . '-' . $right;
148  } else {
149  $fieldArray[] = ‪self::normalizeMonthAndWeekday($listElement, $isMonthField);
150  }
151  }
152  $fieldValues = implode(',', $fieldArray);
153  }
154  return $isMonthField ? ‪self::normalizeIntegerField($fieldValues, 1, 12) : ‪self::normalizeIntegerField($fieldValues, 1, 7);
155  }
156 
166  protected static function ‪normalizeIntegerField($expression, $lowerBound = 0, $upperBound = 59)
167  {
168  if ((string)$expression === '*') {
169  $fieldValues = '*';
170  } else {
171  $listOfCommaValues = explode(',', $expression);
172  $fieldArray = [];
173  foreach ($listOfCommaValues as $listElement) {
174  if (str_contains($listElement, '/')) {
175  [$left, $right] = explode('/', $listElement);
176  if ((string)$left === '*') {
177  $leftList = ‪self::convertRangeToListOfValues($lowerBound . '-' . $upperBound);
178  } else {
179  $leftList = ‪self::convertRangeToListOfValues($left);
180  }
181  $fieldArray[] = ‪self::reduceListOfValuesByStepValue($leftList . '/' . $right);
182  } elseif (str_contains($listElement, '-')) {
183  $fieldArray[] = ‪self::convertRangeToListOfValues($listElement);
184  } elseif (‪MathUtility::canBeInterpretedAsInteger($listElement)) {
185  $fieldArray[] = $listElement;
186  } elseif (strlen($listElement) === 2 && $listElement[0] === '0') {
187  $fieldArray[] = (int)$listElement;
188  } else {
189  throw new \InvalidArgumentException('Unable to normalize integer field.', 1291429389);
190  }
191  }
192  $fieldValues = implode(',', $fieldArray);
193  }
194  if ((string)$fieldValues === '') {
195  throw new \InvalidArgumentException('Unable to convert integer field to list of values: Result list empty.', 1291422012);
196  }
197  if ((string)$fieldValues !== '*') {
198  $fieldList = explode(',', $fieldValues);
199  sort($fieldList);
200  $fieldList = array_unique($fieldList);
201  if (current($fieldList) < $lowerBound) {
202  throw new \InvalidArgumentException('Lowest element in list is smaller than allowed.', 1291470084);
203  }
204  if (end($fieldList) > $upperBound) {
205  throw new \InvalidArgumentException('An element in the list is higher than allowed.', 1291470170);
206  }
207  $fieldValues = implode(',', $fieldList);
208  }
209  return (string)$fieldValues;
210  }
211 
219  protected static function ‪convertRangeToListOfValues($range)
220  {
221  if ((string)$range === '') {
222  throw new \InvalidArgumentException('Unable to convert range to list of values with empty string.', 1291234985);
223  }
224  $rangeArray = explode('-', $range);
225  // Sanitize fields and cast to integer
226  foreach ($rangeArray as $fieldNumber => $fieldValue) {
227  if (!‪MathUtility::canBeInterpretedAsInteger($fieldValue)) {
228  throw new \InvalidArgumentException('Unable to convert value to integer.', 1291237668);
229  }
230  $rangeArray[$fieldNumber] = (int)$fieldValue;
231  }
232 
233  $rangeArrayCount = count($rangeArray);
234  if ($rangeArrayCount === 1) {
235  $resultList = $rangeArray[0];
236  } elseif ($rangeArrayCount === 2) {
237  $left = $rangeArray[0];
238  $right = $rangeArray[1];
239  if ($left > $right) {
240  throw new \InvalidArgumentException('Unable to convert range to list: Left integer must not be greater than right integer.', 1291237145);
241  }
242  $resultListArray = [];
243  for ($i = $left; $i <= $right; $i++) {
244  $resultListArray[] = $i;
245  }
246  $resultList = implode(',', $resultListArray);
247  } else {
248  throw new \InvalidArgumentException('Unable to convert range to list of values.', 1291234986);
249  }
250  return (string)$resultList;
251  }
252 
263  protected static function ‪reduceListOfValuesByStepValue($stepExpression)
264  {
265  if ($stepExpression === '') {
266  throw new \InvalidArgumentException('Unable to convert step values.', 1291234987);
267  }
268  $stepValuesAndStepArray = explode('/', $stepExpression);
269  $stepValuesAndStepArrayCount = count($stepValuesAndStepArray);
270  if ($stepValuesAndStepArrayCount < 1 || $stepValuesAndStepArrayCount > 2) {
271  throw new \InvalidArgumentException('Unable to convert step values: Multiple slashes found.', 1291242168);
272  }
273  $left = $stepValuesAndStepArray[0] ?? '';
274  $right = $stepValuesAndStepArray[1] ?? '';
275  if ($left === '') {
276  throw new \InvalidArgumentException('Unable to convert step values: Left part of / is empty.', 1291414955);
277  }
278  if ($right === '') {
279  throw new \InvalidArgumentException('Unable to convert step values: Right part of / is empty.', 1291414956);
280  }
282  throw new \InvalidArgumentException('Unable to convert step values: Right part must be a single integer.', 1291414957);
283  }
284  $right = (int)$right;
285  $leftArray = explode(',', $left);
286  $validValues = [];
287  $currentStep = $right;
288  foreach ($leftArray as $leftValue) {
290  throw new \InvalidArgumentException('Unable to convert step values: Left part must be a single integer or comma separated list of integers.', 1291414958);
291  }
292  if ($currentStep === 0) {
293  $currentStep = $right;
294  }
295  if ($currentStep === $right) {
296  $validValues[] = (int)$leftValue;
297  }
298  $currentStep--;
299  }
300  if (empty($validValues)) {
301  throw new \InvalidArgumentException('Unable to convert step values: Result value list is empty.', 1291414959);
302  }
303  return implode(',', $validValues);
304  }
305 
313  protected static function ‪normalizeMonthAndWeekday($expression, $isMonth = true)
314  {
315  $expression = $isMonth ? ‪self::normalizeMonth($expression) : ‪self::normalizeWeekday($expression);
316  return (string)$expression;
317  }
318 
327  protected static function ‪normalizeMonth($month)
328  {
329  ‪$timestamp = strtotime('2010-' . $month . '-01');
330  // timestamp must be >= 2010-01-01 and <= 2010-12-01
331  if (!‪$timestamp || ‪$timestamp < strtotime('2010-01-01') || ‪$timestamp > strtotime('2010-12-01')) {
332  throw new \InvalidArgumentException('Unable to convert given month name.', 1291083486);
333  }
334  return (int)date('n', ‪$timestamp);
335  }
336 
345  protected static function ‪normalizeWeekday($weekday)
346  {
347  $normalizedWeekday = false;
348  // 0 (sunday) -> 7
349  if ((string)$weekday === '0') {
350  $weekday = 7;
351  }
352  if ($weekday >= 1 && $weekday <= 7) {
353  $normalizedWeekday = (int)$weekday;
354  }
355  if (!$normalizedWeekday) {
356  // Convert string representation like 'sun' to integer
357  ‪$timestamp = strtotime('next ' . $weekday, (int)mktime(0, 0, 0, 1, 1, 2010));
358  if (!‪$timestamp || ‪$timestamp < strtotime('2010-01-01') || ‪$timestamp > strtotime('2010-01-08')) {
359  throw new \InvalidArgumentException('Unable to convert given weekday name.', 1291163589);
360  }
361  $normalizedWeekday = (int)date('N', ‪$timestamp);
362  }
363  return $normalizedWeekday;
364  }
365 }
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\normalizeMonth
‪static int normalizeMonth($month)
Definition: NormalizeCommand.php:327
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\normalize
‪static string normalize($cronCommand)
Definition: NormalizeCommand.php:40
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\reduceListOfValuesByStepValue
‪static string reduceListOfValuesByStepValue($stepExpression)
Definition: NormalizeCommand.php:263
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand
Definition: NormalizeCommand.php:28
‪TYPO3\CMS\Scheduler\CronCommand\CronCommand\$timestamp
‪int $timestamp
Definition: CronCommand.php:46
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\normalizeMonthAndWeekdayField
‪static string normalizeMonthAndWeekdayField($expression, $isMonthField=true)
Definition: NormalizeCommand.php:121
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\convertRangeToListOfValues
‪static string convertRangeToListOfValues($range)
Definition: NormalizeCommand.php:219
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\normalizeIntegerField
‪static string normalizeIntegerField($expression, $lowerBound=0, $upperBound=59)
Definition: NormalizeCommand.php:166
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\normalizeFields
‪static string normalizeFields($cronCommand)
Definition: NormalizeCommand.php:86
‪$fields
‪$fields
Definition: pages.php:5
‪TYPO3\CMS\Core\Utility\MathUtility\canBeInterpretedAsInteger
‪static bool canBeInterpretedAsInteger(mixed $var)
Definition: MathUtility.php:69
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\normalizeMonthAndWeekday
‪static string normalizeMonthAndWeekday($expression, $isMonth=true)
Definition: NormalizeCommand.php:313
‪TYPO3\CMS\Scheduler\CronCommand
Definition: CronCommand.php:16
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\splitFields
‪static array splitFields($cronCommand)
Definition: NormalizeCommand.php:105
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\normalizeWeekday
‪static int normalizeWeekday($weekday)
Definition: NormalizeCommand.php:345
‪TYPO3\CMS\Core\Utility\MathUtility
Definition: MathUtility.php:24
‪TYPO3\CMS\Scheduler\CronCommand\NormalizeCommand\convertKeywordsToCronCommand
‪static string convertKeywordsToCronCommand($cronCommand)
Definition: NormalizeCommand.php:55