X-Git-Url: http://wagnertech.de/gitweb/gitweb.cgi/timetracker.git/blobdiff_plain/098a79f0819ebb89b7d48df4a6b154af4560f68e..9a23a8c0a51b7ec38a96f525484134f3cb85dc7e:/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 index 00000000..d0f4d3c3 --- /dev/null +++ b/WEB-INF/lib/tdcron/class.tdcron.entry.php @@ -0,0 +1,324 @@ + + * .---------------- minute (0 - 59) + * | .------------- hour (0 - 23) + * | | .---------- day of month (1 - 31) + * | | | .------- month (1 - 12) + * | | | | .----- day of week (0 - 6) + * | | | | | + * * * * * * + * + * + * 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: + * + *
+	 * 1,2,3,4,5
+	 * 1-5
+	 * 10-20/*
+	 * Jan,Feb,Oct
+	 * Monday-Friday
+	 * 1-10,15,20,40-50/2
+	 * 
+ * + * 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 + * @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