PluginProbe
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar / 2.1.21
Booking Manager – Sync WP Booking Calendar – Import Events, Export Bookings to ICS Calendar v2.1.21
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.1.21, at assets/libs/icalendar/includes/ical.php

901 lines 22.8 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] == ':') //FixIn: 2.0.17.1
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 // FixIn: 2025-08-11. 12:52
294 /**
295 * Find a safe byte index to cut $s at, not exceeding $maxBytes.
296 * - Prefer last ' ' or ',' or ';' <= $maxBytes
297 * - Avoid cutting immediately after a backslash (to keep escapes like "\n" intact)
298 * - Ensure we don't split a UTF-8 code point
299 * Returns byte length to keep.
300 */
301 private static function _utf8_safe_cut_pos( $s, $maxBytes ) {
302 $len = strlen( $s );
303 if ( $len <= $maxBytes ) {
304 return $len;
305 }
306
307 // Start with hard limit
308 $cut = $maxBytes;
309
310 // Prefer last breakable char within the current window
311 $window = substr( $s, 0, $cut );
312 $lastSpace = strrpos( $window, ' ' );
313 $lastComma = strrpos( $window, ',' );
314 $lastSemi = strrpos( $window, ';' );
315 $pref = max( $lastSpace === false ? - 1 : $lastSpace, $lastComma === false ? - 1
316 : $lastComma, $lastSemi === false ? - 1 : $lastSemi );
317
318 if ( $pref >= 0 ) {
319 $cut = $pref + 1; // cut *after* the delimiter/space so it stays on line
320 }
321
322 // Avoid cutting right after backslash (don’t break "\n", "\,", "\;", "\\")
323 if ( $cut > 0 && $s[ $cut - 1 ] === '\\' ) {
324 $cut -= 1;
325 if ( $cut <= 0 ) {
326 $cut = $maxBytes;
327 } // fallback
328 }
329
330 // Ensure we don't chop inside a UTF-8 multibyte char
331 // Move back until at start of a UTF-8 code point
332 while ( $cut > 0 && ( ord( $s[ $cut ] ) & 0xC0 ) === 0x80 ) {
333 $cut --;
334 }
335 if ( $cut <= 0 ) {
336 $cut = $maxBytes;
337 } // ultimate fallback
338
339 return $cut;
340 }
341
342 /**
343 * Fold one logical line into RFC 5545 physical lines.
344 * $firstWidth = 75 octets, $contWidth = 74 octets.
345 */
346 private static function _fold_ical_line( $line, $firstWidth = 75, $contWidth = 74 ) {
347 $out = '';
348 $first = true;
349 while ( strlen( $line ) > 0 ) {
350 $width = $first ? $firstWidth : $contWidth;
351 $cut = self::_utf8_safe_cut_pos( $line, $width );
352 $chunk = substr( $line, 0, $cut );
353 $line = substr( $line, $cut );
354 if ( ! $first ) {
355 $out .= ' ';
356 }
357 $out .= $chunk . "\r\n";
358 $first = false;
359 }
360
361 return $out;
362 }
363
364
365 /**
366 * export tree to icalendar format
367 *
368 * @param object $node Top level node to export
369 *
370 * @param int $level Level of recursion (usually leave this blank)
371 *
372 * @return string iCalendar formatted output
373 */
374 function export(& $node=null, $level=0){
375 $txtstr = "";
376 if($node == null)
377 $node = $this;
378 if($level > 5)
379 {
380 //die("levels nested too deep<br/>\n");
381 throw new Exception("levels nested too deep");
382 }
383 $txtstr .= "BEGIN:" . $node->getName() . "\r\n";
384 foreach ($node->data as $d){
385 $p = "";
386 $params = @$d->getParameters();
387 if(count($params) > 0)
388 {
389 foreach($params as $key => $value){
390 $p .= ";" . strtoupper($key) . "=" . $value;
391 }
392 }
393 $values = $d->getValues();
394
395 $line = $d->getName() . $p . ":" . $values;
396 $line = str_replace( array( "<br>", "<BR>", "<br/>", "<BR/" ), "\\n", $line );
397 $line = str_replace( array( "\r\n", "\n\r", "\n", "\r" ), '\n', $line );
398
399 // FixIn: 2025-08-11 12:53.
400 $txtstr .= self::_fold_ical_line( $line );
401 }
402 foreach ($node->child as $c){
403 $txtstr .= $node->export($c,$level + 1);
404 }
405 $txtstr .= "END:" . $node->getName() . "\r\n";
406 return $txtstr;
407 }
408
409 }
410
411 /**
412 *
413 * The main iCalendar object containing ZCiCalDataNodes and ZCiCalNodes.
414 *
415 */
416 class ZCiCal {
417 var $tree=null;
418 var $curnode=null;
419
420 /**
421 * The main iCalendar object containing ZCiCalDataNodes and ZCiCalNodes.
422 *
423 * use maxevents and startevent to read events in multiple passes (to save memory)
424 *
425 * @param string $data icalendar feed string (empty if creating new feed)
426 *
427 * @param int $maxevents maximum # of events to read
428 *
429 * @param int $startevent starting event to read
430 *
431 * @return void
432 *
433 *
434 */
435 // function ZCiCal ($data = "", $maxevents = 1000000, $startevent = 0) {
436 public function __construct( $data = "", $maxevents = 1000000, $startevent = 0) { //FixIn: 2.0.1.5
437 if($data != ""){
438 // unfold lines
439 // first change all eol chars to "\n"
440 $data = str_replace(array("\r\n", "\n\r", "\n", "\r"), "\n", $data);
441 // now unfold lines
442 //$data = str_replace(array("\n ", "\n "),"!?", $data);
443 $data = str_replace(array("\n ", "\n "),"", $data);
444 // replace special iCal chars
445 $data = str_replace(array("\\\\","\,"),array("\\",","), $data);
446
447 // parse each line
448 $lines = explode("\n", $data);
449
450 //echo $data;
451 //exit;
452 $linecount = 0;
453 $eventcount = 0;
454 $eventpos = 0;
455 foreach($lines as $line) {
456 //$line = str_replace("!?", "\n", $line); // add nl back into descriptions
457 // echo ($linecount + 1) . ": " . $line . "<br/>";
458 if(substr($line,0,6) == "BEGIN:") {
459 // start new object
460 $name = substr($line,6);
461 if($name == "VEVENT")
462 {
463 if($eventcount < $maxevents && $eventpos >= $startevent)
464 {
465 $this->curnode = new ZCiCalNode($name, $this->curnode);
466 if($this->tree == null)
467 $this->tree = $this->curnode;
468 }
469 }
470 else
471 {
472 $this->curnode = new ZCiCalNode($name, $this->curnode);
473 if($this->tree == null)
474 $this->tree = $this->curnode;
475 }
476 //echo "new node: " . $this->curnode->name . "<br/>\n";
477 /*
478 if($this->curnode->getParent() != null)
479 echo "parent of " . $this->curnode->getName() . " is " . $this->curnode->getParent()->getName() . "<br/>";
480 else
481 echo "parent of " . $this->curnode->getName() . " is null<br/>";
482 */
483 }
484 else if(substr($line,0,4) == "END:") {
485 $name = substr($line,4);
486 if($name == "VEVENT")
487 {
488 if($eventcount < $maxevents && $eventpos >= $startevent)
489 {
490 $eventcount++;
491 if($this->curnode->getName() != $name) {
492 //panic, mismatch in iCal structure
493 //die("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
494 throw new Exception("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
495 }
496 if($this->curnode->getParent() != null) {
497 //echo "moving up from " . $this->curnode->getName() ;
498 $this->curnode = & $this->curnode->getParent();
499 //echo " to " . $this->curnode->getName() . "<br/>";
500 //echo $this->curnode->getName() . " has " . count($this->curnode->child) . " children<br/>";
501 }
502 }
503 $eventpos++;
504 }
505 else
506 {
507 if($this->curnode->getName() != $name) {
508 //panic, mismatch in iCal structure
509 //die("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
510 throw new Exception("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
511 }
512 if($this->curnode->getParent() != null) {
513 //echo "moving up from " . $this->curnode->getName() ;
514 $this->curnode = & $this->curnode->getParent();
515 //echo " to " . $this->curnode->getName() . "<br/>";
516 //echo $this->curnode->getName() . " has " . count($this->curnode->child) . " children<br/>";
517 }
518 }
519 }
520 else {
521 $datanode = new ZCiCalDataNode($line);
522 if($this->curnode->getName() == "VEVENT")
523 {
524 if($eventcount < $maxevents && $eventpos >= $startevent)
525 {
526 if($datanode->getName() == "EXDATE")
527 {
528 if(!array_key_exists($datanode->getName(),$this->curnode->data))
529 {
530 $this->curnode->data[$datanode->getName()] = $datanode;
531 }
532 else
533 {
534 $this->curnode->data[$datanode->getName()]->value[] = $datanode->value[0];
535 }
536 }
537 else
538 {
539 $this->curnode->data[$datanode->getName()] = $datanode;
540 }
541 }
542 }
543 else
544 {
545 if($datanode->getName() == "EXDATE")
546 {
547 if(!array_key_exists($datanode->getName(),$this->curnode->data))
548 {
549 $this->curnode->data[$datanode->getName()] = $datanode;
550 }
551 else
552 {
553 $this->curnode->data[$datanode->getName()]->value[] = $datanode->value[0];
554 }
555 }
556 else
557 {
558 $this->curnode->data[$datanode->getName()] = $datanode;
559 }
560 }
561 }
562 $linecount++;
563 }
564 }
565 else {
566 $name = "VCALENDAR";
567 $this->curnode = new ZCiCalNode($name, $this->curnode);
568 $this->tree = $this->curnode;
569 $datanode = new ZCiCalDataNode("VERSION:2.0");
570 $this->curnode->data[$datanode->getName()] = $datanode;
571
572 $datanode = new ZCiCalDataNode("PRODID:-//ZContent.net//Zap Calendar 1.0//EN");
573 $this->curnode->data[$datanode->getName()] = $datanode;
574 $datanode = new ZCiCalDataNode("CALSCALE:GREGORIAN");
575 $this->curnode->data[$datanode->getName()] = $datanode;
576 $datanode = new ZCiCalDataNode("METHOD:PUBLISH");
577 $this->curnode->data[$datanode->getName()] = $datanode;
578 }
579 }
580
581 /**
582 * CountEvents()
583 *
584 * Return the # of VEVENTs in the object
585 *
586 * @return int
587 */
588
589 function countEvents() {
590 $count = 0;
591 if(isset($this->tree->child)){
592 foreach($this->tree->child as $child){
593 if($child->getName() == "VEVENT")
594 $count++;
595 }
596 }
597 return $count;
598 }
599
600 /**
601 * CountVenues()
602 *
603 * Return the # of VVENUEs in the object
604 *
605 * @return int
606 */
607
608 function countVenues() {
609 $count = 0;
610 if(isset($this->tree->child)){
611 foreach($this->tree->child as $child){
612 if($child->getName() == "VVENUE")
613 $count++;
614 }
615 }
616 return $count;
617 }
618
619 /**
620 * Export object to string
621 *
622 * This function exports all objects to an iCalendar string
623 *
624 * @return string an iCalendar formatted string
625 */
626
627 function export() {
628 return $this->tree->export($this->tree);
629 }
630
631 /**
632 * Get first event in object list
633 * Use getNextEvent() to navigate through list
634 *
635 * @return object The first event, or null
636 */
637 function &getFirstEvent() {
638 static $nullguard = null;
639 if ($this->countEvents() > 0){
640 $child = $this->tree->child[0];
641 $event=false;
642 while(!$event && $child != null){
643 if($child->getName() == "VEVENT")
644 $event = true;
645 else
646 $child = $child->next;
647 }
648 return $child;
649 }
650 else
651 return $nullguard;
652 }
653
654 /**
655 * Get next event in object list
656 *
657 * @param object $event The current event object
658 *
659 * @return object Returns the next event or null if past last event
660 */
661 function &getNextEvent($event){
662 do{
663 $event = $event->next;
664 } while($event != null && $event->getName() != "VEVENT");
665 return $event;
666 }
667
668 /**
669 * Get first venue in object list
670 * Use getNextVenue() to navigate through list
671 *
672 * @return object The first venue, or null
673 */
674 function &getFirstVenue() {
675 static $nullguard = null;
676 if ($this->countVenues() > 0){
677 $child = $this->tree->child[0];
678 $event=false;
679 while(!$event && $child != null){
680 if($child->getName() == "VVENUE")
681 $event = true;
682 else
683 $child = $child->next;
684 }
685 return $child;
686 }
687 else
688 return $nullguard;
689 }
690
691 /**
692 * Get next venue in object list
693 *
694 * @param object $venue The current venue object
695 *
696 * @return object Returns the next venue or null if past last venue
697 */
698 function &getNextVenue($venue){
699 do{
700 $venue = $venue->next;
701 } while($venue != null && $venue->getName() != "VVENUE");
702 return $venue;
703 }
704
705 /**
706 * Get first child in object list
707 * Use getNextSibling() and getPreviousSibling() to navigate through list
708 *
709 * @param object $thisnode The parent object
710 *
711 * @return object The child object
712 */
713 function &getFirstChild(& $thisnode){
714 $nullvalue = null;
715 if(count($thisnode->child) > 0) {
716 //echo "moving from " . $thisnode->getName() . " to " . $thisnode->child[0]->getName() . "<br/>";
717 return $thisnode->child[0];
718 }
719 else
720 return $nullvalue;
721 }
722
723 /**
724 * Get next sibling in object list
725 *
726 * @param object $thisnode The current object
727 *
728 * @return object Returns the next sibling
729 */
730 function &getNextSibling(& $thisnode){
731 return $thisnode->next;
732 }
733
734 /**
735 * Get previous sibling in object list
736 *
737 * @param object $thisnode The current object
738 *
739 * @return object Returns the previous sibling
740 */
741 function &getPrevSibling(& $thisnode){
742 return $thisnode->prev;
743 }
744
745 /**
746 * Read date/time in iCal formatted string
747 *
748 * @param string iCal formated date/time string
749 *
750 * @return int Unix timestamp
751 */
752
753 function toUnixDateTime($datetime){
754 $year = substr($datetime,0,4);
755 $month = substr($datetime,4,2);
756 $day = substr($datetime,6,2);
757 $hour = 0;
758 $minute = 0;
759 $second = 0;
760 if(strlen($datetime) > 8 && $datetime[8] == "T") { //FixIn: 2.0.17.1
761 $hour = substr($datetime,9,2);
762 $minute = substr($datetime,11,2);
763 $second = substr($datetime,13,2);
764 }
765 $d1 = mktime($hour, $minute, $second, $month, $day, $year);
766
767 }
768
769 /**
770 * fromUnixDateTime()
771 *
772 * Take Unix timestamp and format to iCal date/time string
773 *
774 * @param int $datetime Unix timestamp, leave blank for current date/time
775 *
776 * @return string formatted iCal date/time string
777 */
778
779 static function fromUnixDateTime($datetime = null){
780 date_default_timezone_set('UTC');
781 if($datetime == null)
782 $datetime = time();
783 return date("Ymd\THis",$datetime);
784 }
785
786
787 /**
788 * fromUnixDate()
789 *
790 * Take Unix timestamp and format to iCal date string
791 *
792 * @param int $datetime Unix timestamp, leave blank for current date/time
793 *
794 * @return string formatted iCal date string
795 */
796
797 static function fromUnixDate($datetime = null){
798 date_default_timezone_set('UTC');
799 if($datetime == null)
800 $datetime = time();
801 return date("Ymd",$datetime);
802 }
803
804 /**
805 * Format into iCal time format from SQL date or SQL date-time format
806 *
807 * @param string $datetime SQL date or SQL date-time string
808 *
809 * @return string iCal formatted string
810 */
811 static function fromSqlDateTime($datetime = ""){
812 if($datetime == "")
813 $datetime = ZDateHelper::toSqlDateTime();
814 if(strlen($datetime) > 10)
815 return sprintf('%04d%02d%02dT%02d%02d%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2),
816 substr($datetime,11,2),substr($datetime,14,2),substr($datetime,17,2));
817 else
818 return sprintf('%04d%02d%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2));
819 }
820
821 /**
822 * Format iCal time format to either SQL date or SQL date-time format
823 *
824 * @param string $datetime icalendar formatted date or date-time
825 *
826 * @return string SQL date or SQL date-time string
827 */
828 static function toSqlDateTime($datetime = ""){
829 if($datetime == "")
830 return ZDateHelper::toSqlDateTime();
831 if(strlen($datetime) > 10)
832 return sprintf('%04d-%02d-%02d %02d:%02d:%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2),
833 substr($datetime,11,2),substr($datetime,14,2),substr($datetime,17,2));
834 else
835 return sprintf('%04d-%02d-%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2));
836 }
837
838 /**
839 * Pull timezone data from node and put in array
840 *
841 * Returning array contains the following array keys: tzoffsetfrom, tzoffsetto, tzname, dtstart, rrule
842 *
843 * @param array $node timezone object
844 *
845 * @return array
846 */
847 static function getTZValues($node){
848 $tzvalues = array();
849
850 $tnode = @$node->data['TZOFFSETFROM'];
851 if($tnode != null){
852 $tzvalues["tzoffsetfrom"] = $tnode->getValues();
853 }
854
855 $tnode = @$node->data['TZOFFSETTO'];
856 if($tnode != null){
857 $tzvalues["tzoffsetto"] = $tnode->getValues();
858 }
859
860 $tnode = @$node->data['TZNAME'];
861 if($tnode != null){
862 $tzvalues["tzname"] = $tnode->getValues();
863 }
864 else
865 $tzvalues["tzname"] = "";
866
867 $tnode = @$node->data['DTSTART'];
868 if($tnode != null){
869 $tzvalues["dtstart"] = ZDateHelper::fromiCaltoUnixDateTime($tnode->getValues());
870 }
871
872 $tnode = @$node->data['RRULE'];
873 if($tnode != null){
874 $tzvalues["rrule"] = $tnode->getValues();
875 //echo "rule: " . $tzvalues["rrule"] . "<br/>\n";
876 }
877 else{
878 // no rule specified, let's create one from based on the date
879 $date = getdate($tzvalues["dtstart"]);
880 $month = $date["mon"];
881 $day = $date["mday"];
882 $tzvalues["rrule"] = "FREQ=YEARLY;INTERVAL=1;BYMONTH=$month;BYMONTHDAY=$day";
883 }
884
885 return $tzvalues;
886 }
887
888 /**
889 * Escape slashes, commas and semicolons in strings
890 *
891 * @param string $content
892 *
893 * @return escaped string
894 */
895 static function formatContent($content)
896 {
897 $content = str_replace(array('\\' , ',' , ';' ), array('\\\\' , '\\,' , '\\;' ),$content);
898 return $content;
899 }
900
901 }