PluginProbe
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar / 2.0.2
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar v2.0.2
2.1.21 2.1.20 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 trunk 1.1 2.0 2.0.1 2.0.10.2 2.0.11 2.0.12 2.0.13 2.0.14 2.0.15 2.0.16 2.0.17 2.0.18 2.0.2 2.0.20 2.0.21 2.0.22 All 55 releases
booking-manager / assets / libs / icalendar / includes / recurringdate.php

recurringdate.php in Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar 2.0.2, at assets/libs/icalendar/includes/recurringdate.php

598 lines 18.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Zap Calendar Recurring Date Helper Class
5 *
6 * @copyright Copyright (C) 2006 - 2016 by Dan Cogliano
7 * @license GNU General Public License version 2 or later; see LICENSE.txt
8 */
9
10 // no direct access
11 defined('_ZAPCAL') or die( 'Restricted access' );
12
13 /**
14 * Class to expand recurring rule to a list of dates
15 */
16 class ZCRecurringDate {
17 var $rules = "";
18 var $startdate = null;
19 var $nextdate = null;
20 var $freq = null;
21 var $tzid = null;
22 var $year=0;
23 var $month=0;
24 var $week=0;
25 var $day=0;
26 var $hour=0;
27 var $minute=0;
28 var $second=0;
29 var $until=null;
30 var $count=0;
31 var $repeatmode=null;
32 var $incr=0;
33 var $bysecond=array();
34 var $byminute=array();
35 var $byhour=array();
36 var $byday=array();
37 var $bymonthday=array();
38 var $daybegin=array();
39 var $dayend=array();
40 var $bymonth=array();
41 var $byyear=array();
42 var $bysetpos=array();
43 var $ibymonthday = 0;
44 var $ibymonth = 0;
45 var $interval = 1;
46 var $debug = 0;
47 var $error;
48 var $exdates=array();
49
50 // $startdate is in local timezone
51 // $exdates array is in UTC timezone
52 // function ZCRecurringDate($rules, $startdate, $exdates = array(),$tzid = "UTC"){
53 public function __construct($rules, $startdate, $exdates = array(),$tzid = "UTC"){ //FixIn: 2.0.1.5
54 if(strlen($rules) > 0){
55 //move exdates to event timezone for comparing with event date
56 for($i = 0; $i < count($exdates); $i++)
57 {
58 $exdates[$i] = ZDateHelper::toUnixDateTime(ZDateHelper::toLocalDateTime(ZDateHelper::toSQLDateTime($exdates[$i]),$tzid));
59 }
60
61 $rules=str_replace("\'","",$rules);
62 $this->rules = $rules;
63 if($startdate == null){
64 // if not specified, use start date of beginning of last year
65 $tdate=getdate();
66 $startdate=mktime(0,0,0,1,1,$tdate["year"] - 1);
67 }
68 $this->startdate = $startdate;
69 $this->nextdate = $startdate;
70 $this->tzid = $tzid;
71 $this->exdates = $exdates;
72
73 $rules=explode(";", $rules);
74 $ruletype = "";
75 foreach($rules as $rule){
76 $item=explode("=",$rule);
77 //echo $item[0] . "=" . $item[1] . "<br/>\n";
78 switch($item[0]){
79 case "FREQ":
80 switch($item[1]){
81 case "YEARLY":
82 $this->year = 1;
83 $this->freq="y";
84 break;
85 case "MONTHLY":
86 $this->month = 1;
87 $this->freq="m";
88 break;
89 case "WEEKLY":
90 $this->week = 1;
91 $this->freq="w";
92 break;
93 case "DAILY":
94 $this->day = 1;
95 $this->freq="d";
96 break;
97 case "HOURLY":
98 $this->hour = 1;
99 $this->freq="h";
100 break;
101 case "MINUTELY":
102 $this->minute = 1;
103 $this->freq="i";
104 break;
105 case "SECONDLY":
106 $this->second = 1;
107 $this->freq="s";
108 break;
109 }
110 break;
111 case "INTERVAL":
112 $this->interval = $item[1];
113 break;
114 case "BYSECOND":
115 $this->bysecond = explode(",",$item[1]);
116 $ruletype = $item[0];
117 break;
118 case "BYMINUTE":
119 $this->byminute = explode(",",$item[1]);
120 $ruletype = $item[0];
121 break;
122 case "BYHOUR":
123 $this->byhour = explode(",",$item[1]);
124 $ruletype = $item[0];
125 break;
126 case "BYDAY":
127 $this->byday = explode(",",$item[1]);
128 $ruletype = $item[0];
129 break;
130 case "BYMONTHDAY":
131 $this->bymonthday = explode(",",$item[1]);
132 $ruletype = $item[0];
133 break;
134 case "BYMONTH":
135 $this->bymonth = explode(",",$item[1]);
136 $ruletype = $item[0];
137 break;
138 case "BYYEAR":
139 $this->byyear = explode(",",$item[1]);
140 $ruletype = $item[0];
141 break;
142 case "COUNT":
143 $this->count = intval($item[1]);
144 $this->repeatmode = "c";
145 break;
146 case "BYSETPOS":
147 $this->bysetpos = explode(",",$item[1]);
148 break;
149 case "UNTIL":
150 $this->until = ZDateHelper::fromiCaltoUnixDateTime($item[1]);
151 $this->repeatmode = "u";
152 break;
153 }
154 }
155 if(count($this->bysetpos) > 0){
156 switch($ruletype){
157 case "BYYEAR":
158 $this->byyear = $this->bySetPos($this->byyear,$this->bysetpos);
159 break;
160 case "BYMONTH":
161 $this->bymonth = $this->bySetPos($this->bymonth,$this->bysetpos);
162 break;
163 case "BYMONTHDAY":
164 $this->bymonthday = $this->bySetPos($this->bymonthday,$this->bysetpos);
165 break;
166 case "BYDAY":
167 $this->byday = $this->bySetPos($this->byday,$this->bysetpos);
168 break;
169 case "BYHOUR":
170 $this->byhour = $this->bySetPos($this->byhour,$this->bysetpos);
171 break;
172 case "BYMINUTE":
173 $this->byminute = $this->bySetPos($this->byminute,$this->bysetpos);
174 break;
175 case "BYSECOND":
176 $this->bysecond = $this->bySetPos($this->bysecond,$this->bysetpos);
177 break;
178 }
179 }
180 if(is_array($this->byday)){
181 $dow = array("SU","MO","TU","WE","TH","FR","SA");
182 for($w=0; $w<=5; $w++){
183 for($d=0; $d < 7; $d++){
184 $this->daybegin[$d][$w] = 0;
185 $this->dayend[$d][$w] = 0;
186 if(in_array($dow[$d],$this->byday)||
187 in_array(($w+1) . $dow[$d], $this->byday)||
188 in_array(($w+1) . $dow[$d], $this->byday))
189 $this->daybegin[$d][$w] = 1;
190 if(in_array("-" . ($w+1) . $dow[$d], $this->byday)){
191 $this->dayend[$d][$w] = 1;
192 }
193 // echo $this->daybegin[$d][$w] . " ";
194 }
195 // echo "<br />\n";
196 }
197 }
198
199 }
200 }
201
202 function bySetPos($bytype, $bysetpos){
203 $result = array();
204 for($i=0; $i < count($bysetpos); $i++){
205 for($j=0; $j < count($bytype); $j++){
206 $result[] = $bysetpos[$i] . $bytype[$j];
207 }
208 }
209 return $result;
210 }
211
212 function error($msg){
213 $this->error = $msg;
214 echo "ZCRecurringDate() error:" . $this->error . "<br />\n";
215 }
216
217 function debug($level, $msg){
218 if($this->debug >= $level)
219 echo $msg . "<br/>\n";
220 }
221
222 function getError(){
223 return $this->error;
224 }
225
226 function byYear($startdate, $enddate, &$rdates, $tzid="UTC"){
227 self::debug(1,"byYear(" . ZDateHelper::toSqlDateTime($startdate) . ","
228 . ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
229 $count = 0;
230 if(count($this->byyear) > 0){
231 foreach($this->byyear as $year){
232 $t = getdate($startdate);
233 $wdate = mktime($t[hours],$t[minutes],$t[seconds],$t[month],$t[mday],$year);
234 if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
235 $count = $this->byMonth($wdate, $enddate, $rdates, $tzid);
236 if($count == 0) {
237 $rdates[] = $wdate;
238 $count++;
239 }
240 }
241 }
242 }
243 else if(!$this->maxDates($rdates))
244 $count = $this->byMonth($startdate, $enddate, $rdates, $tzid);
245 self::debug(1,"byYear() returned " . $count );
246 return $count;
247 }
248
249 function byMonth($startdate, $enddate, &$rdates, $tzid="UTC"){
250 self::debug(1,"byMonth(" . ZDateHelper::toSqlDateTime($startdate) . ","
251 . ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
252 $count = 0;
253 if(count($this->bymonth) > 0){
254 foreach($this->bymonth as $month){
255 $t = getdate($startdate);
256 $wdate = mktime($t["hours"],$t["minutes"],$t["seconds"],$month,$t["mday"],$t["year"]);
257 if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
258 $count = $this->byMonthDay($wdate, $enddate, $rdates, $tzid);
259 if($count == 0) {
260 $rdates[] = $wdate;
261 $count++;
262 }
263 }
264 }
265 }
266 else if(!$this->maxDates($rdates))
267 $count = $this->byMonthDay($startdate, $enddate, $rdates, $tzid);
268 self::debug(1,"byMonth() returned " . $count );
269 return $count;
270 }
271
272 function byMonthDay($startdate, $enddate, &$rdates, $tzid="UTC"){
273 self::debug(1,"byMonthDay(" . ZDateHelper::toSqlDateTime($startdate) . ","
274 . ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
275 $count = 0;
276 self::debug(1,"start date: " . ZDateHelper::toSqlDateTime($startdate));
277 if(count($this->bymonthday) > 0){
278 foreach($this->bymonthday as $day){
279 $day = intval($day);
280 $t = getdate($startdate);
281 $wdate = mktime($t['hours'],$t['minutes'],$t['seconds'],$t['mon'],$day,$t['year']);
282 self::debug(2,"mktime(" . $t['hours'] . ", " . $t['minutes']
283 . ", " . $t['mon'] . ", " . $day . ", " . $t['year'] . ") returned $wdate");
284 if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
285 $count = $this->byDay($wdate, $enddate, $rdates, $tzid);
286 if($count == 0) {
287 $rdates[] = $wdate;
288 $count++;
289 }
290 }
291 }
292 }
293 else if(!$this->maxDates($rdates)) {
294 self::debug(1,"start date: " . ZDateHelper::toSqlDateTime($startdate));
295 $count = $this->byDay($startdate, $enddate, $rdates, $tzid);
296 }
297 self::debug(1,"byMonthDay() returned " . $count );
298 return $count;
299 }
300
301 function byDay($startdate, $enddate, &$rdates, $tzid="UTC"){
302 self::debug(1,"byDay(" . ZDateHelper::toSqlDateTime($startdate) . ","
303 . ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
304 $days = array(
305 "SU" => 0,
306 "MO" => 1,
307 "TU" => 2,
308 "WE" => 3,
309 "TH" => 4,
310 "FR" => 5,
311 "SA" => 6);
312 $idays = array(
313 0 => "SU",
314 1 => "MO",
315 2 => "TU",
316 3 => "WE",
317 4 => "TH",
318 5 => "FR",
319 6 => "SA");
320
321 $count = 0;
322 if(count($this->byday) > 0){
323 if(empty($this->byday[0]))
324 {
325 $this->byday[0] = $idays[date("w",$startdate)];
326 }
327 foreach($this->byday as $tday){
328 $t = getdate($startdate);
329 $day = substr($tday,strlen($tday) - 2);
330 if(strlen($day) < 2)
331 {
332 // missing start day, use current date for DOW
333 $day = $idays[date("w",$startdate)];
334 }
335 if(strlen($tday) > 2) {
336 $imin = 1;
337 $imax = 5; // max # of occurances in a month
338 if(strlen($tday) > 2)
339 $imin = $imax = substr($tday,0,strlen($tday) - 2);
340 self::debug(2,"imin: $imin, imax: $imax, tday: $tday, day: $day, daynum: {$days[$day]}");
341 for($i = $imin; $i <= $imax; $i++){
342 $wdate = ZDateHelper::getDateFromDay($startdate,$i-1,$days[$day],$tzid);
343 self::debug(2,"getDateFromDay(" . ZDateHelper::toSqlDateTime($startdate)
344 . ",$i,{$days[$day]}) returned " . ZDateHelper::toSqlDateTime($wdate));
345 if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
346 $count = $this->byHour($wdate, $enddate, $rdates);
347 if($count == 0){
348 $rdates[] = $wdate;
349 $count++;
350 //break;
351 }
352 }
353 }
354 }
355 else {
356 // day of week version
357 $startdate_dow = date("w",$startdate);
358 $datedelta = $days[$day] - $startdate_dow;
359 self::debug(2, "start_dow: $startdate_dow, datedelta: $datedelta");
360 if($datedelta >= 0)
361 {
362 $wdate = ZDateHelper::addDate($startdate,0,0,0,0,$datedelta,0,$this->tzid);
363 self::debug(2, "wdate: " . ZDateHelper::toSqlDateTime($wdate));
364 if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
365 $count = $this->byHour($wdate, $enddate, $rdates);
366 if($count == 0){
367 $rdates[] = $wdate;
368 $count++;
369 self::debug(2,"adding date " . ZDateHelper::toSqlDateTime($wdate) );
370 }
371 }
372 }
373 }
374 }
375 }
376 else if(!$this->maxDates($rdates))
377 $count = $this->byHour($startdate, $enddate, $rdates);
378 self::debug(1,"byDay() returned " . $count );
379 return $count;
380 }
381
382 function byHour($startdate, $enddate, &$rdates, $tzid="UTC"){
383 self::debug(1,"byHour(" . ZDateHelper::toSqlDateTime($startdate) . ","
384 . ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
385 $count = 0;
386 if(count($this->byhour) > 0){
387 foreach($this->byhour as $hour){
388 $t = getdate($startdate);
389 $wdate = mktime($hour,$t["minutes"],$t["seconds"],$t["mon"],$t["mday"],$t["year"]);
390 self::debug(2,"checking date/time " . ZDateHelper::toSqlDateTime($wdate));
391 if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
392 $count = $this->byMinute($wdate, $enddate, $rdates);
393 if($count == 0) {
394 $rdates[] = $wdate;
395 $count++;
396 }
397 }
398 }
399 }
400 else if(!$this->maxDates($rdates))
401 $count = $this->byMinute($startdate, $enddate, $rdates);
402 self::debug(1,"byHour() returned " . $count );
403 return $count;
404 }
405
406 function byMinute($startdate, $enddate, &$rdates, $tzid="UTC"){
407 self::debug(1,"byMinute(" . ZDateHelper::toSqlDateTime($startdate) . ","
408 . ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
409 $count = 0;
410 if(count($this->byminute) > 0){
411 foreach($this->byminute as $minute){
412 $t = getdate($startdate);
413 $wdate = mktime($t["hours"],$minute,$t["seconds"],$t["mon"],$t["mday"],$t["year"]);
414 if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
415 $count = $this->bySecond($wdate, $enddate, $rdates);
416 if($count == 0) {
417 $rdates[] = $wdate;
418 $count++;
419 }
420 }
421 }
422 }
423 else if(!$this->maxDates($rdates))
424 $count = $this->bySecond($startdate, $enddate, $rdates);
425 self::debug(1,"byMinute() returned " . $count );
426 return $count;
427 }
428
429 function bySecond($startdate, $enddate, &$rdates, $tzid="UTC"){
430 self::debug(1,"bySecond(" . ZDateHelper::toSqlDateTime($startdate) . ","
431 . ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
432 $count = 0;
433 if(count($this->bysecond) > 0){
434 foreach($this->bysecond as $second){
435 $t = getdate($startdate);
436 $wdate = mktime($t["hours"],$t["minutes"],$second,$t["mon"],$t["mday"],$t["year"]);
437 if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
438 $rdates[] = $wdate;
439 $count++;
440 }
441 }
442 }
443 self::debug(1,"bySecond() returned " . $count );
444 return $count;
445 }
446
447 function maxDates($rdates){
448 if($this->repeatmode == "c" && count($rdates) >= $this->count)
449 return true; // exceeded count
450 else if(count($rdates) > 0 && $this->repeatmode == "u" && $rdates[count($rdates) - 1] > $this->until){
451 return true; //past date
452 }
453 return false;
454 }
455
456 function getDates($maxdate = null){
457 //$this->debug = 2;
458 self::debug(1,"getDates()");
459 $nextdate = $enddate = $this->startdate;
460 $rdates = array();
461 $done = false;
462 $eventcount = 0;
463 $loopcount = 0;
464 self::debug(2,"freq: " . $this->freq . ", interval: " . $this->interval);
465 while(!$done){
466 self::debug(1,"<b>*** Frequency ({$this->freq}) loop pass $loopcount ***</b>");
467 switch($this->freq){
468 case "y":
469 if($eventcount > 0)
470 {
471 $nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,0,$this->interval,$this->tzid);
472 self::debug(2,"addDate() returned " . ZDateHelper::toSqlDateTime($nextdate));
473 if(!empty($this->byday)){
474 $t = getdate($nextdate);
475 $nextdate = gmmktime($t["hours"],$t["minutes"],$t["seconds"],$t["mon"],1,$t["year"]);
476 }
477 self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")");
478 }
479 $enddate=ZDateHelper::addDate($nextdate,0,0,0,0,0,1);
480 break;
481 case "m":
482 if($eventcount > 0)
483 {
484
485 $nextdate = ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0,$this->tzid);
486 self::debug(2,"addDate() returned " . ZDateHelper::toSqlDateTime($nextdate));
487 }
488 if(count($this->byday) > 0)
489 {
490 $t = getdate($nextdate);
491 if($t["mday"] > 28)
492 {
493 //check for short months when using month by day, make sure we do not overshoot the counter and skip a month
494 $nextdate = ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0,$this->tzid);
495 $t2 = getdate($nextdate);
496 if($t2["mday"] < $t["mday"])
497 {
498 // oops, skipped a month, backup to previous month
499 $nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$t2["mday"] - $t["mday"],0,$this->tzid);
500 }
501 }
502 $t = getdate($nextdate);
503 $nextdate = mktime($t["hours"],$t["minutes"],$t["seconds"],$t["mon"],1,$t["year"]);
504 }
505 self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")");
506 $enddate=ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0);
507 break;
508 case "w":
509 if($eventcount == 0)
510 $nextdate=$nextdate;
511 else {
512 $nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval*7,0,$this->tzid);
513 if(count($this->byday) > 0){
514 $dow = date("w", $nextdate);
515 // move to beginning of week (Sunday)
516 $bow = 0;
517 $diff = $bow - $dow;
518 if($diff > 0)
519 $diff = $diff - 7;
520 $nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$diff,0);
521 }
522 self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")");
523 }
524 $enddate=ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval*7,0);
525 break;
526 case "d":
527 $nextdate=($eventcount==0?$nextdate:
528 ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval,0,$this->tzid));
529 $enddate=ZDateHelper::addDate($nextdate,0,0,0,0,1,0);
530 break;
531 }
532
533 $count = $this->byYear($nextdate,$enddate,$rdates,$this->tzid);
534 $eventcount += $count;
535 if($maxdate > 0 && $maxdate < $nextdate)
536 {
537 array_pop($rdates);
538 $done = true;
539 }
540 else if($count == 0 && !$this->maxDates($rdates)){
541 $rdates[] = $nextdate;
542 $eventcount++;
543 }
544 if($this->maxDates($rdates))
545 $done = true;
546
547 $year = date("Y", $nextdate);
548 if($year > _ZAPCAL_MAXYEAR)
549 {
550 $done = true;
551 }
552 $loopcount++;
553 if($loopcount > _ZAPCAL_MAXYEAR){
554 $done = true;
555 throw new Exception("Infinite loop detected in getDates()");
556 }
557 }
558 if($this->repeatmode == "u" && $rdates[count($rdates) - 1] > $this->until){
559 // erase last item
560 array_pop($rdates);
561 }
562 $count1 = count($rdates);
563 $rdates = array_unique($rdates);
564 $count2 = count($rdates);
565 $dups = $count1 - $count2;
566 $excount = 0;
567
568 foreach($this->exdates as $exdate)
569 {
570 if($pos = array_search($exdate,$rdates))
571 {
572 array_splice($rdates,$pos,1);
573 $excount++;
574 }
575 }
576 self::debug(1,"getDates() returned " . count($rdates) . " dates, removing $dups duplicates, $excount exceptions");
577
578
579 if($this->debug >= 2)
580 {
581 self::debug(2,"Recurring Dates:");
582 foreach($rdates as $rdate)
583 {
584 $d = getdate($rdate);
585 self::debug(2,ZDateHelper::toSQLDateTime($rdate) . " " . $d["wday"] );
586 }
587 self::debug(2,"Exception Dates:");
588 foreach($this->exdates as $exdate)
589 {
590 self::debug(2, ZDateHelper::toSQLDateTime($exdate));
591 }
592 //exit;
593 }
594
595 return $rdates;
596 }
597 }
598