[ Index ]

PHP Cross Reference of Joomla 4.2.2 documentation

title

Body

[close]

/libraries/vendor/dragonmantank/cron-expression/src/Cron/ -> AbstractField.php (source)

   1  <?php
   2  
   3  declare(strict_types=1);
   4  
   5  namespace Cron;
   6  
   7  use DateTimeInterface;
   8  
   9  /**
  10   * Abstract CRON expression field.
  11   */
  12  abstract class AbstractField implements FieldInterface
  13  {
  14      /**
  15       * Full range of values that are allowed for this field type.
  16       *
  17       * @var array
  18       */
  19      protected $fullRange = [];
  20  
  21      /**
  22       * Literal values we need to convert to integers.
  23       *
  24       * @var array
  25       */
  26      protected $literals = [];
  27  
  28      /**
  29       * Start value of the full range.
  30       *
  31       * @var int
  32       */
  33      protected $rangeStart;
  34  
  35      /**
  36       * End value of the full range.
  37       *
  38       * @var int
  39       */
  40      protected $rangeEnd;
  41  
  42      /**
  43       * Constructor
  44       */
  45      public function __construct()
  46      {
  47          $this->fullRange = range($this->rangeStart, $this->rangeEnd);
  48      }
  49  
  50      /**
  51       * Check to see if a field is satisfied by a value.
  52       *
  53       * @internal
  54       * @param int $dateValue Date value to check
  55       * @param string $value Value to test
  56       *
  57       * @return bool
  58       */
  59      public function isSatisfied(int $dateValue, string $value): bool
  60      {
  61          if ($this->isIncrementsOfRanges($value)) {
  62              return $this->isInIncrementsOfRanges($dateValue, $value);
  63          }
  64  
  65          if ($this->isRange($value)) {
  66              return $this->isInRange($dateValue, $value);
  67          }
  68  
  69          return '*' === $value || $dateValue === (int) $value;
  70      }
  71  
  72      /**
  73       * Check if a value is a range.
  74       *
  75       * @internal
  76       * @param string $value Value to test
  77       *
  78       * @return bool
  79       */
  80      public function isRange(string $value): bool
  81      {
  82          return false !== strpos($value, '-');
  83      }
  84  
  85      /**
  86       * Check if a value is an increments of ranges.
  87       *
  88       * @internal
  89       * @param string $value Value to test
  90       *
  91       * @return bool
  92       */
  93      public function isIncrementsOfRanges(string $value): bool
  94      {
  95          return false !== strpos($value, '/');
  96      }
  97  
  98      /**
  99       * Test if a value is within a range.
 100       *
 101       * @internal
 102       * @param int $dateValue Set date value
 103       * @param string $value Value to test
 104       *
 105       * @return bool
 106       */
 107      public function isInRange(int $dateValue, $value): bool
 108      {
 109          $parts = array_map(
 110              function ($value) {
 111                  $value = trim($value);
 112  
 113                  return $this->convertLiterals($value);
 114              },
 115              explode('-', $value, 2)
 116          );
 117  
 118          return $dateValue >= $parts[0] && $dateValue <= $parts[1];
 119      }
 120  
 121      /**
 122       * Test if a value is within an increments of ranges (offset[-to]/step size).
 123       *
 124       * @internal
 125       * @param int $dateValue Set date value
 126       * @param string $value Value to test
 127       *
 128       * @return bool
 129       */
 130      public function isInIncrementsOfRanges(int $dateValue, string $value): bool
 131      {
 132          $chunks = array_map('trim', explode('/', $value, 2));
 133          $range = $chunks[0];
 134          $step = $chunks[1] ?? 0;
 135  
 136          // No step or 0 steps aren't cool
 137          /** @phpstan-ignore-next-line */
 138          if (null === $step || '0' === $step || 0 === $step) {
 139              return false;
 140          }
 141  
 142          // Expand the * to a full range
 143          if ('*' === $range) {
 144              $range = $this->rangeStart . '-' . $this->rangeEnd;
 145          }
 146  
 147          // Generate the requested small range
 148          $rangeChunks = explode('-', $range, 2);
 149          $rangeStart = (int) $rangeChunks[0];
 150          $rangeEnd = $rangeChunks[1] ?? $rangeStart;
 151          $rangeEnd = (int) $rangeEnd;
 152  
 153          if ($rangeStart < $this->rangeStart || $rangeStart > $this->rangeEnd || $rangeStart > $rangeEnd) {
 154              throw new \OutOfRangeException('Invalid range start requested');
 155          }
 156  
 157          if ($rangeEnd < $this->rangeStart || $rangeEnd > $this->rangeEnd || $rangeEnd < $rangeStart) {
 158              throw new \OutOfRangeException('Invalid range end requested');
 159          }
 160  
 161          // Steps larger than the range need to wrap around and be handled
 162          // slightly differently than smaller steps
 163  
 164          // UPDATE - This is actually false. The C implementation will allow a
 165          // larger step as valid syntax, it never wraps around. It will stop
 166          // once it hits the end. Unfortunately this means in future versions
 167          // we will not wrap around. However, because the logic exists today
 168          // per the above documentation, fixing the bug from #89
 169          if ($step > $this->rangeEnd) {
 170              $thisRange = [$this->fullRange[$step % \count($this->fullRange)]];
 171          } else {
 172              if ($step > ($rangeEnd - $rangeStart)) {
 173                  $thisRange[$rangeStart] = (int) $rangeStart;
 174              } else {
 175                  $thisRange = range($rangeStart, $rangeEnd, (int) $step);
 176              }
 177          }
 178  
 179          return \in_array($dateValue, $thisRange, true);
 180      }
 181  
 182      /**
 183       * Returns a range of values for the given cron expression.
 184       *
 185       * @param string $expression The expression to evaluate
 186       * @param int $max Maximum offset for range
 187       *
 188       * @return array
 189       */
 190      public function getRangeForExpression(string $expression, int $max): array
 191      {
 192          $values = [];
 193          $expression = $this->convertLiterals($expression);
 194  
 195          if (false !== strpos($expression, ',')) {
 196              $ranges = explode(',', $expression);
 197              $values = [];
 198              foreach ($ranges as $range) {
 199                  $expanded = $this->getRangeForExpression($range, $this->rangeEnd);
 200                  $values = array_merge($values, $expanded);
 201              }
 202  
 203              return $values;
 204          }
 205  
 206          if ($this->isRange($expression) || $this->isIncrementsOfRanges($expression)) {
 207              if (!$this->isIncrementsOfRanges($expression)) {
 208                  [$offset, $to] = explode('-', $expression);
 209                  $offset = $this->convertLiterals($offset);
 210                  $to = $this->convertLiterals($to);
 211                  $stepSize = 1;
 212              } else {
 213                  $range = array_map('trim', explode('/', $expression, 2));
 214                  $stepSize = $range[1] ?? 0;
 215                  $range = $range[0];
 216                  $range = explode('-', $range, 2);
 217                  $offset = $range[0];
 218                  $to = $range[1] ?? $max;
 219              }
 220              $offset = '*' === $offset ? $this->rangeStart : $offset;
 221              if ($stepSize >= $this->rangeEnd) {
 222                  $values = [$this->fullRange[$stepSize % \count($this->fullRange)]];
 223              } else {
 224                  for ($i = $offset; $i <= $to; $i += $stepSize) {
 225                      $values[] = (int) $i;
 226                  }
 227              }
 228              sort($values);
 229          } else {
 230              $values = [$expression];
 231          }
 232  
 233          return $values;
 234      }
 235  
 236      /**
 237       * Convert literal.
 238       *
 239       * @param string $value
 240       *
 241       * @return string
 242       */
 243      protected function convertLiterals(string $value): string
 244      {
 245          if (\count($this->literals)) {
 246              $key = array_search(strtoupper($value), $this->literals, true);
 247              if (false !== $key) {
 248                  return (string) $key;
 249              }
 250          }
 251  
 252          return $value;
 253      }
 254  
 255      /**
 256       * Checks to see if a value is valid for the field.
 257       *
 258       * @param string $value
 259       *
 260       * @return bool
 261       */
 262      public function validate(string $value): bool
 263      {
 264          $value = $this->convertLiterals($value);
 265  
 266          // All fields allow * as a valid value
 267          if ('*' === $value) {
 268              return true;
 269          }
 270  
 271          // Validate each chunk of a list individually
 272          if (false !== strpos($value, ',')) {
 273              foreach (explode(',', $value) as $listItem) {
 274                  if (!$this->validate($listItem)) {
 275                      return false;
 276                  }
 277              }
 278  
 279              return true;
 280          }
 281  
 282          if (false !== strpos($value, '/')) {
 283              [$range, $step] = explode('/', $value);
 284  
 285              // Don't allow numeric ranges
 286              if (is_numeric($range)) {
 287                  return false;
 288              }
 289  
 290              return $this->validate($range) && filter_var($step, FILTER_VALIDATE_INT);
 291          }
 292  
 293          if (false !== strpos($value, '-')) {
 294              if (substr_count($value, '-') > 1) {
 295                  return false;
 296              }
 297  
 298              $chunks = explode('-', $value);
 299              $chunks[0] = $this->convertLiterals($chunks[0]);
 300              $chunks[1] = $this->convertLiterals($chunks[1]);
 301  
 302              if ('*' === $chunks[0] || '*' === $chunks[1]) {
 303                  return false;
 304              }
 305  
 306              return $this->validate($chunks[0]) && $this->validate($chunks[1]);
 307          }
 308  
 309          if (!is_numeric($value)) {
 310              return false;
 311          }
 312  
 313          if (false !== strpos($value, '.')) {
 314              return false;
 315          }
 316  
 317          // We should have a numeric by now, so coerce this into an integer
 318          $value = (int) $value;
 319  
 320          return \in_array($value, $this->fullRange, true);
 321      }
 322  
 323      protected function timezoneSafeModify(DateTimeInterface $dt, string $modification): DateTimeInterface
 324      {
 325          $timezone = $dt->getTimezone();
 326          $dt = $dt->setTimezone(new \DateTimeZone("UTC"));
 327          $dt = $dt->modify($modification);
 328          $dt = $dt->setTimezone($timezone);
 329          return $dt;
 330      }
 331  
 332      protected function setTimeHour(DateTimeInterface $date, bool $invert, int $originalTimestamp): DateTimeInterface
 333      {
 334          $date = $date->setTime((int)$date->format('H'), ($invert ? 59 : 0));
 335  
 336          // setTime caused the offset to change, moving time in the wrong direction
 337          $actualTimestamp = $date->format('U');
 338          if ((! $invert) && ($actualTimestamp <= $originalTimestamp)) {
 339              $date = $this->timezoneSafeModify($date, "+1 hour");
 340          } elseif ($invert && ($actualTimestamp >= $originalTimestamp)) {
 341              $date = $this->timezoneSafeModify($date, "-1 hour");
 342          }
 343  
 344          return $date;
 345      }
 346  }


Generated: Wed Sep 7 05:41:13 2022 Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer