]> wagnertech.de Git - timetracker.git/blobdiff - WEB-INF/lib/tdcron/class.tdcron.entry.php
Initial repo created
[timetracker.git] / WEB-INF / lib / tdcron / class.tdcron.entry.php
diff --git a/WEB-INF/lib/tdcron/class.tdcron.entry.php b/WEB-INF/lib/tdcron/class.tdcron.entry.php
new file mode 100644 (file)
index 0000000..d0f4d3c
--- /dev/null
@@ -0,0 +1,324 @@
+<?php
+
+       /**
+        * tinyCronEntry is part of tdCron. Its a class to parse Cron-Expressions like "1-45 1,2,3 1-30/5 January,February Mon,Tue"
+        * and convert it to an easily useable format.
+        *
+        * The parser is quite powerful and understands pretty much everything you will ever find in a Cron-Expression.
+        *
+        * A Cron-Expression consists of 5 segments:
+        *
+        * <pre>
+        *  .---------------- minute (0 - 59)
+        *  |   .------------- hour (0 - 23)
+        *  |   |   .---------- day of month (1 - 31)
+        *  |   |   |   .------- month (1 - 12)
+        *  |   |   |   |  .----- day of week (0 - 6)
+        *  |   |   |   |  |
+        *  *   *   *   *  *
+        * </pre>
+        *
+        * Each segment can contain values, ranges and intervals. A range is always written as "value1-value2" and
+        * intervals as "value1/value2".
+        *
+        * Of course each segment can contain multiple values seperated by commas.
+        *
+        * Some valid examples:
+        *
+        * <pre>
+        * 1,2,3,4,5
+        * 1-5
+        * 10-20/*
+        * Jan,Feb,Oct
+        * Monday-Friday
+        * 1-10,15,20,40-50/2
+        * </pre>
+        *
+        * The current version of the parser understands all weekdays and month names in german and english!
+        *
+        * Usually you won't need to call this class directly.
+        *
+        * Copyright (c) 2010 Christian Land / tagdocs.de
+        *
+        * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
+        * associated documentation files (the "Software"), to deal in the Software without restriction,
+        * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
+        * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
+        * subject to the following conditions:
+        *
+        * The above copyright notice and this permission notice shall be included in all copies or substantial
+        * portions of the Software.
+        *
+        * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
+        * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+        * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+        * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+        * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+        *
+        * @author      Christian Land <devel@tagdocs.de>
+        * @package     tinyCron
+        * @subpackage  tinyCronEntry
+        * @copyright   Copyright (c) 2010, Christian Land / tagdocs.de
+        * @version     v0.0.1 beta
+        */
+
+       class tdCronEntry {
+
+               /**
+                * The parsed cron-expression.
+                * @var mixed
+                */
+               static private $cron            = array();
+
+               /**
+                * Ranges.
+                * @var mixed
+                */
+               static private $ranges          = array(
+                                                       IDX_MINUTE              => array( 'min' => 0,
+                                                                                         'max' => 59   ),      // Minutes
+                                                       IDX_HOUR                => array( 'min' => 0,
+                                                                                         'max' => 23   ),      // Hours
+                                                       IDX_DAY                 => array( 'min' => 1,
+                                                                                         'max' => 31   ),      // Days
+                                                       IDX_MONTH               => array( 'min' => 1,
+                                                                                         'max' => 12   ),      // Months
+                                                       IDX_WEEKDAY             => array( 'min' => 0,
+                                                                                         'max' => 7    )       // Weekdays
+                                               );
+
+               /**
+                * Named intervals.
+                * @var mixed
+                */
+               static private $intervals       = array(
+                                                       '@yearly'       => '0 0 1 1 *',
+                                                       '@annualy'      => '0 0 1 1 *',
+                                                       '@monthly'      => '0 0 1 * *',
+                                                       '@weekly'       => '0 0 * * 0',
+                                                       '@midnight'     => '0 0 * * *',
+                                                       '@daily'        => '0 0 * * *',
+                                                       '@hourly'       => '0 * * * *'
+                                                       );
+
+
+               /**
+                * Possible keywords for months/weekdays.
+                * @var mixed
+                */
+               static private $keywords        = array(
+                                                       IDX_MONTH       => array(
+                                                                               '/(january|januar|jan)/i'                       => 1,
+                                                                               '/(february|februar|feb)/i'                     => 2,
+                                                                               '/(march|maerz|märz|mar|mae|mär)/i'             => 3,
+                                                                               '/(april|apr)/i'                                => 4,
+                                                                               '/(may|mai)/i'                                  => 5,
+                                                                               '/(june|juni|jun)/i'                            => 6,
+                                                                               '/(july|juli|jul)/i'                            => 7,
+                                                                               '/(august|aug)/i'                               => 8,
+                                                                               '/(september|sep)/i'                            => 9,
+                                                                               '/(october|oktober|okt|oct)/i'                  => 10,
+                                                                               '/(november|nov)/i'                             => 11,
+                                                                               '/(december|dezember|dec|dez)/i'                => 12
+                                                                               ),
+                                                       IDX_WEEKDAY     => array(
+                                                                               '/(sunday|sonntag|sun|son|su|so)/i'             => 0,
+                                                                               '/(monday|montag|mon|mo)/i'                     => 1,
+                                                                               '/(tuesday|dienstag|die|tue|tu|di)/i'           => 2,
+                                                                               '/(wednesdays|mittwoch|mit|wed|we|mi)/i'        => 3,
+                                                                               '/(thursday|donnerstag|don|thu|th|do)/i'        => 4,
+                                                                               '/(friday|freitag|fre|fri|fr)/i'                => 5,
+                                                                               '/(saturday|samstag|sam|sat|sa)/i'              => 6
+                                                                               )
+                                                       );
+
+               /**
+                * parseExpression() analyses crontab-expressions like "* * 1,2,3 * mon,tue" and returns an array
+                * containing all values. If it can't be parsed, an exception is thrown.
+                *
+                * @access              public
+                * @param               string          $expression     The cron-expression to parse.
+                * @return              mixed
+                */
+
+               static public function parse($expression) {
+
+                       // Convert named expressions if neccessary
+
+                       if (substr($expression,0,1) == '@') {
+
+                               $expression     = strtr($expression, self::$intervals);
+
+                               if (substr($expression,0,1) == '@') {
+
+                                       // Oops... unknown named interval!?!!
+                                       throw new Exception('Unknown named interval ['.$expression.']', 10000);
+
+                               }
+
+                       }
+
+                       // Next basic check... do we have 5 segments?
+
+                       $cron   = explode(' ',$expression);
+
+                       if (count($cron) <> 5) {
+
+                               // No... we haven't...
+                               throw new Exception('Wrong number of segments in expression. Expected: 5, Found: '.count($cron), 10001);
+
+                       } else {
+
+                               // Yup, 5 segments... lets see if we can work with them
+
+                               foreach ($cron as $idx=>$segment) {
+
+                                       try {
+
+                                               $dummy[$idx]    = self::expandSegment($idx, $segment);
+
+                                       } catch (Exception $e) {
+
+                                               throw $e;
+
+                                       }
+
+                               }
+
+                       }
+
+                       return $dummy;
+
+               }
+
+               /**
+                * expandSegment() analyses a single segment
+                *
+                * @access              public
+                * @param               void
+                * @return              void
+                */
+
+               static private function expandSegment($idx, $segment) {
+
+                       // Store original segment for later use
+
+                       $osegment       = $segment;
+
+                       // Replace months/weekdays like "January", "February", etc. with numbers
+
+                       if (isset(self::$keywords[$idx])) {
+
+                               $segment        = preg_replace(
+                                                               array_keys(self::$keywords[$idx]),
+                                                               array_values(self::$keywords[$idx]),
+                                                               $segment
+                                                               );
+
+                       }
+
+                       // Replace wildcards
+
+                       if (substr($segment,0,1) == '*') {
+
+                               $segment        = preg_replace('/^\*(\/\d+)?$/i',
+                                                               self::$ranges[$idx]['min'].'-'.self::$ranges[$idx]['max'].'$1',
+                                                               $segment);
+
+                       }
+
+                       // Make sure that nothing unparsed is left :)
+
+                       $dummy          = preg_replace('/[0-9\-\/\,]/','',$segment);
+
+                       if (!empty($dummy)) {
+
+                               // Ohoh.... thats not good :-)
+                               throw new Exception('Failed to parse segment: '.$osegment, 10002);
+
+                       }
+
+                       // At this point our string should be OK - lets convert it to an array
+
+                       $result         = array();
+                       $atoms          = explode(',',$segment);
+
+                       foreach ($atoms as $curatom) {
+
+                               $result = array_merge($result, self::parseAtom($curatom));
+
+                       }
+
+                       // Get rid of duplicates and sort the array
+
+                       $result         = array_unique($result);
+                       sort($result);
+
+                       // Check for invalid values
+
+                       if ($idx == IDX_WEEKDAY) {
+
+                               if (end($result) == 7) {
+
+                                       if (reset($result) <> 0) {
+                                               array_unshift($result, 0);
+                                       }
+
+                                       array_pop($result);
+
+                               }
+
+                       }
+
+                       foreach ($result as $key=>$value) {
+
+                               if (($value < self::$ranges[$idx]['min']) || ($value > self::$ranges[$idx]['max'])) {
+                                       throw new Exception('Failed to parse segment, invalid value ['.$value.']: '.$osegment, 10003);
+                               }
+
+                       }
+
+                       return $result;
+
+               }
+
+               /**
+                * parseAtom() analyses a single segment
+                *
+                * @access              public
+                * @param               string          $atom           The segment to parse
+                * @return              array
+                */
+
+               static private function parseAtom($atom) {
+
+                       $expanded       = array();
+
+                       if (preg_match('/^(\d+)-(\d+)(\/(\d+))?/i', $atom, $matches)) {
+
+                               $low    = $matches[1];
+                               $high   = $matches[2];
+
+                               if ($low > $high) {
+                                       list($low,$high)        = array($high,$low);
+                               }
+
+                               $step   = isset($matches[4]) ? $matches[4] : 1;
+
+                               for($i = $low; $i <= $high; $i += $step) {
+                                       $expanded[]     = (int)$i;
+                               }
+
+                       } else {
+
+                               $expanded[]     = (int)$atom;
+
+                       }
+
+                       $expanded2      = array_unique($expanded);
+
+                       return $expanded;
+
+               }
+
+       }
\ No newline at end of file