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 / ical.php

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

840 lines 21.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Zap Calendar ical Helper Class
4 *
5 * @copyright Copyright (C) 2006 - 2016 by Dan Cogliano
6 * @license GNU General Public License version 2 or later; see LICENSE.txt
7 */
8
9 // no direct access
10 defined('_ZAPCAL') or die( 'Restricted access' );
11
12 /**
13 * Object for storing an unfolded iCalendar line
14 *
15 * The ZCiCalDataNode class contains data from an unfolded iCalendar line
16 *
17 */
18
19 class ZCiCalDataNode {
20 /**
21 * The name of the node
22 *
23 * @var string
24 */
25 var $name = "";
26
27 /**
28 * Node parameters (before the colon ":")
29 *
30 * @var array
31 */
32 var $parameter=array();
33
34 /**
35 * Node values (after the colon ":")
36 *
37 * @var array
38 */
39 var $value=array();
40
41 /**
42 * Create an object from an unfolded iCalendar line
43 *
44 * @param string $line An unfolded iCalendar line
45 *
46 * @return void
47 *
48 */
49 // function ZCiCalDataNode( $line ) {
50 public function __construct( $line ) { //FixIn: 2.0.1.5
51 //echo "ZCiCalDataNode($line)<br/>\n";
52 //separate line into parameters and value
53 // look for colon separating name or parameter and value
54 // first change any escaped colons temporarily to make it easier
55 $tline = str_replace("\\:", "`~", $line);
56 // see if first colon is inside a quoted string
57 $i = 0;
58 $datafind = false;
59 $inquotes = false;
60 while(!$datafind && ($i < strlen($tline))) {
61 //echo "$i: " . $tline{$i} . ", ord() = " . ord($tline{$i}) . "<br>\n";
62 if(!$inquotes && $tline{$i} == ':')
63 $datafind=true;
64 else{
65 $i += 1;
66 if(substr($tline,$i,1) == '"')
67 $inquotes = !$inquotes;
68 }
69 }
70 if($datafind){
71 $value = str_replace("`~","\\:",substr($line,$i+1));
72 // fix escaped characters (don't see double quotes in spec but Apple apparently uses it in iCal)
73 $value = str_replace(array('\\N' , '\\n', '\\"' ), array("\n", "\n" , '"'), $value);
74 $tvalue = str_replace("\\,", "`~", $value);
75 //echo "value: " . $tvalue . "<br>\n";
76 $tvalue = explode(",",$tvalue);
77 $value = str_replace("`~","\\,",$tvalue);
78 $this->value = $value;
79 }
80
81 $parameter = trim(substr($line,0,$i));
82
83 $parameter = str_replace("\\;", "`~", $parameter);
84 $parameters = explode(";", $parameter);
85 $parameters = str_replace("`~", "\\;", $parameters);
86 $this->name = array_shift($parameters);
87 foreach($parameters as $parameter){
88 $pos = strpos($parameter,"=");
89 if($pos > 0){
90 $param = substr($parameter,0,$pos);
91 $paramvalue = substr($parameter,$pos+1);
92 $tvalue = str_replace("\\,", "`~", $paramvalue);
93 //$tvalue = explode(",",$tvalue);
94 $paramvalue = str_replace("`~","\\,",$tvalue);
95 $this->parameter[strtolower($param)] = $paramvalue;
96 //$this->paramvalue[] = $paramvalue;
97 }
98 }
99 }
100
101 /**
102 * getName()
103 *
104 * Return the name of the object
105 *
106 * @return string
107 */
108 function getName(){
109 return $this->name;
110 }
111
112 /**
113 * Get $ith parameter from array
114 * @param int $i
115 *
116 * @return var
117 */
118 function getParameter($i){
119 return $this->parameter[$i];
120 }
121
122 /**
123 * Get parameter array
124 *
125 * @return array
126 */
127 function getParameters(){
128 return $this->parameter;
129 }
130
131 /**
132 * Get comma separated values
133 *
134 * @return string
135 */
136 function getValues(){
137 return implode(",",$this->value);
138 }
139 }
140
141 /**
142 * Object for storing a list of unfolded iCalendar lines (ZCiCalDataNode objects)
143 *
144 */
145
146 class ZCiCalNode {
147 var $name="";
148 var $parentnode=null;
149 var $child= array();
150 var $data= array();
151 var $next=null;
152 var $prev=null;
153
154 /**
155 * Create ZCiCalNode
156 *
157 * @param string $_name Name of node
158 *
159 * @param object $_parent Parent node for this node
160 *
161 * @param bool $first Is this the first child for this parent?
162 */
163 // function ZCiCalNode( $_name, & $_parent, $first = false) {
164 public function __construct( $_name, & $_parent, $first = false) { //FixIn: 2.0.1.5
165 $this->name = $_name;
166 $this->parentnode = $_parent;
167 if($_parent != null){
168 if(count($this->parentnode->child) > 0) {
169 if($first)
170 {
171 $first = & $this->parentnode->child[0];
172 $first->prev = & $this;
173 $this->next = & $first;
174 }
175 else
176 {
177 $prev =& $this->parentnode->child[count($this->parentnode->child)-1];
178 $prev->next =& $this;
179 $this->prev =& $prev;
180 }
181 }
182 if($first)
183 {
184 array_unshift($this->parentnode->child, $this);
185 }
186 else
187 {
188 $this->parentnode->child[] =& $this;
189 }
190 }
191 /*
192 echo "creating " . $this->getName();
193 if($_parent != null)
194 echo " child of " . $_parent->getName() . "/" . count($this->parentnode->child);
195 echo "<br/>";
196 */
197 }
198
199 /**
200 * Return the name of the object
201 *
202 * @return string
203 */
204 function getName() {
205 return $this->name;
206 }
207
208 /**
209 * Add node to list
210 *
211 * @param object $node
212 *
213 */
214 function addNode($node) {
215 $this->data[$node->getName()] = $node;
216 }
217
218 /**
219 * Get Attribute
220 *
221 * @param int $i array id of attribute to get
222 *
223 * @return string
224 */
225 function getAttrib($i) {
226 return $this->attrib[$i];
227 }
228
229 /**
230 * Set Attribute
231 *
232 * @param string $value value of attribute to set
233 *
234 */
235 function setAttrib($value) {
236 $this->attrib[] = $value;
237 }
238
239 /**
240 * Get the parent object of this object
241 *
242 * @return object parent of this object
243 */
244 function &getParent() {
245 return $this->parentnode;
246 }
247
248 /**
249 * Get the first child of this object
250 *
251 * @return object The first child
252 */
253 function &getFirstChild(){
254 static $nullguard = null;
255 if(count($this->child) > 0) {
256 //echo "moving from " . $this->getName() . " to " . $this->child[0]->getName() . "<br/>";
257 return $this->child[0];
258 }
259 else
260 return $nullguard;
261 }
262
263 /**
264 * Print object tree in HTML for debugging purposes
265 *
266 * @param object $node select part of tree to print, or leave blank for full tree
267 *
268 * @param int $level Level of recursion (usually leave this blank)
269 *
270 * @return string - HTML formatted display of object tree
271 */
272 function printTree(& $node=null, $level=1){
273 $level += 1;
274 $html = "";
275 if($node == null)
276 $node = $this->parentnode;
277 if($level > 5)
278 {
279 die("levels nested too deep<br/>\n");
280 //return;
281 }
282 for($i = 0 ; $i < $level; $i ++)
283 $html .= "+";
284 $html .= $node->getName() . "<br/>\n";
285 foreach ($node->child as $c){
286 $html .= $node->printTree($c,$level);
287 }
288 $level -= 1;
289 return $html;
290 }
291
292 /**
293 * export tree to icalendar format
294 *
295 * @param object $node Top level node to export
296 *
297 * @param int $level Level of recursion (usually leave this blank)
298 *
299 * @return string iCalendar formatted output
300 */
301 function export(& $node=null, $level=0){
302 $txtstr = "";
303 if($node == null)
304 $node = $this;
305 if($level > 5)
306 {
307 //die("levels nested too deep<br/>\n");
308 throw new Exception("levels nested too deep");
309 }
310 $txtstr .= "BEGIN:" . $node->getName() . "\r\n";
311 foreach ($node->data as $d){
312 $p = "";
313 $params = @$d->getParameters();
314 if(count($params) > 0)
315 {
316 foreach($params as $key => $value){
317 $p .= ";" . strtoupper($key) . "=" . $value;
318 }
319 }
320 $values = $d->getValues();
321 // don't think we need this, Sunbird does not like it in the EXDATE field
322 //$values = str_replace(",", "\\,", $values);
323
324 $line = $d->getName() . $p . ":" . $values;
325 $line = str_replace(array("<br>","<BR>","<br/>","<BR/"),"\\n",$line);
326 $line = str_replace(array("\r\n","\n\r","\n","\r"),'\n',$line);
327 //$line = str_replace(array(',',';','\\'), array('\\,','\\;','\\\\'),$line);
328 //$line =strip_tags($line);
329 $linecount = 0;
330 while (strlen($line) > 0) {
331 $linewidth = ($linecount == 0? 75 : 74);
332 $linesize = (strlen($line) > $linewidth? $linewidth: strlen($line));
333 if($linecount > 0)
334 $txtstr .= " ";
335 $txtstr .= substr($line,0,$linesize) . "\r\n";
336 $linecount += 1;
337 $line = substr($line,$linewidth);
338 }
339 //echo $line . "\n";
340 }
341 foreach ($node->child as $c){
342 $txtstr .= $node->export($c,$level + 1);
343 }
344 $txtstr .= "END:" . $node->getName() . "\r\n";
345 return $txtstr;
346 }
347
348 }
349
350 /**
351 *
352 * The main iCalendar object containing ZCiCalDataNodes and ZCiCalNodes.
353 *
354 */
355 class ZCiCal {
356 var $tree=null;
357 var $curnode=null;
358
359 /**
360 * The main iCalendar object containing ZCiCalDataNodes and ZCiCalNodes.
361 *
362 * use maxevents and startevent to read events in multiple passes (to save memory)
363 *
364 * @param string $data icalendar feed string (empty if creating new feed)
365 *
366 * @param int $maxevents maximum # of events to read
367 *
368 * @param int $startevent starting event to read
369 *
370 * @return void
371 *
372 *
373 */
374 // function ZCiCal ($data = "", $maxevents = 1000000, $startevent = 0) {
375 public function __construct( $data = "", $maxevents = 1000000, $startevent = 0) { //FixIn: 2.0.1.5
376 if($data != ""){
377 // unfold lines
378 // first change all eol chars to "\n"
379 $data = str_replace(array("\r\n", "\n\r", "\n", "\r"), "\n", $data);
380 // now unfold lines
381 //$data = str_replace(array("\n ", "\n "),"!?", $data);
382 $data = str_replace(array("\n ", "\n "),"", $data);
383 // replace special iCal chars
384 $data = str_replace(array("\\\\","\,"),array("\\",","), $data);
385
386 // parse each line
387 $lines = explode("\n", $data);
388
389 //echo $data;
390 //exit;
391 $linecount = 0;
392 $eventcount = 0;
393 $eventpos = 0;
394 foreach($lines as $line) {
395 //$line = str_replace("!?", "\n", $line); // add nl back into descriptions
396 // echo ($linecount + 1) . ": " . $line . "<br/>";
397 if(substr($line,0,6) == "BEGIN:") {
398 // start new object
399 $name = substr($line,6);
400 if($name == "VEVENT")
401 {
402 if($eventcount < $maxevents && $eventpos >= $startevent)
403 {
404 $this->curnode = new ZCiCalNode($name, $this->curnode);
405 if($this->tree == null)
406 $this->tree = $this->curnode;
407 }
408 }
409 else
410 {
411 $this->curnode = new ZCiCalNode($name, $this->curnode);
412 if($this->tree == null)
413 $this->tree = $this->curnode;
414 }
415 //echo "new node: " . $this->curnode->name . "<br/>\n";
416 /*
417 if($this->curnode->getParent() != null)
418 echo "parent of " . $this->curnode->getName() . " is " . $this->curnode->getParent()->getName() . "<br/>";
419 else
420 echo "parent of " . $this->curnode->getName() . " is null<br/>";
421 */
422 }
423 else if(substr($line,0,4) == "END:") {
424 $name = substr($line,4);
425 if($name == "VEVENT")
426 {
427 if($eventcount < $maxevents && $eventpos >= $startevent)
428 {
429 $eventcount++;
430 if($this->curnode->getName() != $name) {
431 //panic, mismatch in iCal structure
432 //die("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
433 throw new Exception("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
434 }
435 if($this->curnode->getParent() != null) {
436 //echo "moving up from " . $this->curnode->getName() ;
437 $this->curnode = & $this->curnode->getParent();
438 //echo " to " . $this->curnode->getName() . "<br/>";
439 //echo $this->curnode->getName() . " has " . count($this->curnode->child) . " children<br/>";
440 }
441 }
442 $eventpos++;
443 }
444 else
445 {
446 if($this->curnode->getName() != $name) {
447 //panic, mismatch in iCal structure
448 //die("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
449 throw new Exception("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
450 }
451 if($this->curnode->getParent() != null) {
452 //echo "moving up from " . $this->curnode->getName() ;
453 $this->curnode = & $this->curnode->getParent();
454 //echo " to " . $this->curnode->getName() . "<br/>";
455 //echo $this->curnode->getName() . " has " . count($this->curnode->child) . " children<br/>";
456 }
457 }
458 }
459 else {
460 $datanode = new ZCiCalDataNode($line);
461 if($this->curnode->getName() == "VEVENT")
462 {
463 if($eventcount < $maxevents && $eventpos >= $startevent)
464 {
465 if($datanode->getName() == "EXDATE")
466 {
467 if(!array_key_exists($datanode->getName(),$this->curnode->data))
468 {
469 $this->curnode->data[$datanode->getName()] = $datanode;
470 }
471 else
472 {
473 $this->curnode->data[$datanode->getName()]->value[] = $datanode->value[0];
474 }
475 }
476 else
477 {
478 $this->curnode->data[$datanode->getName()] = $datanode;
479 }
480 }
481 }
482 else
483 {
484 if($datanode->getName() == "EXDATE")
485 {
486 if(!array_key_exists($datanode->getName(),$this->curnode->data))
487 {
488 $this->curnode->data[$datanode->getName()] = $datanode;
489 }
490 else
491 {
492 $this->curnode->data[$datanode->getName()]->value[] = $datanode->value[0];
493 }
494 }
495 else
496 {
497 $this->curnode->data[$datanode->getName()] = $datanode;
498 }
499 }
500 }
501 $linecount++;
502 }
503 }
504 else {
505 $name = "VCALENDAR";
506 $this->curnode = new ZCiCalNode($name, $this->curnode);
507 $this->tree = $this->curnode;
508 $datanode = new ZCiCalDataNode("VERSION:2.0");
509 $this->curnode->data[$datanode->getName()] = $datanode;
510
511 $datanode = new ZCiCalDataNode("PRODID:-//ZContent.net//Zap Calendar 1.0//EN");
512 $this->curnode->data[$datanode->getName()] = $datanode;
513 $datanode = new ZCiCalDataNode("CALSCALE:GREGORIAN");
514 $this->curnode->data[$datanode->getName()] = $datanode;
515 $datanode = new ZCiCalDataNode("METHOD:PUBLISH");
516 $this->curnode->data[$datanode->getName()] = $datanode;
517 }
518 }
519
520 /**
521 * CountEvents()
522 *
523 * Return the # of VEVENTs in the object
524 *
525 * @return int
526 */
527
528 function countEvents() {
529 $count = 0;
530 if(isset($this->tree->child)){
531 foreach($this->tree->child as $child){
532 if($child->getName() == "VEVENT")
533 $count++;
534 }
535 }
536 return $count;
537 }
538
539 /**
540 * CountVenues()
541 *
542 * Return the # of VVENUEs in the object
543 *
544 * @return int
545 */
546
547 function countVenues() {
548 $count = 0;
549 if(isset($this->tree->child)){
550 foreach($this->tree->child as $child){
551 if($child->getName() == "VVENUE")
552 $count++;
553 }
554 }
555 return $count;
556 }
557
558 /**
559 * Export object to string
560 *
561 * This function exports all objects to an iCalendar string
562 *
563 * @return string an iCalendar formatted string
564 */
565
566 function export() {
567 return $this->tree->export($this->tree);
568 }
569
570 /**
571 * Get first event in object list
572 * Use getNextEvent() to navigate through list
573 *
574 * @return object The first event, or null
575 */
576 function &getFirstEvent() {
577 static $nullguard = null;
578 if ($this->countEvents() > 0){
579 $child = $this->tree->child[0];
580 $event=false;
581 while(!$event && $child != null){
582 if($child->getName() == "VEVENT")
583 $event = true;
584 else
585 $child = $child->next;
586 }
587 return $child;
588 }
589 else
590 return $nullguard;
591 }
592
593 /**
594 * Get next event in object list
595 *
596 * @param object $event The current event object
597 *
598 * @return object Returns the next event or null if past last event
599 */
600 function &getNextEvent($event){
601 do{
602 $event = $event->next;
603 } while($event != null && $event->getName() != "VEVENT");
604 return $event;
605 }
606
607 /**
608 * Get first venue in object list
609 * Use getNextVenue() to navigate through list
610 *
611 * @return object The first venue, or null
612 */
613 function &getFirstVenue() {
614 static $nullguard = null;
615 if ($this->countVenues() > 0){
616 $child = $this->tree->child[0];
617 $event=false;
618 while(!$event && $child != null){
619 if($child->getName() == "VVENUE")
620 $event = true;
621 else
622 $child = $child->next;
623 }
624 return $child;
625 }
626 else
627 return $nullguard;
628 }
629
630 /**
631 * Get next venue in object list
632 *
633 * @param object $venue The current venue object
634 *
635 * @return object Returns the next venue or null if past last venue
636 */
637 function &getNextVenue($venue){
638 do{
639 $venue = $venue->next;
640 } while($venue != null && $venue->getName() != "VVENUE");
641 return $venue;
642 }
643
644 /**
645 * Get first child in object list
646 * Use getNextSibling() and getPreviousSibling() to navigate through list
647 *
648 * @param object $thisnode The parent object
649 *
650 * @return object The child object
651 */
652 function &getFirstChild(& $thisnode){
653 $nullvalue = null;
654 if(count($thisnode->child) > 0) {
655 //echo "moving from " . $thisnode->getName() . " to " . $thisnode->child[0]->getName() . "<br/>";
656 return $thisnode->child[0];
657 }
658 else
659 return $nullvalue;
660 }
661
662 /**
663 * Get next sibling in object list
664 *
665 * @param object $thisnode The current object
666 *
667 * @return object Returns the next sibling
668 */
669 function &getNextSibling(& $thisnode){
670 return $thisnode->next;
671 }
672
673 /**
674 * Get previous sibling in object list
675 *
676 * @param object $thisnode The current object
677 *
678 * @return object Returns the previous sibling
679 */
680 function &getPrevSibling(& $thisnode){
681 return $thisnode->prev;
682 }
683
684 /**
685 * Read date/time in iCal formatted string
686 *
687 * @param string iCal formated date/time string
688 *
689 * @return int Unix timestamp
690 */
691
692 function toUnixDateTime($datetime){
693 $year = substr($datetime,0,4);
694 $month = substr($datetime,4,2);
695 $day = substr($datetime,6,2);
696 $hour = 0;
697 $minute = 0;
698 $second = 0;
699 if(strlen($datetime) > 8 && $datetime{8} == "T") {
700 $hour = substr($datetime,9,2);
701 $minute = substr($datetime,11,2);
702 $second = substr($datetime,13,2);
703 }
704 $d1 = mktime($hour, $minute, $second, $month, $day, $year);
705
706 }
707
708 /**
709 * fromUnixDateTime()
710 *
711 * Take Unix timestamp and format to iCal date/time string
712 *
713 * @param int $datetime Unix timestamp, leave blank for current date/time
714 *
715 * @return string formatted iCal date/time string
716 */
717
718 static function fromUnixDateTime($datetime = null){
719 date_default_timezone_set('UTC');
720 if($datetime == null)
721 $datetime = time();
722 return date("Ymd\THis",$datetime);
723 }
724
725
726 /**
727 * fromUnixDate()
728 *
729 * Take Unix timestamp and format to iCal date string
730 *
731 * @param int $datetime Unix timestamp, leave blank for current date/time
732 *
733 * @return string formatted iCal date string
734 */
735
736 static function fromUnixDate($datetime = null){
737 date_default_timezone_set('UTC');
738 if($datetime == null)
739 $datetime = time();
740 return date("Ymd",$datetime);
741 }
742
743 /**
744 * Format into iCal time format from SQL date or SQL date-time format
745 *
746 * @param string $datetime SQL date or SQL date-time string
747 *
748 * @return string iCal formatted string
749 */
750 static function fromSqlDateTime($datetime = ""){
751 if($datetime == "")
752 $datetime = ZDateHelper::toSqlDateTime();
753 if(strlen($datetime) > 10)
754 return sprintf('%04d%02d%02dT%02d%02d%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2),
755 substr($datetime,11,2),substr($datetime,14,2),substr($datetime,17,2));
756 else
757 return sprintf('%04d%02d%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2));
758 }
759
760 /**
761 * Format iCal time format to either SQL date or SQL date-time format
762 *
763 * @param string $datetime icalendar formatted date or date-time
764 *
765 * @return string SQL date or SQL date-time string
766 */
767 static function toSqlDateTime($datetime = ""){
768 if($datetime == "")
769 return ZDateHelper::toSqlDateTime();
770 if(strlen($datetime) > 10)
771 return sprintf('%04d-%02d-%02d %02d:%02d:%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2),
772 substr($datetime,11,2),substr($datetime,14,2),substr($datetime,17,2));
773 else
774 return sprintf('%04d-%02d-%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2));
775 }
776
777 /**
778 * Pull timezone data from node and put in array
779 *
780 * Returning array contains the following array keys: tzoffsetfrom, tzoffsetto, tzname, dtstart, rrule
781 *
782 * @param array $node timezone object
783 *
784 * @return array
785 */
786 static function getTZValues($node){
787 $tzvalues = array();
788
789 $tnode = @$node->data['TZOFFSETFROM'];
790 if($tnode != null){
791 $tzvalues["tzoffsetfrom"] = $tnode->getValues();
792 }
793
794 $tnode = @$node->data['TZOFFSETTO'];
795 if($tnode != null){
796 $tzvalues["tzoffsetto"] = $tnode->getValues();
797 }
798
799 $tnode = @$node->data['TZNAME'];
800 if($tnode != null){
801 $tzvalues["tzname"] = $tnode->getValues();
802 }
803 else
804 $tzvalues["tzname"] = "";
805
806 $tnode = @$node->data['DTSTART'];
807 if($tnode != null){
808 $tzvalues["dtstart"] = ZDateHelper::fromiCaltoUnixDateTime($tnode->getValues());
809 }
810
811 $tnode = @$node->data['RRULE'];
812 if($tnode != null){
813 $tzvalues["rrule"] = $tnode->getValues();
814 //echo "rule: " . $tzvalues["rrule"] . "<br/>\n";
815 }
816 else{
817 // no rule specified, let's create one from based on the date
818 $date = getdate($tzvalues["dtstart"]);
819 $month = $date["mon"];
820 $day = $date["mday"];
821 $tzvalues["rrule"] = "FREQ=YEARLY;INTERVAL=1;BYMONTH=$month;BYMONTHDAY=$day";
822 }
823
824 return $tzvalues;
825 }
826
827 /**
828 * Escape slashes, commas and semicolons in strings
829 *
830 * @param string $content
831 *
832 * @return escaped string
833 */
834 static function formatContent($content)
835 {
836 $content = str_replace(array('\\' , ',' , ';' ), array('\\\\' , '\\,' , '\\;' ),$content);
837 return $content;
838 }
839
840 }