PluginProbe
ShiftController Employee Shift Scheduling / 4.9.66
ShiftController Employee Shift Scheduling v4.9.66
4.9.97 4.9.96 4.9.95 4.9.74 4.9.75 4.9.76 4.9.77 4.9.78 4.9.84 4.9.85 4.9.87 4.9.91 4.9.92 trunk 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 3.2.4 All 38 releases
shiftcontroller / sh4 / ical / lib / icalcreator.php

icalcreator.php in ShiftController Employee Shift Scheduling 4.9.66, at sh4/ical/lib/icalcreator.php

3,817 lines 137.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php if (! defined('ABSPATH')) exit; // Exit if accessed directly
2 /*********************************************************************************/
3 /**
4 * iCalcreator class v2.6
5 * copyright (c) 2007-2008 Kjell-Inge Gustafsson kigkonsult
6 * www.kigkonsult.se/iCalcreator/index.php
7 * ical@kigkonsult.se
8 *
9 * Description:
10 * This file is a PHP implementation of RFC 2445.
11 *
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
16 *
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
21 *
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26 /*********************************************************************************/
27 /*********************************************************************************/
28 /* A little setup */
29 /*********************************************************************************/
30 /* your local language code */
31 // define( 'ICAL_LANG', 'sv' );
32 // alt. autosetting
33 /*
34 $langstr = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
35 $pos = strpos( $langstr, ';' );
36 if ($pos !== false) {
37 $langstr = substr( $langstr, 0, $pos );
38 $pos = strpos( $langstr, ',' );
39 if ($pos !== false) {
40 $pos = strpos( $langstr, ',' );
41 $langstr = substr( $langstr, 0, $pos );
42 }
43 define( 'ICAL_LANG', $langstr );
44 }
45 */
46 /* only for phpversion 5.x, date management, default timezone setting */
47 if( substr( phpversion(), 0, 1) >= '5' ){ // && ( 'UTC' == date_default_timezone_get() )) {
48 // date_default_timezone_set( 'UTC' );
49 }
50 /* version string, do NOT remove!! */
51 if( ! defined('HC_ICALCREATOR_VERSION') ){
52 define( 'HC_ICALCREATOR_VERSION', 'iCalcreator 2.6' );
53 }
54 /*********************************************************************************/
55 /*********************************************************************************/
56 /**
57 * vcalendar class
58 *
59 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
60 * @since 2.2.13 - 2007-12-30
61 */
62 class SH4_Ical_Lib_iCalCreator {
63 // calendar property variables
64 public $method;
65 public $prodid;
66 public $version;
67 public $xprop;
68 // container for calendar components
69 public $components;
70 // component config variables
71 public $allowEmpty;
72 public $unique_id;
73 public $language;
74 public $url;
75 public $delimiter;
76 public $nl;
77 public $format;
78 // component internal variables
79 public $attributeDelimiter;
80 public $valueInit;
81 // component xCal declaration container
82 public $xcaldecl;
83 /*
84 * constructor for calendar object
85 *
86 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
87 * @since 2.2.13 - 2007-12-30
88 * @return void
89 */
90 function __construct(
91 )
92 {
93 $this->_makeVersion();
94 $this->method = null;
95 $this->_makeUnique_id();
96 $this->prodid = null;
97 $this->xprop = array();
98 /**
99 * language = <Text identifying a language, as defined in [RFC 1766]>
100 */
101 if( defined( 'ICAL_LANG' ))
102 $this->setConfig( 'language', ICAL_LANG );
103 $this->setConfig( 'allowEmpty', TRUE );
104 // $this->setConfig( 'nl', "\n" );
105 $this->setConfig( 'nl', "\r\n" );
106 $this->setConfig( 'format', 'iCal');
107 $this->url = null;
108 $this->setConfig( 'delimiter', DIRECTORY_SEPARATOR );
109 $this->xcaldecl = array();
110 $this->components = array();
111 }
112 /*********************************************************************************/
113 /**
114 * Property Name: METHOD
115 */
116 /**
117 * creates formatted output for calendar property method
118 *
119 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
120 * @since 0.9.7 - 2006-11-20
121 * @return string
122 */
123 function createMethod() {
124 if( empty( $this->method )) return FALSE;
125 switch( $this->format ) {
126 case 'xcal':
127 return ' method="'.$this->method.'"'.$this->nl;
128 break;
129 default:
130 return 'METHOD:'.$this->method.$this->nl;
131 break;
132 }
133 }
134 /**
135 * set calendar property method
136 *
137 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
138 * @since 2.4.8 - 2008-20-23
139 * @param string $value
140 * @return bool
141 */
142 function setMethod( $value ) {
143 if( empty( $value )) return FALSE;
144 $this->method = strtoupper($value);
145 return TRUE;
146 }
147 /*********************************************************************************/
148 /**
149 * Property Name: PRODID
150 *
151 * The identifier is RECOMMENDED to be the identical syntax to the
152 * [RFC 822] addr-spec. A good method to assure uniqueness is to put the
153 * domain name or a domain literal IP address of the host on which.. .
154 */
155 /**
156 * creates formatted output for calendar property prodid
157 *
158 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
159 * @since 0.9.7 - 2006-11-20
160 * @return string
161 */
162 function createProdid() {
163 if( !isset( $this->prodid ))
164 $this->_makeProdid();
165 switch( $this->format ) {
166 case 'xcal':
167 return ' prodid="'.$this->prodid.'"'.$this->nl;
168 break;
169 default:
170 return 'PRODID:'.$this->prodid.$this->nl;
171 break;
172 }
173 }
174 /**
175 * make default value for calendar prodid
176 *
177 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
178 * @since 0.3.0 - 2006-08-10
179 * @return void
180 */
181 function _makeProdid() {
182 // $this->prodid = '-//'.$this->unique_id.'//NONSGML '.HC_ICALCREATOR_VERSION.'//'.strtoupper( $this->language );
183 // $this->prodid = '-//'.$this->unique_id.'//NONSGML ical';
184 // $this->prodid = '-//plainware//NONSGML ical';
185 $this->prodid = 'plainware NONSGML ical';
186 }
187 /**
188 * Conformance: The property MUST be specified once in an iCalendar object.
189 * Description: The vendor of the implementation SHOULD assure that this
190 * is a globally unique identifier; using some technique such as an FPI
191 * value, as defined in [ISO 9070].
192 */
193 /**
194 * make default unique_id for calendar prodid
195 *
196 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
197 * @since 0.3.0 - 2006-08-10
198 * @return void
199 */
200 function _makeUnique_id() {
201 $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
202 }
203 /*********************************************************************************/
204 /**
205 * Property Name: VERSION
206 *
207 * Description: A value of "2.0" corresponds to this memo.
208 */
209 /**
210 * creates formatted output for calendar property version
211
212 *
213 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
214 * @since 0.9.7 - 2006-11-20
215 * @return string
216 */
217 function createVersion() {
218 if( empty( $this->version ))
219 $this->_makeVersion();
220 switch( $this->format ) {
221 case 'xcal':
222 return ' version="'.$this->version.'"'.$this->nl;
223 break;
224 default:
225 return 'VERSION:'.$this->version.$this->nl;
226 break;
227 }
228 }
229 /**
230 * set default calendar version
231 *
232 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
233 * @since 0.3.0 - 2006-08-10
234 * @return void
235 */
236 function _makeVersion() {
237 $this->version = '2.0';
238 }
239 /**
240 * set calendar version
241 *
242 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
243 * @since 2.4.8 - 2008-10-23
244 * @param string $value
245 * @return void
246 */
247 function setVersion( $value ) {
248 if( empty( $value )) return FALSE;
249 $this->version = $value;
250 return TRUE;
251 }
252 /*********************************************************************************/
253 /**
254 * Property Name: x-prop
255 */
256 /**
257 * creates formatted output for calendar property x-prop, iCal format only
258 *
259 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
260 * @since 2.4.11 - 2008-11-03
261 * @return string
262 */
263 function createXprop() {
264 if( 'xcal' == $this->format )
265 return false;
266 if( 0 >= count( $this->xprop ))
267 return;
268 $output = null;
269 $toolbox = new hc_calendarComponent();
270 $toolbox->setConfig( 'language', $this->getConfig( 'language' ));
271 $toolbox->setConfig( 'nl', $this->getConfig( 'nl' ));
272 $toolbox->_createFormat( $this->getConfig( 'format' ));
273 foreach( $this->xprop as $label => $xpropPart ) {
274 if( empty( $xpropPart['value'] )) {
275 $output .= $toolbox->_createElement( $label );
276 continue;
277 }
278 $attributes = $toolbox->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
279 if( is_array( $xpropPart['value'] )) {
280 foreach( $xpropPart['value'] as $pix => $theXpart )
281 $xpropPart['value'][$pix] = $toolbox->_strrep( $theXpart );
282 $xpropPart['value'] = implode( ',', $xpropPart['value'] );
283 }
284 else
285 $xpropPart['value'] = $toolbox->_strrep( $xpropPart['value'] );
286 $output .= $toolbox->_createElement( $label, $attributes, $xpropPart['value'] );
287 }
288 return $output;
289 }
290 /**
291 * set calendar property x-prop
292 *
293 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
294 * @since 2.4.11 - 2008-11-04
295 * @param string $label
296 * @param string $value
297 * @param array $params optional
298 * @return bool
299 */
300 function setXprop( $label, $value, $params=FALSE ) {
301 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
302 if( empty( $label )) return FALSE;
303 $xprop = array( 'value' => $value );
304 $toolbox = new hc_calendarComponent();
305 $xprop['params'] = $toolbox->_setParams( $params );
306 if( !is_array( $this->xprop )) $this->xprop = array();
307 $this->xprop[strtoupper( $label )] = $xprop;
308 return TRUE;
309 }
310
311 /**
312 * get calendar property value/params
313 *
314 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
315 * @since 2.5.1 - 2008-11-02
316 * @param string $propName, optional
317 * @param int @propix, optional, if specific property is wanted in case of multiply occurences
318 * @param bool $inclParam=FALSE
319 * @return mixed
320 */
321 function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE ) {
322 $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
323 if( 'X-PROP' == $propName ) {
324 if( !$propix )
325 $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
326 $this->propix[$propName] = --$propix;
327 }
328 switch( $propName ) {
329 case 'METHOD':
330 return ( !empty( $this->method )) ? $this->method : null;
331 break;
332 case 'PRODID':
333 if( empty( $this->prodid ))
334 $this->_makeProdid();
335 return $this->prodid;
336 break;
337 case 'VERSION':
338 return ( !empty( $this->version )) ? $this->version : null;
339 break;
340 default:
341 if( $propName != 'X-PROP' ) {
342 if( !isset( $this->xprop[$propName] )) return FALSE;
343 return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
344 : array( $propName, $this->xprop[$propName]['value'] );
345 }
346 else {
347 if( empty( $this->xprop )) return FALSE;
348 $xpropno = 0;
349 foreach( $this->xprop as $xpropkey => $xpropvalue ) {
350 if( $propix == $xpropno )
351 return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
352 : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
353 else
354 $xpropno++;
355 }
356 return FALSE; // not found ??
357 }
358 }
359 return FALSE;
360 }
361 /**
362 * general vcalendar property setting
363 *
364 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
365 * @since 2.2.13 - 2007-11-04
366 * @param mixed $args variable number of function arguments,
367 * first argument is ALWAYS component name,
368 * second ALWAYS component value!
369 * @return bool
370 */
371 function setProperty () {
372 $numargs = func_num_args();
373 if( 1 > $numargs )
374 return FALSE;
375 $arglist = func_get_args();
376 $arglist[0] = strtoupper( $arglist[0] );
377 switch( $arglist[0] ) {
378 case 'METHOD':
379 return $this->setMethod( $arglist[1] );
380 case 'VERSION':
381 return $this->setVersion( $arglist[1] );
382 default:
383 if( !isset( $arglist[1] )) $arglist[1] = null;
384 if( !isset( $arglist[2] )) $arglist[2] = null;
385 return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
386 }
387 return FALSE;
388 }
389 /*********************************************************************************/
390 /**
391 * get vcalendar config values or * calendar components
392 *
393 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
394 * @since 2.4.10 - 2008-10-23
395 * @param string $config
396 * @return value
397 */
398 function getConfig( $config ) {
399 switch( strtoupper( $config )) {
400 case 'ALLOWEMPTY':
401 return $this->allowEmpty;
402 break;
403 case 'COMPSINFO':
404 unset( $this->compix );
405 $info = array();
406 foreach( $this->components as $cix => $component ) {
407 if( empty( $component )) continue;
408 unset( $component->propix );
409 $info[$cix]['ordno'] = $cix + 1;
410 $info[$cix]['type'] = $component->objName;
411 $info[$cix]['uid'] = $component->getProperty( 'uid' );
412 $info[$cix]['props'] = $component->getConfig( 'propinfo' );
413 $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
414 unset( $component->propix );
415 }
416 return $info;
417 break;
418 case 'DELIMITER':
419 return $this->delimiter;
420 break;
421 case 'FORMAT':
422 return $this->format;
423 break;
424 case 'LANGUAGE':
425 /* get language for calendar component as defined in [RFC 1766] */
426 return $this->language;
427 break;
428 case 'NL':
429 case 'NEWLINECHAR':
430 return $this->nl;
431 break;
432 case 'UNIQUE_ID':
433 return $this->unique_id;
434 break;
435 case 'URL':
436 if( !empty( $this->url ))
437 return $this->url;
438 else
439 return FALSE;
440 break;
441 }
442 }
443 /**
444 * general vcalendar config setting
445 *
446 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
447 * @since 2.4.8 - 2008-10-24
448 * @param string $config
449 * @param string $value
450 * @return void
451 */
452 function setConfig( $config, $value ) {
453 $res = FALSE;
454 switch( strtoupper( $config )) {
455 case 'ALLOWEMPTY':
456 $this->allowEmpty = $value;
457 $subcfg = array( 'ALLOWEMPTY' => $value );
458 $res = TRUE;
459 break;
460 case 'DELIMITER':
461 $this->delimiter = $value;
462 return TRUE;
463 break;
464 case 'FORMAT':
465 $value = trim( $value );
466 if( 'xcal' == strtolower( $value )) {
467 $this->format = 'xcal';
468 $this->attributeDelimiter = $this->nl;
469 $this->valueInit = null;
470 }
471 else {
472 $this->format = null;
473 $this->attributeDelimiter = ';';
474 $this->valueInit = ':';
475 }
476 $subcfg = array( 'FORMAT' => $value );
477 $res = TRUE;
478 break;
479 case 'LANGUAGE':
480 // set language for calendar component as defined in [RFC 1766]
481 $value = trim( $value );
482 $this->language = $value;
483 $subcfg = array( 'LANGUAGE' => $value );
484 $res = TRUE;
485 break;
486 case 'NL':
487 case 'NEWLINECHAR':
488 $this->nl = $value;
489 $subcfg = array( 'NL' => $value );
490 $res = TRUE;
491 break;
492 case 'UNIQUE_ID':
493 $value = trim( $value );
494 $this->unique_id = $value;
495 $subcfg = array( 'UNIQUE_ID' => $value );
496 $res = TRUE;
497 break;
498 }
499 if( !$res ) return FALSE;
500 if( isset( $subcfg ) && !empty( $this->components )) {
501 foreach( $subcfg as $cfgkey => $cfgvalue ) {
502 foreach( $this->components as $cix => $component ) {
503 $res = $component->setConfig( $cfgkey, $cfgvalue );
504 if( !$res )
505 break 2;
506 $this->components[$cix] = $component->copy(); // PHP4 compliant
507 }
508 }
509 }
510 return $res;
511 }
512 /*********************************************************************************/
513 /**
514 * add calendar component to container
515 *
516 * alias to setComponent
517 *
518 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
519 * @since 1.x.x - 2007-04-24
520 * @param object $component calendar component
521 * @return void
522 */
523 function addComponent( $component ) {
524 $this->setComponent( $component );
525 }
526 /**
527 * get calendar component from container
528 *
529 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
530 * @since 2.4.10 - 2008-08-06
531 * @param mixed $arg1 optional, ordno/component type/ component uid
532 * @param mixed $arg2 optional, ordno if arg1 = component type
533 * @return object
534 */
535 function getComponent( $arg1=FALSE, $arg2=FALSE ) {
536 $index = $argType = null;
537 if ( !$arg1 ) {
538 $argType = 'INDEX';
539 $index = $this->compix['INDEX'] =
540 ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
541 }
542 elseif ( ctype_digit( (string) $arg1 )) {
543 $argType = 'INDEX';
544 $index = (int) $arg1;
545 unset( $this->compix );
546 }
547 elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
548 unset( $this->compix['INDEX'] );
549 $argType = strtolower( $arg1 );
550 if( !$arg2 )
551 $index = $this->compix[$argType] =
552 ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
553 else
554 $index = (int) $arg2;
555 }
556 $index -= 1;
557 $ckeys = array_keys( $this->components );
558 if( !empty( $index) && ( $index > end( $ckeys )))
559 return FALSE;
560 $cix1gC = 0;
561 foreach ( $this->components as $cix => $component) {
562 if( empty( $component )) continue;
563 unset( $component->propix );
564 if(( 'INDEX' == $argType ) && ( $index == $cix ))
565 return $component->copy();
566 elseif( $argType == $component->objName ) {
567 if( $index == $cix1gC )
568 return $component->copy();
569 $cix1gC++;
570 }
571 elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
572 unset( $component->propix );
573 return $component->copy();
574 }
575 }
576 /* not found.. . */
577 unset( $this->compix );
578 return FALSE;
579 }
580
581 /**
582 * add calendar component to container
583 *
584 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
585 * @since 2.4.10 - 2008-08-06
586 * @param object $component calendar component
587 * @param mixed $arg1 optional, ordno/component type/ component uid
588 * @param mixed $arg2 optional, ordno if arg1 = component type
589 * @return void
590 */
591 function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
592 if( '' >= $component->getConfig( 'language'))
593 $component->setConfig( 'language', $this->getConfig( 'language' ));
594 $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
595 $component->setConfig( 'nl', $this->getConfig( 'nl' ));
596 $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
597 $component->setConfig( 'format', $this->getConfig( 'format' ));
598 if( !in_array( $component->objName, array( 'hc_valarm', 'hc_vtimezone' ))) {
599 unset( $component->propix );
600 /* make sure dtstamp and uid is set */
601 $dummy1 = $component->getProperty( 'dtstamp' );
602 $dummy2 = $component->getProperty( 'uid' );
603 }
604 if( !$arg1 ) {
605 $this->components[] = $component->copy();
606 return TRUE;
607 }
608 $argType = $index = null;
609 if ( ctype_digit( (string) $arg1 )) {
610 $argType = 'INDEX';
611 $index = (int) $arg1 - 1;
612 }
613 elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
614 $argType = strtolower( $arg1 );
615 $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
616 }
617 $cix1sC = 0;
618 foreach ( $this->components as $cix => $component2) {
619 if( empty( $component2 )) continue;
620 unset( $component2->propix );
621 if(( 'INDEX' == $argType ) && ( $index == $cix )) {
622 $this->components[$cix] = $component->copy();
623 return TRUE;
624 }
625 elseif( $argType == $component2->objName ) {
626 if( $index == $cix1sC ) {
627 $this->components[$cix] = $component->copy();
628 return TRUE;
629 }
630 $cix1sC++;
631 }
632 elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) {
633 $this->components[$cix] = $component->copy();
634 return TRUE;
635 }
636 }
637 /* not found.. . insert last in chain anyway .. .*/
638 $this->components[] = $component->copy();
639 return TRUE;
640 }
641
642 /*********************************************************************************/
643 /**
644 * creates formatted output for calendar object instance
645 *
646 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
647 * @since 2.4.10 - 2008-08-06
648 * @return string
649 */
650 function createCalendar() {
651 $calendarInit1 = $calendarInit2 = $calendarxCaldecl = $calendarStart = $calendar = null;
652 switch( $this->format ) {
653 case 'xcal':
654 $calendarInit1 = '<?xml version="1.0" encoding="UTF-8"?>'.$this->nl.
655 '<!DOCTYPE iCalendar PUBLIC "-//IETF//DTD XCAL/iCalendar XML//EN"'.$this->nl.
656 '"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"';
657 $calendarInit2 = '>'.$this->nl;
658 $calendarStart = '<vcalendar';
659 break;
660 default:
661 $calendarStart = 'BEGIN:VCALENDAR'.$this->nl;
662 break;
663 }
664 $calendarStart .= $this->createMethod();
665 $calendarStart .= $this->createProdid();
666 $calendarStart .= $this->createVersion();
667 switch( $this->format ) {
668 case 'xcal':
669 $nlstrlen = strlen( $this->nl );
670 if( $this->nl == substr( $calendarStart, ( 0 - $nlstrlen )))
671 $calendarStart = substr( $calendarStart, 0, ( strlen( $calendarStart ) - $nlstrlen ));
672 $calendarStart .= '>'.$this->nl;
673 break;
674 default:
675 break;
676 }
677 $calendar .= $this->createXprop();
678 foreach( $this->components as $component ) {
679 if( empty( $component )) continue;
680 if( '' >= $component->getConfig( 'language'))
681 $component->setConfig( 'language', $this->getConfig( 'language' ));
682 $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
683 $component->setConfig( 'nl', $this->getConfig( 'nl' ));
684 $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
685 $component->setConfig( 'format', $this->getConfig( 'format' ));
686 $calendar .= $component->createComponent( $this->xcaldecl );
687 }
688 if(( 0 < count( $this->xcaldecl )) && ( 'xcal' == $this->format )) { // xCal only
689 $calendarInit1 .= $this->nl.'['.$this->nl;
690 $old_xcaldecl = array();
691 foreach( $this->xcaldecl as $declix => $declPart ) {
692 if(( 0 < count( $old_xcaldecl)) &&
693 ( in_array( $declPart['uri'], $old_xcaldecl['uri'] )) &&
694 ( in_array( $declPart['external'], $old_xcaldecl['external'] )))
695 continue; // no duplicate uri and ext. references
696 $calendarxCaldecl .= '<!';
697 foreach( $declPart as $declKey => $declValue ) {
698 switch( $declKey ) { // index
699 case 'xmldecl': // no 1
700 $calendarxCaldecl .= $declValue.' ';
701 break;
702 case 'uri': // no 2
703 $calendarxCaldecl .= $declValue.' ';
704 $old_xcaldecl['uri'][] = $declValue;
705 break;
706 case 'ref': // no 3
707 $calendarxCaldecl .= $declValue.' ';
708 break;
709 case 'external': // no 4
710 $calendarxCaldecl .= '"'.$declValue.'" ';
711 $old_xcaldecl['external'][] = $declValue;
712 break;
713 case 'type': // no 5
714 $calendarxCaldecl .= $declValue.' ';
715 break;
716 case 'type2': // no 6
717 $calendarxCaldecl .= $declValue;
718 break;
719 }
720 }
721 $calendarxCaldecl .= '>'.$this->nl;
722 }
723 $calendarInit2 = ']'.$calendarInit2;
724 }
725 switch( $this->format ) {
726 case 'xcal':
727 $calendar .= '</vcalendar>'.$this->nl;
728 break;
729 default:
730 $calendar .= 'END:VCALENDAR'.$this->nl;
731 break;
732 }
733 return $calendarInit1.$calendarxCaldecl.$calendarInit2.$calendarStart.$calendar;
734 }
735 }
736
737 /*********************************************************************************/
738 /*********************************************************************************/
739 /**
740 * abstract class for calendar components
741 *
742 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
743 * @since 2.4.19 - 2008-10-12
744 */
745 class hc_calendarComponent {
746 // component property variables
747 public $uid;
748 public $dtstamp;
749
750 // component config variables
751 public $allowEmpty;
752 public $language;
753 public $nl;
754 public $unique_id;
755 public $format;
756 public $objName; // created automatically at instance creation
757 // component internal variables
758 public $componentStart1;
759 public $componentStart2;
760 public $componentEnd1;
761 public $componentEnd2;
762 public $elementStart1;
763 public $elementStart2;
764 public $elementEnd1;
765 public $elementEnd2;
766 public $intAttrDelimiter;
767 public $attributeDelimiter;
768 public $valueInit;
769 // component xCal declaration container
770 public $xcaldecl;
771 /**
772 * constructor for calendar component object
773 *
774 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
775 * @since 2.4.19 - 2008-10-23
776 */
777 function __construct() {
778 $this->objName = ( isset( $this->timezonetype )) ?
779 strtolower( $this->timezonetype ) : get_class ( $this );
780
781 if( substr($this->objName, 0, strlen('hc_')) == 'hc_' ){
782 $this->objName = substr($this->objName, strlen('hc_'));
783 }
784
785 $this->uid = array();
786 $this->dtstamp = array();
787
788 $this->language = null;
789 $this->nl = null;
790 $this->unique_id = null;
791 $this->format = null;
792 $this->allowEmpty = TRUE;
793 $this->xcaldecl = array();
794
795 $this->_createFormat();
796 $this->_makeDtstamp();
797 }
798 /*********************************************************************************/
799 /**
800 * Property Name: ATTENDEE
801 */
802 /**
803 * creates formatted output for calendar component property attendee
804 *
805 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
806 * @since 2.4.8 - 2008-09-23
807 * @return string
808 */
809 function createAttendee() {
810 if( empty( $this->attendee )) return FALSE;
811 $output = null;
812 foreach( $this->attendee as $attendeePart ) { // start foreach 1
813 if( empty( $attendeePart['value'] )) {
814 if( $this->getConfig( 'allowEmpty' ))
815 $output .= $this->_createElement( 'ATTENDEE' );
816 continue;
817 }
818 $attendee1 = $attendee2 = $attendeeLANG = $attendeeCN = null;
819 foreach( $attendeePart as $paramlabel => $paramvalue ) { // start foreach 2
820 if( 'value' == $paramlabel )
821 $attendee2 .= 'MAILTO:'.$paramvalue;
822 elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) { // start elseif
823 foreach( $paramvalue as $optparamlabel => $optparamvalue ) { // start foreach 3
824 $attendee11 = $attendee12 = null;
825 if( is_int( $optparamlabel )) {
826 $attendee1 .= $this->intAttrDelimiter.$optparamvalue;
827 continue;
828 }
829 switch( $optparamlabel ) { // start switch
830 case 'CUTYPE':
831 case 'PARTSTAT':
832 case 'ROLE':
833 case 'RSVP':
834 $attendee1 .= $this->intAttrDelimiter.$optparamlabel.'="'.$optparamvalue.'"';
835 break;
836 case 'SENT-BY':
837 $attendee1 .= $this->intAttrDelimiter.'SENT-BY="MAILTO:'.$optparamvalue.'"';
838 break;
839 case 'CN':
840 $attendeeCN .= $this->intAttrDelimiter.'CN="'.$optparamvalue.'"';
841 break;
842 case 'DIR':
843 $attendee1 .= $this->intAttrDelimiter.'DIR="'.$optparamvalue.'"';
844 break;
845 case 'LANGUAGE':
846 $attendeeLANG .= $this->intAttrDelimiter.'LANGUAGE='.$optparamvalue;
847 break;
848 default:
849 $attendee1 .= $this->intAttrDelimiter."$optparamlabel=$optparamvalue";
850 break;
851 } // end switch
852 } // end foreach 3
853 } // end elseif
854 } // end foreach 2
855 $output .= $this->_createElement( 'ATTENDEE', $attendee1.$attendeeLANG.$attendeeCN, $attendee2 );
856 } // end foreach 1
857 return $output;
858 }
859 /**
860 * set calendar component property attendee
861 *
862 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
863 * @since 2.5.1 - 2008-11-05
864 * @param string $value
865 * @param array $params, optional
866 * @param integer $index, optional
867 * @return bool
868 */
869 function setAttendee( $value, $params=FALSE, $index=FALSE ) {
870 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
871 $value = str_replace ( 'MAILTO:', '', $value );
872 $value = str_replace ( 'mailto:', '', $value );
873 $params2 = array();
874 if( is_array($params )) {
875 $optarrays = array();
876 foreach( $params as $optparamlabel => $optparamvalue ) {
877 $optparamlabel = strtoupper( $optparamlabel );
878 switch( $optparamlabel ) {
879 case 'MEMBER':
880 if( is_array( $optparamvalue )) {
881 foreach( $optparamvalue as $part ) {
882 $part = str_replace( 'MAILTO:', '', $part );
883 $part = str_replace( 'mailto:', '', $part );
884 if(( '"' == $part[0] ) && ( '"' == $part[strlen($part)-1] ))
885 $part = substr( $part, 1, ( strlen($part)-2 ));
886 $optarrays[$optparamlabel][] = $part;
887 }
888 }
889 else {
890 $part = str_replace( 'MAILTO:', '', $optparamvalue );
891 $part = str_replace( 'mailto:', '', $part );
892 if(( '"' == $part[0] ) && ( '"' == $part[strlen($part)-1] ))
893 $part = substr( $part, 1, ( strlen($part)-2 ));
894 $optarrays[$optparamlabel][] = $part;
895 }
896 break;
897 default:
898 if( 'SENT-BY' == $optparamlabel ) {
899 $optparamvalue = str_replace( 'MAILTO:', '', $optparamvalue );
900 $optparamvalue = str_replace( 'mailto:', '', $optparamvalue );
901 }
902 if(( '"' == substr( $optparamvalue, 0, 1 )) &&
903 ( '"' == substr( $optparamvalue, -1 )))
904 $optparamvalue = substr( $optparamvalue, 1, ( strlen( $optparamvalue ) - 2 ));
905 $params2[$optparamlabel] = $optparamvalue;
906 break;
907 } // end switch( $optparamlabel.. .
908 } // end foreach( $optparam.. .
909 foreach( $optarrays as $optparamlabel => $optparams )
910 $params2[$optparamlabel] = $optparams;
911 }
912 // remove defaults
913 $this->_existRem( $params2, 'CUTYPE', 'INDIVIDUAL' );
914 $this->_existRem( $params2, 'PARTSTAT', 'NEEDS-ACTION' );
915 $this->_existRem( $params2, 'ROLE', 'REQ-PARTICIPANT' );
916 $this->_existRem( $params2, 'RSVP', 'FALSE' );
917 // check language setting
918 if( isset( $params2['CN' ] )) {
919 $lang = $this->getConfig( 'language' );
920 if( !isset( $params2['LANGUAGE' ] ) && !empty( $lang ))
921 $params2['LANGUAGE' ] = $lang;
922 }
923 $this->_setMval( $this->attendee, $value, $params2, FALSE, $index );
924 return TRUE;
925 }
926 /*********************************************************************************/
927 /**
928 * Property Name: COMMENT
929 */
930 /**
931 * creates formatted output for calendar component property comment
932 *
933 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
934 * @since 2.4.8 - 2008-10-22
935 * @return string
936 */
937 function createComment() {
938 if( empty( $this->comment )) return FALSE;
939 $output = null;
940 foreach( $this->comment as $commentPart ) {
941 if( empty( $commentPart['value'] )) {
942 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'COMMENT' );
943 continue;
944 }
945 $attributes = $this->_createParams( $commentPart['params'], array( 'ALTREP', 'LANGUAGE' ));
946 $content = $this->_strrep( $commentPart['value'] );
947 $output .= $this->_createElement( 'COMMENT', $attributes, $content );
948 }
949 return $output;
950 }
951 /**
952 * set calendar component property comment
953 *
954 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
955 * @since 2.5.1 - 2008-11-06
956 * @param string $value
957 * @param array $params, optional
958 * @param integer $index, optional
959 * @return bool
960 */
961 function setComment( $value, $params=FALSE, $index=FALSE ) {
962 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
963 $this->_setMval( $this->comment, $value, $params, FALSE, $index );
964 return TRUE;
965 }
966 /*********************************************************************************/
967 /**
968 * Property Name: COMPLETED
969 */
970 /**
971 * creates formatted output for calendar component property completed
972 *
973 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
974 * @since 2.4.8 - 2008-10-22
975 * @return string
976 */
977 function createCompleted( ) {
978 if( empty( $this->completed )) return FALSE;
979 if( !isset( $this->completed['value']['year'] ) &&
980 !isset( $this->completed['value']['month'] ) &&
981 !isset( $this->completed['value']['day'] ) &&
982 !isset( $this->completed['value']['hour'] ) &&
983 !isset( $this->completed['value']['min'] ) &&
984 !isset( $this->completed['value']['sec'] ))
985 if( $this->getConfig( 'allowEmpty' ))
986 return $this->_createElement( 'COMPLETED' );
987 else return FALSE;
988 $formatted = $this->_format_date_time( $this->completed['value'], 7 );
989 $attributes = $this->_createParams( $this->completed['params'] );
990 return $this->_createElement( 'COMPLETED', $attributes, $formatted );
991 }
992 /**
993 * set calendar component property completed
994 *
995 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
996 * @since 2.4.8 - 2008-10-23
997 * @param mixed $year
998 * @param mixed $month optional
999 * @param int $day optional
1000 * @param int $hour optional
1001 * @param int $min optional
1002 * @param int $sec optional
1003 * @param array $params optional
1004 * @return bool
1005 */
1006 function setCompleted( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1007 if( empty( $year )) {
1008 if( $this->getConfig( 'allowEmpty' )) {
1009 $this->completed = array( 'value' => null, 'params' => $this->_setParams( $params ));
1010 return TRUE;
1011 }
1012 else
1013 return FALSE;
1014 }
1015 $this->completed = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
1016 return TRUE;
1017 }
1018 /*********************************************************************************/
1019 /**
1020 * Property Name: CONTACT
1021 */
1022 /**
1023 * creates formatted output for calendar component property contact
1024 *
1025 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1026 * @since 2.4.8 - 2008-10-23
1027 * @return string
1028 */
1029 function createContact() {
1030 if( empty( $this->contact )) return FALSE;
1031 $output = null;
1032 foreach( $this->contact as $contact ) {
1033 if( !empty( $contact['value'] )) {
1034 $attributes = $this->_createParams( $contact['params'], array( 'ALTREP', 'LANGUAGE' ));
1035 $content = $this->_strrep( $contact['value'] );
1036 $output .= $this->_createElement( 'CONTACT', $attributes, $content );
1037 }
1038 elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'CONTACT' );
1039 }
1040 return $output;
1041 }
1042 /**
1043 * set calendar component property contact
1044 *
1045 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1046 * @since 2.5.1 - 2008-11-05
1047 * @param string $value
1048 * @param array $params, optional
1049 * @param integer $index, optional
1050 * @return bool
1051 */
1052 function setContact( $value, $params=FALSE, $index=FALSE ) {
1053 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1054 $this->_setMval( $this->contact, $value, $params, FALSE, $index );
1055 return TRUE;
1056 }
1057 /*********************************************************************************/
1058 /**
1059 * Property Name: CREATED
1060 */
1061 /**
1062 * creates formatted output for calendar component property created
1063 *
1064 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1065 * @since 2.4.8 - 2008-10-21
1066 * @return string
1067 */
1068 function createCreated() {
1069 if( empty( $this->created )) return FALSE;
1070 $formatted = $this->_format_date_time( $this->created['value'], 7 );
1071 $attributes = $this->_createParams( $this->created['params'] );
1072 return $this->_createElement( 'CREATED', $attributes, $formatted );
1073 }
1074 /**
1075 * set calendar component property created
1076 *
1077 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1078 * @since 2.4.8 - 2008-10-23
1079 * @param mixed $year optional
1080 * @param mixed $month optional
1081 * @param int $day optional
1082 * @param int $hour optional
1083 * @param int $min optional
1084 * @param int $sec optional
1085 * @param mixed $params optional
1086 * @return bool
1087 */
1088 function setCreated( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1089 if( !isset( $year )) {
1090 $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
1091 }
1092 $this->created = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
1093 return TRUE;
1094 }
1095 /*********************************************************************************/
1096 /**
1097 * Property Name: DESCRIPTION
1098 */
1099 /**
1100 * creates formatted output for calendar component property description
1101 *
1102 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1103 * @since 2.4.8 - 2008-10-22
1104 * @return string
1105 */
1106 function createDescription() {
1107 if( empty( $this->description )) return FALSE;
1108 $output = null;
1109 foreach( $this->description as $description ) {
1110 if( !empty( $description['value'] )) {
1111 $attributes = $this->_createParams( $description['params'], array( 'ALTREP', 'LANGUAGE' ));
1112 $content = $this->_strrep( $description['value'] );
1113 $output .= $this->_createElement( 'DESCRIPTION', $attributes, $content );
1114 }
1115 elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'DESCRIPTION' );
1116 }
1117 return $output;
1118 }
1119 /**
1120 * set calendar component property description
1121 *
1122 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1123 * @since 2.5.1 - 2008-11-05
1124 * @param string $value
1125 * @param array $params, optional
1126 * @param integer $index, optional
1127 * @return bool
1128 */
1129 function setDescription( $value, $params=FALSE, $index=FALSE ) {
1130 if( empty( $value )) { if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; }
1131 $this->_setMval( $this->description, $value, $params, FALSE, $index );
1132 return TRUE;
1133 }
1134 /*********************************************************************************/
1135 /**
1136 * Property Name: DTEND
1137 */
1138 /**
1139 * creates formatted output for calendar component property dtend
1140 *
1141 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1142 * @since 2.4.8 - 2008-10-21
1143 * @return string
1144 */
1145 function createDtend() {
1146 if( empty( $this->dtend )) return FALSE;
1147 if( !isset( $this->dtend['value']['year'] ) &&
1148 !isset( $this->dtend['value']['month'] ) &&
1149 !isset( $this->dtend['value']['day'] ) &&
1150 !isset( $this->dtend['value']['hour'] ) &&
1151 !isset( $this->dtend['value']['min'] ) &&
1152 !isset( $this->dtend['value']['sec'] ))
1153 if( $this->getConfig( 'allowEmpty' ))
1154 return $this->_createElement( 'DTEND' );
1155 else return FALSE;
1156 $formatted = $this->_format_date_time( $this->dtend['value'] );
1157 $attributes = $this->_createParams( $this->dtend['params'] );
1158 return $this->_createElement( 'DTEND', $attributes, $formatted );
1159 }
1160 /**
1161 * set calendar component property dtend
1162 *
1163 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1164 * @since 2.4.8 - 2008-10-23
1165 * @param mixed $year
1166 * @param mixed $month optional
1167 * @param int $day optional
1168 * @param int $hour optional
1169 * @param int $min optional
1170 * @param int $sec optional
1171 * @param string $tz optional
1172 * @param array params optional
1173 * @return bool
1174 */
1175 function setDtend( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
1176 if( empty( $year )) {
1177 if( $this->getConfig( 'allowEmpty' )) {
1178 $this->dtend = array( 'value' => null, 'params' => $this->_setParams( $params ));
1179 return TRUE;
1180 }
1181 else
1182 return FALSE;
1183 }
1184 $this->dtend = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params );
1185 return TRUE;
1186 }
1187 /*********************************************************************************/
1188 /**
1189 * Property Name: DTSTAMP
1190 */
1191 /**
1192 * creates formatted output for calendar component property dtstamp
1193 *
1194 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1195 * @since 2.4.4 - 2008-03-07
1196 * @return string
1197 */
1198 function createDtstamp() {
1199 if( !isset( $this->dtstamp['value']['year'] ) &&
1200 !isset( $this->dtstamp['value']['month'] ) &&
1201 !isset( $this->dtstamp['value']['day'] ) &&
1202 !isset( $this->dtstamp['value']['hour'] ) &&
1203 !isset( $this->dtstamp['value']['min'] ) &&
1204 !isset( $this->dtstamp['value']['sec'] ))
1205 $this->_makeDtstamp();
1206 $formatted = $this->_format_date_time( $this->dtstamp['value'], 7 );
1207 $attributes = $this->_createParams( $this->dtstamp['params'] );
1208 return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
1209 }
1210 /**
1211 * computes datestamp for calendar component object instance dtstamp
1212 *
1213 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1214 * @since 1.x.x - 2007-05-13
1215 * @return void
1216 */
1217 function _makeDtstamp() {
1218 $this->dtstamp['value'] = array( 'year' => date( 'Y' )
1219 , 'month' => date( 'm' )
1220 , 'day' => date( 'd' )
1221 , 'hour' => date( 'H' )
1222 , 'min' => date( 'i' )
1223 , 'sec' => date( 's' ) - date( 'Z' ));
1224 $this->dtstamp['params'] = null;
1225 }
1226 /**
1227 * set calendar component property dtstamp
1228 *
1229 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1230 * @since 2.4.8 - 2008-10-23
1231 * @param mixed $year
1232 * @param mixed $month optional
1233 * @param int $day optional
1234 * @param int $hour optional
1235 * @param int $min optional
1236 * @param int $sec optional
1237 * @param array $params optional
1238 * @return TRUE
1239 */
1240 function setDtstamp( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1241 if( empty( $year ))
1242 $this->_makeDtstamp();
1243 else
1244 $this->dtstamp = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
1245 return TRUE;
1246 }
1247 /*********************************************************************************/
1248 /**
1249 * Property Name: DTSTART
1250 */
1251 /**
1252 * creates formatted output for calendar component property dtstart
1253 *
1254 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1255 * @since 2.4.16 - 2008-10-26
1256 * @return string
1257 */
1258 function createDtstart() {
1259 if( empty( $this->dtstart )) return FALSE;
1260 if( !isset( $this->dtstart['value']['year'] ) &&
1261 !isset( $this->dtstart['value']['month'] ) &&
1262 !isset( $this->dtstart['value']['day'] ) &&
1263 !isset( $this->dtstart['value']['hour'] ) &&
1264 !isset( $this->dtstart['value']['min'] ) &&
1265 !isset( $this->dtstart['value']['sec'] ))
1266 if( $this->getConfig( 'allowEmpty' ))
1267 return $this->_createElement( 'DTSTART' );
1268 else return FALSE;
1269 if( in_array( $this->objName, array( 'hc_vtimezone', 'standard', 'daylight' )))
1270 unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
1271 $formatted = $this->_format_date_time( $this->dtstart['value'] );
1272 $attributes = $this->_createParams( $this->dtstart['params'] );
1273 return $this->_createElement( 'DTSTART', $attributes, $formatted );
1274 }
1275 /**
1276 * set calendar component property dtstart
1277 *
1278 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1279 * @since 2.4.16 - 2008-11-04
1280 * @param mixed $year
1281 * @param mixed $month optional
1282 * @param int $day optional
1283 * @param int $hour optional
1284 * @param int $min optional
1285 * @param int $sec optional
1286 * @param string $tz optional
1287 * @param array $params optional
1288 * @return bool
1289 */
1290 function setDtstart( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
1291 if( empty( $year )) {
1292 if( $this->getConfig( 'allowEmpty' )) {
1293 $this->dtstart = array( 'value' => null, 'params' => $this->_setParams( $params ));
1294 return TRUE;
1295 }
1296 else
1297 return FALSE;
1298 }
1299 $this->dtstart = $this->_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart' );
1300 return TRUE;
1301 }
1302 /*********************************************************************************/
1303 /**
1304 * Property Name: DURATION
1305 */
1306 /**
1307 * creates formatted output for calendar component property duration
1308 *
1309 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1310 * @since 2.4.8 - 2008-10-21
1311 * @return string
1312 */
1313 function createDuration() {
1314 if( empty( $this->duration )) return FALSE;
1315 if( !isset( $this->duration['value']['week'] ) &&
1316 !isset( $this->duration['value']['day'] ) &&
1317 !isset( $this->duration['value']['hour'] ) &&
1318 !isset( $this->duration['value']['min'] ) &&
1319 !isset( $this->duration['value']['sec'] ))
1320 if( $this->getConfig( 'allowEmpty' ))
1321 return $this->_createElement( 'DURATION', array(), null );
1322 else return FALSE;
1323 $attributes = $this->_createParams( $this->duration['params'] );
1324 return $this->_createElement( 'DURATION', $attributes, $this->_format_duration( $this->duration['value'] ));
1325 }
1326 /**
1327 * set calendar component property duration
1328 *
1329 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1330 * @since 2.4.8 - 2008-11-04
1331 * @param mixed $week
1332 * @param mixed $day optional
1333 * @param int $hour optional
1334 * @param int $min optional
1335 * @param int $sec optional
1336 * @param array $params optional
1337 * @return bool
1338 */
1339 function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1340 if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE;
1341 if( is_array( $week ) && ( 1 <= count( $week )))
1342 $this->duration = array( 'value' => $this->_duration_array( $week ), 'params' => $this->_setParams( $day ));
1343 elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
1344 $week = trim( $week );
1345 if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
1346 $week = substr( $week, 1 );
1347 $this->duration = array( 'value' => $this->_duration_string( $week ), 'params' => $this->_setParams( $day ));
1348 }
1349 elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec ))
1350 return FALSE;
1351 else
1352 $this->duration = array( 'value' => $this->_duration_array( array( $week, $day, $hour, $min, $sec )), 'params' => $this->_setParams( $params ));
1353 return TRUE;
1354 }
1355 /*********************************************************************************/
1356 /**
1357 * Property Name: LAST-MODIFIED
1358 */
1359 /**
1360 * creates formatted output for calendar component property last-modified
1361 *
1362 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1363 * @since 2.4.8 - 2008-10-21
1364 * @return string
1365 */
1366 function createLastModified() {
1367 if( empty( $this->lastmodified )) return FALSE;
1368 $attributes = $this->_createParams( $this->lastmodified['params'] );
1369 $formatted = $this->_format_date_time( $this->lastmodified['value'], 7 );
1370 return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
1371 }
1372 /**
1373 * set calendar component property completed
1374 *
1375 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1376 * @since 2.4.8 - 2008-10-23
1377 * @param mixed $year optional
1378 * @param mixed $month optional
1379 * @param int $day optional
1380 * @param int $hour optional
1381 * @param int $min optional
1382 * @param int $sec optional
1383 * @param array $params optional
1384 * @return boll
1385 */
1386 function setLastModified( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1387 if( empty( $year ))
1388 $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
1389 $this->lastmodified = $this->_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
1390 return TRUE;
1391 }
1392 /*********************************************************************************/
1393 /**
1394 * Property Name: LOCATION
1395 */
1396 /**
1397 * creates formatted output for calendar component property location
1398 *
1399 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1400 * @since 2.4.8 - 2008-10-22
1401 * @return string
1402 */
1403 function createLocation() {
1404 if( empty( $this->location )) return FALSE;
1405 if( empty( $this->location['value'] ))
1406 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'LOCATION' ) : FALSE;
1407 $attributes = $this->_createParams( $this->location['params'], array( 'ALTREP', 'LANGUAGE' ));
1408 $content = $this->_strrep( $this->location['value'] );
1409 return $this->_createElement( 'LOCATION', $attributes, $content );
1410 }
1411 /**
1412 * set calendar component property location
1413 '
1414 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1415 * @since 2.4.8 - 2008-11-04
1416 * @param string $value
1417 * @param array params optional
1418 * @return bool
1419 */
1420 function setLocation( $value, $params=FALSE ) {
1421 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1422 $this->location = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1423 return TRUE;
1424 }
1425 /*********************************************************************************/
1426 /**
1427 * Property Name: ORGANIZER
1428 */
1429 /**
1430 * creates formatted output for calendar component property organizer
1431 *
1432 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1433 * @since 2.4.8 - 2008-10-21
1434 * @return string
1435 */
1436 function createOrganizer() {
1437 if( empty( $this->organizer )) return FALSE;
1438 if( empty( $this->organizer['value'] ))
1439 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ORGANIZER' ) : FALSE;
1440 $attributes = $this->_createParams( $this->organizer['params']
1441 , array( 'CN', 'DIR', 'LANGUAGE', 'SENT-BY' ));
1442 $content = 'MAILTO:'.$this->organizer['value'];
1443 return $this->_createElement( 'ORGANIZER', $attributes, $content );
1444 }
1445 /**
1446 * set calendar component property organizer
1447 *
1448 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1449 * @since 2.4.8 - 2008-11-04
1450 * @param string $value
1451 * @param array params optional
1452 * @return bool
1453 */
1454 function setOrganizer( $value, $params=FALSE ) {
1455 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1456 $value = str_replace ( 'MAILTO:', '', $value );
1457 $value = str_replace ( 'mailto:', '', $value );
1458 $this->organizer = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1459 if( isset( $this->organizer['params']['SENT-BY'] )) {
1460 if( 'MAILTO' == strtoupper( substr( $this->organizer['params']['SENT-BY'], 0, 6 )))
1461 $this->organizer['params']['SENT-BY'] = substr( $this->organizer['params']['SENT-BY'], 7 );
1462 }
1463 return TRUE;
1464 }
1465 /*********************************************************************************/
1466 /**
1467 * Property Name: PRIORITY
1468 */
1469 /**
1470 * creates formatted output for calendar component property priority
1471 *
1472 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1473 * @since 2.4.8 - 2008-10-21
1474 * @return string
1475 */
1476 function createPriority() {
1477 if( empty( $this->priority )) return FALSE;
1478 if( empty( $this->priority['value'] ))
1479 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PRIORITY' ) : FALSE;
1480 $attributes = $this->_createParams( $this->priority['params'] );
1481 return $this->_createElement( 'PRIORITY', $attributes, $this->priority['value'] );
1482 }
1483 /**
1484 * set calendar component property priority
1485 *
1486 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1487 * @since 2.4.8 - 2008-11-04
1488 * @param int $value
1489 * @param array $params optional
1490 * @return bool
1491 */
1492 function setPriority( $value, $params=FALSE ) {
1493 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1494 $this->priority = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1495 return TRUE;
1496 }
1497 /*********************************************************************************/
1498 /**
1499 * Property Name: RESOURCES
1500 */
1501 /**
1502 * creates formatted output for calendar component property resources
1503 *
1504 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1505 * @since 2.4.8 - 2008-10-23
1506 * @return string
1507 */
1508 function createResources() {
1509 if( empty( $this->resources )) return FALSE;
1510 $output = null;
1511 foreach( $this->resources as $resource ) {
1512 if( empty( $resource['value'] )) {
1513 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RESOURCES' );
1514 continue;
1515 }
1516 $attributes = $this->_createParams( $resource['params'], array( 'ALTREP', 'LANGUAGE' ));
1517 if( is_array( $resource['value'] )) {
1518 foreach( $resource['value'] as $rix => $resourcePart )
1519 $resource['value'][$rix] = $this->_strrep( $resourcePart );
1520 $content = implode( ',', $resource['value'] );
1521 }
1522 else
1523 $content = $this->_strrep( $resource['value'] );
1524 $output .= $this->_createElement( 'RESOURCES', $attributes, $content );
1525 }
1526 return $output;
1527 }
1528 /**
1529 * set calendar component property recources
1530 *
1531 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1532 * @since 2.5.1 - 2008-11-05
1533 * @param mixed $value
1534 * @param array $params, optional
1535 * @param integer $index, optional
1536 * @return bool
1537 */
1538 function setResources( $value, $params=FALSE, $index=FALSE ) {
1539 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1540 $this->_setMval( $this->resources, $value, $params, FALSE, $index );
1541 return TRUE;
1542 }
1543 /*********************************************************************************/
1544 /**
1545 * Property Name: SEQUENCE
1546 */
1547 /**
1548 * creates formatted output for calendar component property sequence
1549 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1550 * @since 0.9.7 - 2006-11-20
1551 * @return string
1552 */
1553 function createSequence() {
1554 if( empty( $this->sequence )) return FALSE;
1555 if( empty( $this->sequence['value'] ))
1556 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SEQUENCE' ) : FALSE;
1557 $attributes = $this->_createParams( $this->sequence['params'] );
1558 return $this->_createElement( 'SEQUENCE', $attributes, $this->sequence['value'] );
1559 }
1560 /**
1561 * set calendar component property sequence
1562 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1563 * @since 2.4.8 - 2008-11-04
1564 * @param int $value optional
1565 * @param array $params optional
1566 * @return bool
1567 */
1568 function setSequence( $value=FALSE, $params=FALSE ) {
1569 if( empty( $value ))
1570 $value = ( isset( $this->sequence['value'] ) && ( 0 < $this->sequence['value'] )) ? $this->sequence['value'] + 1 : 1;
1571 $this->sequence = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1572 return TRUE;
1573 }
1574 /*********************************************************************************/
1575 /**
1576 * Property Name: STATUS
1577 */
1578 /**
1579 * creates formatted output for calendar component property status
1580 *
1581 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1582 * @since 2.4.8 - 2008-10-21
1583 * @return string
1584 */
1585 function createStatus() {
1586 if( empty( $this->status )) return FALSE;
1587 if( empty( $this->status['value'] ))
1588 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'STATUS' ) : FALSE;
1589 $attributes = $this->_createParams( $this->status['params'] );
1590 return $this->_createElement( 'STATUS', $attributes, $this->status['value'] );
1591 }
1592 /**
1593 * set calendar component property status
1594 *
1595 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1596 * @since 2.4.8 - 2008-11-04
1597 * @param string $value
1598 * @param array $params optional
1599 * @return bool
1600 */
1601 function setStatus( $value, $params=FALSE ) {
1602 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1603 $this->status = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1604 return TRUE;
1605 }
1606 /*********************************************************************************/
1607 /**
1608 * Property Name: SUMMARY
1609 */
1610 /**
1611 * creates formatted output for calendar component property summary
1612 *
1613 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1614 * @since 2.4.8 - 2008-10-21
1615 * @return string
1616 */
1617 function createSummary() {
1618 if( empty( $this->summary )) return FALSE;
1619 if( empty( $this->summary['value'] ))
1620 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SUMMARY' ) : FALSE;
1621 $attributes = $this->_createParams( $this->summary['params'], array( 'ALTREP', 'LANGUAGE' ));
1622 $content = $this->_strrep( $this->summary['value'] );
1623 return $this->_createElement( 'SUMMARY', $attributes, $content );
1624 }
1625 /**
1626 * set calendar component property summary
1627 *
1628 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1629 * @since 2.4.8 - 2008-11-04
1630 * @param string $value
1631 * @param string $params optional
1632 * @return bool
1633 */
1634 function setSummary( $value, $params=FALSE ) {
1635 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1636 $this->summary = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1637 return TRUE;
1638 }
1639 /*********************************************************************************/
1640 /**
1641 * Property Name: TZID
1642 */
1643 /**
1644 * creates formatted output for calendar component property tzid
1645 *
1646 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1647 * @since 2.4.8 - 2008-10-21
1648 * @return string
1649 */
1650 function createTzid() {
1651 if( empty( $this->tzid )) return FALSE;
1652 if( empty( $this->tzid['value'] ))
1653 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZID' ) : FALSE;
1654 $attributes = $this->_createParams( $this->tzid['params'] );
1655 return $this->_createElement( 'TZID', $attributes, $this->_strrep( $this->tzid['value'] ));
1656 }
1657 /**
1658 * set calendar component property tzid
1659 *
1660 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1661 * @since 2.4.8 - 2008-11-04
1662 * @param string $value
1663 * @param array $params optional
1664 * @return bool
1665 */
1666 function setTzid( $value, $params=FALSE ) {
1667 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1668 $this->tzid = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1669 return TRUE;
1670 }
1671 /*********************************************************************************/
1672 /**
1673 * .. .
1674 * Property Name: TZNAME
1675 */
1676 /**
1677 * creates formatted output for calendar component property tzname
1678 *
1679 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1680 * @since 2.4.8 - 2008-10-21
1681 * @return string
1682 */
1683 function createTzname() {
1684 if( empty( $this->tzname )) return FALSE;
1685 $output = null;
1686 foreach( $this->tzname as $theName ) {
1687 if( !empty( $theName['value'] )) {
1688 $attributes = $this->_createParams( $theName['params'], array( 'LANGUAGE' ));
1689 $output .= $this->_createElement( 'TZNAME', $attributes, $this->_strrep( $theName['value'] ));
1690 }
1691 elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'TZNAME' );
1692 }
1693 return $output;
1694 }
1695 /**
1696 * set calendar component property tzname
1697 *
1698 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1699 * @since 2.5.1 - 2008-11-05
1700 * @param string $value
1701 * @param string $params, optional
1702 * @param integer $index, optional
1703 * @return bool
1704 */
1705 function setTzname( $value, $params=FALSE, $index=FALSE ) {
1706 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1707 $this->_setMval( $this->tzname, $value, $params, FALSE, $index );
1708 return TRUE;
1709 }
1710 /*********************************************************************************/
1711 /**
1712 * Property Name: TZOFFSETFROM
1713 */
1714 /**
1715 * creates formatted output for calendar component property tzoffsetfrom
1716 *
1717 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1718 * @since 2.4.8 - 2008-10-21
1719 * @return string
1720 */
1721 function createTzoffsetfrom() {
1722 if( empty( $this->tzoffsetfrom )) return FALSE;
1723 if( empty( $this->tzoffsetfrom['value'] ))
1724 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETFROM' ) : FALSE;
1725 $attributes = $this->_createParams( $this->tzoffsetfrom['params'] );
1726 return $this->_createElement( 'TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value'] );
1727 }
1728 /**
1729 * set calendar component property tzoffsetfrom
1730 *
1731 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1732 * @since 2.4.8 - 2008-11-04
1733 * @param string $value
1734 * @param string $params optional
1735 * @return bool
1736 */
1737 function setTzoffsetfrom( $value, $params=FALSE ) {
1738 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1739 $this->tzoffsetfrom = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1740 return TRUE;
1741 }
1742 /*********************************************************************************/
1743 /**
1744 * Property Name: TZOFFSETTO
1745 */
1746 /**
1747 * creates formatted output for calendar component property tzoffsetto
1748 *
1749 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1750 * @since 2.4.8 - 2008-10-21
1751 * @return string
1752 */
1753 function createTzoffsetto() {
1754 if( empty( $this->tzoffsetto )) return FALSE;
1755 if( empty( $this->tzoffsetto['value'] ))
1756 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETTO' ) : FALSE;
1757 $attributes = $this->_createParams( $this->tzoffsetto['params'] );
1758 return $this->_createElement( 'TZOFFSETTO', $attributes, $this->tzoffsetto['value'] );
1759 }
1760 /**
1761 * set calendar component property tzoffsetto
1762 *
1763 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1764 * @since 2.4.8 - 2008-11-04
1765 * @param string $value
1766 * @param string $params optional
1767 * @return bool
1768 */
1769 function setTzoffsetto( $value, $params=FALSE ) {
1770 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1771 $this->tzoffsetto = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1772 return TRUE;
1773 }
1774 /*********************************************************************************/
1775 /**
1776 * Property Name: TZURL
1777 */
1778 /**
1779 * creates formatted output for calendar component property tzurl
1780 *
1781 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1782 * @since 2.4.8 - 2008-10-21
1783 * @return string
1784 */
1785 function createTzurl() {
1786 if( empty( $this->tzurl )) return FALSE;
1787 if( empty( $this->tzurl['value'] ))
1788 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZURL' ) : FALSE;
1789 $attributes = $this->_createParams( $this->tzurl['params'] );
1790 return $this->_createElement( 'TZURL', $attributes, $this->tzurl['value'] );
1791 }
1792 /**
1793 * set calendar component property tzurl
1794 *
1795 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1796 * @since 2.4.8 - 2008-11-04
1797 * @param string $value
1798 * @param string $params optional
1799 * @return boll
1800 */
1801 function setTzurl( $value, $params=FALSE ) {
1802 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1803 $this->tzurl = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1804 return TRUE;
1805 }
1806 /*********************************************************************************/
1807 /**
1808 * Property Name: UID
1809 */
1810 /**
1811 * creates formatted output for calendar component property uid
1812 *
1813 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1814 * @since 0.9.7 - 2006-11-20
1815 * @return string
1816 */
1817 function createUid() {
1818 if( 0 >= count( $this->uid ))
1819 $this->_makeuid();
1820 $attributes = $this->_createParams( $this->uid['params'] );
1821 return $this->_createElement( 'UID', $attributes, $this->uid['value'] );
1822 }
1823 /**
1824 * create an unique id for this calendar component object instance
1825 *
1826 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1827 * @since 2.2.7 - 2007-09-04
1828 * @return void
1829 */
1830 function _makeUid() {
1831 $date = date('Ymd\THisT');
1832 $unique = substr(microtime(), 2, 4);
1833 $base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890';
1834 $start = 0;
1835 $end = strlen( $base ) - 1;
1836 $length = 6;
1837 $str = null;
1838 for( $p = 0; $p < $length; $p++ )
1839 $unique .= $base[mt_rand( $start, $end )];
1840 $this->uid = array( 'params' => null );
1841 $this->uid['value'] = $date.'-'.$unique.'@'.$this->getConfig( 'unique_id' );
1842 }
1843 /**
1844 * set calendar component property uid
1845 *
1846 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1847 * @since 2.4.8 - 2008-11-04
1848 * @param string $value
1849 * @param string $params optional
1850 * @return bool
1851 */
1852 function setUid( $value, $params=FALSE ) {
1853 if( empty( $value )) return FALSE; // no allowEmpty check here !!!!
1854 $this->uid = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1855 return TRUE;
1856 }
1857 /*********************************************************************************/
1858 /**
1859 * Property Name: URL
1860 */
1861 /**
1862 * creates formatted output for calendar component property url
1863 *
1864 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1865 * @since 2.4.8 - 2008-10-21
1866 * @return string
1867 */
1868 function createUrl() {
1869 if( empty( $this->url )) return FALSE;
1870 if( empty( $this->url['value'] ))
1871 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'URL' ) : FALSE;
1872 $attributes = $this->_createParams( $this->url['params'] );
1873 return $this->_createElement( 'URL', $attributes, $this->url['value'] );
1874 }
1875 /**
1876 * set calendar component property url
1877 *
1878 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1879 * @since 2.4.8 - 2008-11-04
1880 * @param string $value
1881 * @param string $params optional
1882 * @return bool
1883 */
1884 function setUrl( $value, $params=FALSE ) {
1885 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1886 $this->url = array( 'value' => $value, 'params' => $this->_setParams( $params ));
1887 return TRUE;
1888 }
1889 /*********************************************************************************/
1890 /**
1891 * Property Name: x-prop
1892 */
1893 /**
1894 * creates formatted output for calendar component property x-prop
1895 *
1896 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1897 * @since 2.4.11 - 2008-10-22
1898 * @return string
1899 */
1900 function createXprop() {
1901 if( empty( $this->xprop )) return FALSE;
1902 $output = null;
1903 foreach( $this->xprop as $label => $xpropPart ) {
1904 if( empty( $xpropPart['value'] )) {
1905 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $label );
1906 continue;
1907 }
1908 $attributes = $this->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
1909 if( is_array( $xpropPart['value'] )) {
1910 foreach( $xpropPart['value'] as $pix => $theXpart )
1911 $xpropPart['value'][$pix] = $this->_strrep( $theXpart );
1912 $xpropPart['value'] = implode( ',', $xpropPart['value'] );
1913 }
1914 else
1915 $xpropPart['value'] = $this->_strrep( $xpropPart['value'] );
1916 $output .= $this->_createElement( $label, $attributes, $xpropPart['value'] );
1917 }
1918 return $output;
1919 }
1920 /**
1921 * set calendar component property x-prop
1922 *
1923 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1924 * @since 2.4.11 - 2008-11-04
1925 * @param string $label
1926 * @param mixed $value
1927 * @param array $params optional
1928 * @return bool
1929 */
1930 function setXprop( $label, $value, $params=FALSE ) {
1931 if( empty( $label )) return;
1932 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1933 $xprop = array( 'value' => $value );
1934 $toolbox = new hc_calendarComponent();
1935 $xprop['params'] = $toolbox->_setParams( $params );
1936 if( !is_array( $this->xprop )) $this->xprop = array();
1937 $this->xprop[strtoupper( $label )] = $xprop;
1938 return TRUE;
1939 }
1940 /*********************************************************************************/
1941 /*********************************************************************************/
1942 /**
1943 * create element format parts
1944 *
1945 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1946 * @since 2.0.6 - 2006-06-20
1947 * @return string
1948 */
1949 function _createFormat() {
1950 $objectname = null;
1951 switch( $this->format ) {
1952 case 'xcal':
1953 $objectname = ( isset( $this->timezonetype )) ?
1954 strtolower( $this->timezonetype ) : strtolower( $this->objName );
1955 $this->componentStart1 = $this->elementStart1 = '<';
1956 $this->componentStart2 = $this->elementStart2 = '>';
1957 $this->componentEnd1 = $this->elementEnd1 = '</';
1958 $this->componentEnd2 = $this->elementEnd2 = '>'.$this->nl;
1959 $this->intAttrDelimiter = '<!-- -->';
1960 $this->attributeDelimiter = $this->nl;
1961 $this->valueInit = null;
1962 break;
1963 default:
1964 $objectname = ( isset( $this->timezonetype )) ?
1965 strtoupper( $this->timezonetype ) : strtoupper( $this->objName );
1966 $this->componentStart1 = 'BEGIN:';
1967 $this->componentStart2 = null;
1968 $this->componentEnd1 = 'END:';
1969 $this->componentEnd2 = $this->nl;
1970 $this->elementStart1 = null;
1971 $this->elementStart2 = null;
1972 $this->elementEnd1 = null;
1973 $this->elementEnd2 = $this->nl;
1974 $this->intAttrDelimiter = '<!-- -->';
1975 $this->attributeDelimiter = ';';
1976 $this->valueInit = ':';
1977 break;
1978 }
1979 return $objectname;
1980 }
1981 /**
1982 * creates formatted output for calendar component property
1983 *
1984 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
1985 * @since 2.4.8 - 2008-10-23
1986 * @param string $label property name
1987 * @param string $attributes property attributes
1988 * @param string $content property content (optional)
1989 * @return string
1990 */
1991 function _createElement( $label, $attributes=null, $content=FALSE ) {
1992 $label = $this->_formatPropertyName( $label );
1993 $output = $this->elementStart1.$label;
1994 $categoriesAttrLang = null;
1995 $attachInlineBinary = FALSE;
1996 $attachfmttype = null;
1997 if( !empty( $attributes )) {
1998 $attributes = trim( $attributes );
1999 if ( 'xcal' == $this->format) {
2000 $attributes2 = explode( $this->intAttrDelimiter, $attributes );
2001 $attributes = null;
2002 foreach( $attributes2 as $attribute ) {
2003 $attrKVarr = explode( '=', $attribute );
2004 if( empty( $attrKVarr[0] ))
2005 continue;
2006 if( !isset( $attrKVarr[1] )) {
2007 $attrValue = $attrKVarr[0];
2008 $attrKey = null;
2009 }
2010 elseif( 2 == count( $attrKVarr)) {
2011 $attrKey = strtolower( $attrKVarr[0] );
2012 $attrValue = $attrKVarr[1];
2013 }
2014 else {
2015 $attrKey = strtolower( $attrKVarr[0] );
2016 unset( $attrKVarr[0] );
2017 $attrValue = implode( '=', $attrKVarr );
2018 }
2019 if(( 'attach' == $label ) && ( in_array( $attrKey, array( 'fmttype', 'encoding', 'value' )))) {
2020 $attachInlineBinary = TRUE;
2021 if( 'fmttype' == $attrKey )
2022 $attachfmttype = $attrKey.'='.$attrValue;
2023 continue;
2024 }
2025 elseif(( 'categories' == $label ) && ( 'language' == $attrKey ))
2026 $categoriesAttrLang = $attrKey.'='.$attrValue;
2027 else {
2028 $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
2029 $attributes .= ( !empty( $attrKey )) ? $attrKey.'=' : null;
2030 if(( '"' == substr( $attrValue, 0, 1 )) && ( '"' == substr( $attrValue, -1 ))) {
2031 $attrValue = substr( $attrValue, 1, ( strlen( $attrValue ) - 2 ));
2032 $attrValue = str_replace( '"', '', $attrValue );
2033 }
2034 $attributes .= '"'.htmlspecialchars( $attrValue ).'"';
2035 }
2036 }
2037 }
2038 else {
2039 $attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes );
2040 }
2041 }
2042 if(((( 'attach' == $label ) && !$attachInlineBinary ) ||
2043 ( in_array( $label, array( 'tzurl', 'url' )))) && ( 'xcal' == $this->format)) {
2044 $pos = strrpos($content, "/");
2045 $docname = ( $pos !== false) ? substr( $content, (1 - strlen( $content ) + $pos )) : $content;
2046 $this->xcaldecl[] = array( 'xmldecl' => 'ENTITY'
2047 , 'uri' => $docname
2048 , 'ref' => 'SYSTEM'
2049 , 'external' => $content
2050 , 'type' => 'NDATA'
2051 , 'type2' => 'BINERY' );
2052 $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
2053 $attributes .= 'uri="'.$docname.'"';
2054 $content = null;
2055 if( 'attach' == $label ) {
2056 $attributes = str_replace( $this->attributeDelimiter, $this->intAttrDelimiter, $attributes );
2057 $content = $this->_createElement( 'extref', $attributes, null );
2058 $attributes = null;
2059 }
2060 }
2061 elseif(( 'attach' == $label ) && $attachInlineBinary && ( 'xcal' == $this->format)) {
2062 $content = $this->nl.$this->_createElement( 'b64bin', $attachfmttype, $content ); // max one attribute
2063 }
2064 $output .= $attributes;
2065 if( !$content ) {
2066 switch( $this->format ) {
2067 case 'xcal':
2068 $output .= ' /';
2069 $output .= $this->elementStart2;
2070 return $output;
2071 break;
2072 default:
2073 $output .= $this->elementStart2.$this->valueInit;
2074 return $this->_size75( $output );
2075 break;
2076 }
2077 }
2078 $output .= $this->elementStart2;
2079 $output .= $this->valueInit.$content;
2080 switch( $this->format ) {
2081 case 'xcal':
2082 return $output.$this->elementEnd1.$label.$this->elementEnd2;
2083 break;
2084 default:
2085 return $this->_size75( $output );
2086 break;
2087 }
2088 }
2089 /**
2090 * creates formatted output for calendar component property parameters
2091 *
2092 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2093 * @since 0.9.22 - 2007-04-10
2094 * @param array $params optional
2095 * @param array $ctrKeys optional
2096 * @return string
2097 */
2098 function _createParams( $params=array(), $ctrKeys=array() ) {
2099 $attrLANG = $attr1 = $attr2 = null;
2100 $CNattrKey = ( in_array( 'CN', $ctrKeys )) ? TRUE : FALSE ;
2101 $LANGattrKey = ( in_array( 'LANGUAGE', $ctrKeys )) ? TRUE : FALSE ;
2102 $CNattrExist = $LANGattrExist = FALSE;
2103 if( is_array( $params )) {
2104 foreach( $params as $paramKey => $paramValue ) {
2105 if( is_int( $paramKey ))
2106 $attr2 .= $this->intAttrDelimiter.$paramValue;
2107 elseif(( 'LANGUAGE' == $paramKey ) && $LANGattrKey ) {
2108 $attrLANG .= $this->intAttrDelimiter."LANGUAGE=$paramValue";
2109 $LANGattrExist = TRUE;
2110 }
2111 elseif(( 'CN' == $paramKey ) && $CNattrKey ) {
2112 $attr1 = $this->intAttrDelimiter.'CN="'.$paramValue.'"';
2113 $CNattrExist = TRUE;
2114 }
2115 elseif(( 'ALTREP' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
2116 $attr2 .= $this->intAttrDelimiter.'ALTREP="'.$paramValue.'"';
2117 elseif(( 'DIR' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
2118 $attr2 .= $this->intAttrDelimiter.'DIR="'.$paramValue.'"';
2119 elseif(( 'SENT-BY' == $paramKey ) && in_array( $paramKey, $ctrKeys ))
2120 $attr2 .= $this->intAttrDelimiter.'SENT-BY="MAILTO:'.$paramValue.'"';
2121 else
2122 $attr2 .= $this->intAttrDelimiter."$paramKey=$paramValue";
2123 }
2124 }
2125 if( !$LANGattrExist ) {
2126 $lang = $this->getConfig( 'language' );
2127 if(( $CNattrExist || $LANGattrKey ) && $lang )
2128 $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$lang;
2129 }
2130 return $attrLANG.$attr1.$attr2;
2131 }
2132 /**
2133 * ensures internal date-time/date format for input date-time/date in array format
2134 *
2135 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2136 * @since 0.3.0 - 2006-08-15
2137 * @param array $datetime
2138 * @param int $parno optional, default FALSE
2139 * @return array
2140 */
2141 function _date_time_array( $datetime, $parno=FALSE ) {
2142 $output = array();
2143 foreach( $datetime as $dateKey => $datePart ) {
2144 switch ( $dateKey ) {
2145 case '0': case 'year': $output['year'] = $datePart; break;
2146 case '1': case 'month': $output['month'] = $datePart; break;
2147 case '2': case 'day': $output['day'] = $datePart; break;
2148 }
2149 if( 3 != $parno ) {
2150 switch ( $dateKey ) {
2151 case '0':
2152 case '1':
2153 case '2': break;
2154 case '3': case 'hour': $output['hour'] = $datePart; break;
2155 case '4': case 'min' : $output['min'] = $datePart; break;
2156 case '5': case 'sec' : $output['sec'] = $datePart; break;
2157 case '6': case 'tz' : $output['tz'] = $datePart; break;
2158 }
2159 }
2160 }
2161 if( 3 != $parno ) {
2162 if( !isset( $output['hour'] ))
2163 $output['hour'] = 0;
2164 if( !isset( $output['min'] ))
2165 $output['min'] = 0;
2166 if( !isset( $output['sec'] ))
2167 $output['sec'] = 0;
2168 }
2169 return $output;
2170 }
2171 /**
2172 * ensures internal date-time/date format for input date-time/date in string fromat
2173 *
2174 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2175 * @since 2.2.10 - 2007-10-19
2176 * @param array $datetime
2177 * @param int $parno optional, default FALSE
2178 * @return array
2179 */
2180 function _date_time_string( $datetime, $parno=FALSE ) {
2181 $datetime = (string) trim( $datetime );
2182 $tz = null;
2183 $len = strlen( $datetime ) - 1;
2184 if( 'Z' == substr( $datetime, -1 )) {
2185 $tz = 'Z';
2186 $datetime = trim( substr( $datetime, 0, $len ));
2187 }
2188 elseif( ( ctype_digit( substr( $datetime, -2, 2 ))) && // time or date
2189 ( '-' == substr( $datetime, -3, 1 )) ||
2190 ( ':' == substr( $datetime, -3, 1 )) ||
2191 ( '.' == substr( $datetime, -3, 1 ))) {
2192 $continue = TRUE;
2193 }
2194 elseif( ( ctype_digit( substr( $datetime, -4, 4 ))) && // 4 pos offset
2195 ( ' +' == substr( $datetime, -6, 2 )) ||
2196 ( ' -' == substr( $datetime, -6, 2 ))) {
2197 $tz = substr( $datetime, -5, 5 );
2198 $datetime = substr( $datetime, 0, ($len - 5));
2199 }
2200 elseif( ( ctype_digit( substr( $datetime, -6, 6 ))) && // 6 pos offset
2201 ( ' +' == substr( $datetime, -8, 2 )) ||
2202 ( ' -' == substr( $datetime, -8, 2 ))) {
2203 $tz = substr( $datetime, -7, 7 );
2204 $datetime = substr( $datetime, 0, ($len - 7));
2205 }
2206 elseif( ( 6 < $len ) && ( ctype_digit( substr( $datetime, -6, 6 )))) {
2207 $continue = TRUE;
2208 }
2209 elseif( 'T' == substr( $datetime, -7, 1 )) {
2210 $continue = TRUE;
2211 }
2212 else {
2213 $cx = $tx = 0; // 19970415T133000 US-Eastern
2214 for( $cx = -1; $cx > ( 9 - $len ); $cx-- ) {
2215 if(( ' ' == substr( $datetime, $cx, 1 )) || ctype_digit( substr( $datetime, $cx, 1 )))
2216 break; // if exists, tz ends here.. . ?
2217 elseif( ctype_alpha( substr( $datetime, $cx, 1 )) ||
2218 ( in_array( substr( $datetime, $cx, 1 ), array( '-', '/' ))))
2219 $tx--; // tz length counter
2220 }
2221 if( 0 > $tx ) {
2222 $tz = substr( $datetime, $tx );
2223 $datetime = trim( substr( $datetime, 0, $len + $tx + 1 ));
2224 }
2225 }
2226 if( 0 < substr_count( $datetime, '-' )) {
2227 $datetime = str_replace( '-', '/', $datetime );
2228 }
2229 elseif( ctype_digit( substr( $datetime, 0, 8 )) &&
2230 ( 'T' == substr( $datetime, 8, 1 )) &&
2231 ctype_digit( substr( $datetime, 9, 6 ))) {
2232 $datetime = substr( $datetime, 4, 2 )
2233 .'/'.substr( $datetime, 6, 2 )
2234 .'/'.substr( $datetime, 0, 4 )
2235 .' '.substr( $datetime, 9, 2 )
2236 .':'.substr( $datetime, 11, 2 )
2237 .':'.substr( $datetime, 13);
2238 }
2239 $datestring = date( 'Y-m-d H:i:s', strtotime( $datetime ));
2240 $tz = trim( $tz );
2241 $output = array();
2242 $output['year'] = substr( $datestring, 0, 4 );
2243 $output['month'] = substr( $datestring, 5, 2 );
2244 $output['day'] = substr( $datestring, 8, 2 );
2245 if(( 6 == $parno ) || ( 7 == $parno )) {
2246 $output['hour'] = substr( $datestring, 11, 2 );
2247 $output['min'] = substr( $datestring, 14, 2 );
2248 $output['sec'] = substr( $datestring, 17, 2 );
2249 if( !empty( $tz ))
2250 $output['tz'] = $tz;
2251 }
2252 elseif( 3 != $parno ) {
2253 if(( '00' < substr( $datestring, 11, 2 )) ||
2254 ( '00' < substr( $datestring, 14, 2 )) ||
2255 ( '00' < substr( $datestring, 17, 2 ))) {
2256 $output['hour'] = substr( $datestring, 11, 2 );
2257 $output['min'] = substr( $datestring, 14, 2 );
2258 $output['sec'] = substr( $datestring, 17, 2 );
2259 }
2260 if( !empty( $tz ))
2261 $output['tz'] = $tz;
2262 }
2263 return $output;
2264 }
2265 /**
2266 * ensures internal duration format for input in array format
2267 *
2268 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2269 * @since 2.1.1 - 2007-06-24
2270 * @param array $duration
2271 * @return array
2272 */
2273 function _duration_array( $duration ) {
2274 $output = array();
2275 if( is_array( $duration ) &&
2276 ( 1 == count( $duration )) &&
2277 isset( $duration['sec'] ) &&
2278 ( 60 < $duration['sec'] )) {
2279 $durseconds = $duration['sec'];
2280 $output['week'] = floor( $durseconds / ( 60 * 60 * 24 * 7 ));
2281 $durseconds = $durseconds % ( 60 * 60 * 24 * 7 );
2282 $output['day'] = floor( $durseconds / ( 60 * 60 * 24 ));
2283 $durseconds = $durseconds % ( 60 * 60 * 24 );
2284 $output['hour'] = floor( $durseconds / ( 60 * 60 ));
2285 $durseconds = $durseconds % ( 60 * 60 );
2286 $output['min'] = floor( $durseconds / ( 60 ));
2287 $output['sec'] = ( $durseconds % ( 60 ));
2288 }
2289 else {
2290 foreach( $duration as $durKey => $durValue ) {
2291 if( empty( $durValue )) continue;
2292 switch ( $durKey ) {
2293 case '0': case 'week': $output['week'] = $durValue; break;
2294 case '1': case 'day': $output['day'] = $durValue; break;
2295 case '2': case 'hour': $output['hour'] = $durValue; break;
2296 case '3': case 'min': $output['min'] = $durValue; break;
2297 case '4': case 'sec': $output['sec'] = $durValue; break;
2298 }
2299 }
2300 }
2301 if( isset( $output['week'] ) && ( 0 < $output['week'] )) {
2302 unset( $output['day'], $output['hour'], $output['min'], $output['sec'] );
2303 return $output;
2304 }
2305 unset( $output['week'] );
2306 if( empty( $output['day'] ))
2307 unset( $output['day'] );
2308 if ( isset( $output['hour'] ) || isset( $output['min'] ) || isset( $output['sec'] )) {
2309 if( !isset( $output['hour'] )) $output['hour'] = 0;
2310 if( !isset( $output['min'] )) $output['min'] = 0;
2311 if( !isset( $output['sec'] )) $output['sec'] = 0;
2312 if(( 0 == $output['hour'] ) && ( 0 == $output['min'] ) && ( 0 == $output['sec'] ))
2313 unset( $output['hour'], $output['min'], $output['sec'] );
2314 }
2315 return $output;
2316 }
2317 /**
2318 * convert duration to date in array format based on input or dtstart value
2319 *
2320 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2321 * @since 2.4.8 - 2008-10-30
2322 * @param array $startdate, optional
2323 * @param array $duration, optional
2324 * @return array, date format
2325 */
2326 function duration2date( $startdate=FALSE, $duration=FALSE ) {
2327 if( $startdate && $duration ) {
2328 $d1 = $startdate;
2329 $dur = $duration;
2330 }
2331 elseif( isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) {
2332 $d1 = $this->dtstart['value'];
2333 $dur = $this->duration['value'];
2334 }
2335 else
2336 return null;
2337 $dateOnly = ( isset( $d1['hour'] ) || isset( $d1['min'] ) || isset( $d1['sec'] )) ? FALSE : TRUE;
2338 $d1['hour'] = ( isset( $d1['hour'] )) ? $d1['hour'] : 0;
2339 $d1['min'] = ( isset( $d1['min'] )) ? $d1['min'] : 0;
2340 $d1['sec'] = ( isset( $d1['sec'] )) ? $d1['sec'] : 0;
2341 $dtend = mktime( $d1['hour'], $d1['min'], $d1['sec'], $d1['month'], $d1['day'], $d1['year'] );
2342 if( isset( $dur['week'] ))
2343 $dtend += ( $dur['week'] * 7 * 24 * 60 * 60 );
2344 if( isset( $dur['day'] ))
2345 $dtend += ( $dur['day'] * 24 * 60 * 60 );
2346 if( isset( $dur['hour'] ))
2347 $dtend += ( $dur['hour'] * 60 *60 );
2348 if( isset( $dur['min'] ))
2349 $dtend += ( $dur['min'] * 60 );
2350 if( isset( $dur['sec'] ))
2351 $dtend += $dur['sec'];
2352 $dtend2 = array();
2353 $dtend2['year'] = date('Y', $dtend );
2354 $dtend2['month'] = date('m', $dtend );
2355 $dtend2['day'] = date('d', $dtend );
2356 $dtend2['hour'] = date('H', $dtend );
2357 $dtend2['min'] = date('i', $dtend );
2358 $dtend2['sec'] = date('s', $dtend );
2359 if( isset( $d1['tz'] ))
2360 $dtend2['tz'] = $d1['tz'];
2361 if( $dateOnly && (( 0 == $dtend2['hour'] ) && ( 0 == $dtend2['min'] ) && ( 0 == $dtend2['sec'] )))
2362 unset( $dtend2['hour'], $dtend2['min'], $dtend2['sec'] );
2363 return $dtend2;
2364 }
2365 /**
2366 * ensures internal duration format for input in string format
2367 *
2368 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2369 * @since 2.0.5 - 2007-03-14
2370 * @param string $duration
2371 * @return array
2372 */
2373 function _duration_string( $duration ) {
2374 $duration = (string) trim( $duration );
2375 while( 'P' != strtoupper( substr( $duration, 0, 1 ))) {
2376 if( 0 < strlen( $duration ))
2377 $duration = substr( $duration, 1 );
2378 else
2379 return false; // no leading P !?!?
2380 }
2381 $duration = substr( $duration, 1 ); // skip P
2382 $duration = str_replace ( 't', 'T', $duration );
2383 $duration = str_replace ( 'T', '', $duration );
2384 $output = array();
2385 $val = null;
2386 for( $ix=0; $ix < strlen( $duration ); $ix++ ) {
2387 switch( strtoupper( $duration[$ix] )) {
2388 case 'W':
2389 $output['week'] = $val;
2390 $val = null;
2391 break;
2392 case 'D':
2393 $output['day'] = $val;
2394 $val = null;
2395 break;
2396 case 'H':
2397 $output['hour'] = $val;
2398 $val = null;
2399 break;
2400 case 'M':
2401 $output['min'] = $val;
2402 $val = null;
2403 break;
2404 case 'S':
2405 $output['sec'] = $val;
2406 $val = null;
2407 break;
2408 default:
2409 if( !ctype_digit( $duration[$ix] ))
2410 return false; // unknown duration controll character !?!?
2411 else
2412 $val .= $duration[$ix];
2413 }
2414 }
2415 return $this->_duration_array( $output );
2416 }
2417 /**
2418 * if not preSet, if exist, remove key with expected value from array and return hit value else return elseValue
2419 *
2420 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2421 * @since 2.4.16 - 2008-11-08
2422 * @param array $array
2423 * @param string $expkey, expected key
2424 * @param string $expval, expected value
2425 * @param int $hitVal optional, return value if found
2426 * @param int $elseVal optional, return value if not found
2427 * @param int $preSet optional, return value if already preset
2428 * @return int
2429 */
2430 function _existRem( &$array, $expkey, $expval=FALSE, $hitVal=null, $elseVal=null, $preSet=null ) {
2431 if( $preSet )
2432 return $preSet;
2433 if( !is_array( $array ) || ( 0 == count( $array )))
2434 return $elseVal;
2435 foreach( $array as $key => $value ) {
2436 if( strtoupper( $expkey ) == strtoupper( $key )) {
2437 if( !$expval || ( strtoupper( $expval ) == strtoupper( $array[$key] ))) {
2438 unset( $array[$key] );
2439 return $hitVal;
2440 }
2441 }
2442 }
2443 return $elseVal;
2444 }
2445 /**
2446 * creates formatted output for calendar component property data value type date/date-time
2447 *
2448 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2449 * @since 2.4.8 - 2008-10-30
2450 * @param array $datetime
2451 * @param int $parno, optional, default 6
2452 * @return string
2453 */
2454 function _format_date_time( $datetime, $parno=6 ) {
2455 if( !isset( $datetime['year'] ) &&
2456 !isset( $datetime['month'] ) &&
2457 !isset( $datetime['day'] ) &&
2458 !isset( $datetime['hour'] ) &&
2459 !isset( $datetime['min'] ) &&
2460 !isset( $datetime['sec'] ))
2461 return ;
2462 $output = null;
2463 // if( !isset( $datetime['day'] )) { $o=''; foreach($datetime as $k=>$v) {if(is_array($v)) $v=implode('-',$v);$o.=" $k=>$v";} echo " day SAKNAS : $o <br />\n"; }
2464 foreach( $datetime as $dkey => $dvalue ) {
2465 if( 'tz' != $dkey )
2466 $datetime[$dkey] = (integer) $dvalue;
2467 }
2468 $output = date('Ymd', mktime( 0, 0, 0, $datetime['month'], $datetime['day'], $datetime['year']));
2469 if( isset( $datetime['hour'] ) ||
2470 isset( $datetime['min'] ) ||
2471 isset( $datetime['sec'] ) ||
2472 isset( $datetime['tz'] )) {
2473 if( isset( $datetime['tz'] ) &&
2474 !isset( $datetime['hour'] ))
2475 $datetime['hour'] = 0;
2476 if( isset( $datetime['hour'] ) &&
2477 !isset( $datetime['min'] ))
2478 $datetime['min'] = 0;
2479 if( isset( $datetime['hour'] ) &&
2480 isset( $datetime['min'] ) &&
2481 !isset( $datetime['sec'] ))
2482 $datetime['sec'] = 0;
2483 $date = mktime( $datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year']);
2484 $output .= date('\THis', $date );
2485 if( isset( $datetime['tz'] ) && ( '' < trim ( $datetime['tz'] ))) {
2486 $datetime['tz'] = trim( $datetime['tz'] );
2487 if( 'Z' == $datetime['tz'] )
2488 $output .= 'Z';
2489 $offset = $this->_tz2offset( $datetime['tz'] );
2490 if( 0 != $offset ) {
2491 $date = mktime( $datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year']);
2492 $output = date( 'Ymd\THis\Z', $date );
2493 }
2494 }
2495 elseif( 7 == $parno )
2496 $output .= 'Z';
2497 }
2498 return $output;
2499 }
2500 /**
2501 * creates formatted output for calendar component property data value type duration
2502 *
2503 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2504 * @since 2.4.16 - 2008-10-10
2505 * @param array $duration ( week, day, hour, min, sec )
2506 * @return string
2507 */
2508 function _format_duration( $duration ) {
2509 if( !isset( $duration['week'] ) &&
2510 !isset( $duration['day'] ) &&
2511 !isset( $duration['hour'] ) &&
2512 !isset( $duration['min'] ) &&
2513 !isset( $duration['sec'] ))
2514 return;
2515 $output = 'P';
2516 if( isset( $duration['week'] ) && ( 0 < $duration['week'] ))
2517 $output .= $duration['week'].'W';
2518 else {
2519 if( isset($duration['day'] ) && ( 0 < $duration['day'] ))
2520 $output .= $duration['day'].'D';
2521 if(( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ||
2522 ( isset( $duration['min']) && ( 0 < $duration['min'] )) ||
2523 ( isset( $duration['sec']) && ( 0 < $duration['sec'] ))) {
2524 $output .= 'T';
2525 $output .= ( isset( $duration['hour']) && ( 0 < $duration['hour'] )) ? $duration['hour'].'H' : '0H';
2526 $output .= ( isset( $duration['min']) && ( 0 < $duration['min'] )) ? $duration['min']. 'M' : '0M';
2527 $output .= ( isset( $duration['sec']) && ( 0 < $duration['sec'] )) ? $duration['sec']. 'S' : '0S';
2528 }
2529 }
2530 return $output;
2531 }
2532 /**
2533 * create property name case - lower/upper
2534 *
2535 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2536 * @since 0.9.7 - 2006-11-20
2537 * @param string $propertyName
2538 * @return string
2539 */
2540 function _formatPropertyName( $propertyName ) {
2541 switch( $this->format ) {
2542 case 'xcal':
2543 return strtolower( $propertyName );
2544 break;
2545 default:
2546 return strtoupper( $propertyName );
2547 break;
2548 }
2549 }
2550 /**
2551 * checks if input array contains a date
2552 *
2553 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2554 * @since 2.4.16 - 2008-10-25
2555 * @param array $input
2556 * @return bool
2557 */
2558 function _isArrayDate( $input ) {
2559 if( ! is_array($input) ){
2560 return FALSE;
2561 }
2562 if( isset( $input['week'] ) || ( ! in_array( count( $input ), array( 3, 6, 7 ))))
2563 return FALSE;
2564 if( 7 == count( $input ))
2565 return TRUE;
2566 if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
2567 return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
2568 if( isset( $input['day'] ) || isset( $input['hour'] ) || isset( $input['min'] ) || isset( $input['sec'] ))
2569 return FALSE;
2570 if( in_array( 0, $input ))
2571 return FALSE;
2572 if(( 1970 > $input[0] ) || ( 12 < $input[1] ) || ( 31 < $input[2] ))
2573 return FALSE;
2574 if(( isset( $input[0] ) && isset( $input[1] ) && isset( $input[2] )) &&
2575 checkdate( (int) $input[1], (int) $input[2], (int) $input[0] ))
2576 return TRUE;
2577 $input = $this->_date_time_string( $input[1].'/'.$input[2].'/'.$input[0], 3 ); // m - d - Y
2578 if( isset( $input['year'] ) && isset( $input['month'] ) && isset( $input['day'] ))
2579 return checkdate( (int) $input['month'], (int) $input['day'], (int) $input['year'] );
2580 return FALSE;
2581 }
2582 /**
2583 * checks if input array contains a timestamp date
2584 *
2585 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2586 * @since 2.4.16 - 2008-10-18
2587 * @param array $input
2588 * @return bool
2589 */
2590 function _isArrayTimestampDate( $input ) {
2591 return ( is_array( $input ) && isset( $input['timestamp'] )) ? TRUE : FALSE ;
2592 }
2593 /**
2594 * controll if input string contains traling UTC offset
2595 *
2596 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2597 * @since 2.4.16 - 2008-10-19
2598 * @param string $input
2599 * @return bool
2600 */
2601 function _isOffset( $input ) {
2602 $input = trim( (string) $input );
2603 if( 'Z' == substr( $input, -1 ))
2604 return TRUE;
2605 elseif(( 5 <= strlen( $input )) &&
2606 ( in_array( substr( $input, -5, 1 ), array( '+', '-' ))) &&
2607 ( '0000' < substr( $input, -4 )) && ( '9999' >= substr( $input, -4 )))
2608 return TRUE;
2609 elseif(( 7 <= strlen( $input )) &&
2610 ( in_array( substr( $input, -7, 1 ), array( '+', '-' ))) &&
2611 ( '000000' < substr( $input, -6 )) && ( '999999' >= substr( $input, -6 )))
2612 return TRUE;
2613 return FALSE;
2614
2615 }
2616 /**
2617 * check if property not exists within component
2618 *
2619 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2620 * @since 2.5.1 - 2008-10-15
2621 * @param string $propName
2622 * @return bool
2623 */
2624 function _notExistProp( $propName ) {
2625 if( empty( $propName )) return FALSE; // when deleting x-prop, an empty propName may be used=allowed
2626 $propName = strtolower( $propName );
2627 if( 'last-modified' == $propName ) { if( !isset( $this->lastmodified )) return TRUE; }
2628 elseif(( 'x-' != substr($propName,0,2)) && !isset( $this->$propName )) return TRUE;
2629 return FALSE;
2630 }
2631
2632 /**
2633 * convert format for input date to internal date with parameters
2634 *
2635 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2636 * @since 2.4.17 - 2008-10-31
2637 * @param mixed $year
2638 * @param mixed $month optional
2639 * @param int $day optional
2640 * @param int $hour optional
2641 * @param int $min optional
2642 * @param int $sec optional
2643 * @param array $params optional
2644 * @param string $caller optional
2645 * @return array
2646 */
2647 function _setDate( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE, $caller=null ) {
2648 $input = $parno = null;
2649 $localtime = (( 'dtstart' == $caller ) && in_array( $this->objName, array( 'hc_vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
2650 if( $this->_isArrayDate( $year )) {
2651 if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
2652 $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
2653 if( isset( $input['params']['TZID'] )) {
2654 $input['params']['VALUE'] = 'DATE-TIME';
2655 unset( $year['tz'] );
2656 }
2657 $hitval = (( !empty( $year['tz'] ) || !empty( $year[6] ))) ? 7 : 6;
2658 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval );
2659 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3, count( $year ), $parno );
2660 $input['value'] = $this->_date_time_array( $year, $parno );
2661 }
2662 elseif( $this->_isArrayTimestampDate( $year )) {
2663 if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
2664 $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
2665 if( isset( $input['params']['TZID'] )) {
2666 $input['params']['VALUE'] = 'DATE-TIME';
2667 unset( $year['tz'] );
2668 }
2669 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3 );
2670 $hitval = ( isset( $year['tz'] )) ? 7 : 6;
2671 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno );
2672 $input['value'] = $this->_timestamp2date( $year, $parno );
2673 }
2674 elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
2675 if( $localtime ) unset ( $month['VALUE'], $month['TZID'] );
2676 $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ));
2677 if( isset( $input['params']['TZID'] )) {
2678 $input['params']['VALUE'] = 'DATE-TIME';
2679 $parno = 6;
2680 }
2681 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7, $parno );
2682 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3, $parno, $parno );
2683 $input['value'] = $this->_date_time_string( $year, $parno );
2684 }
2685 else {
2686 if( is_array( $params )) {
2687 if( $localtime ) unset ( $params['VALUE'], $params['TZID'] );
2688 $input['params'] = $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
2689 }
2690 elseif( is_array( $tz )) {
2691 $input['params'] = $this->_setParams( $tz, array( 'VALUE' => 'DATE-TIME' ));
2692 $tz = FALSE;
2693 }
2694 elseif( is_array( $hour )) {
2695 $input['params'] = $this->_setParams( $hour, array( 'VALUE' => 'DATE-TIME' ));
2696 $hour = $min = $sec = $tz = FALSE;
2697 }
2698 if( isset( $input['params']['TZID'] )) {
2699 $tz = null;
2700 $input['params']['VALUE'] = 'DATE-TIME';
2701 }
2702 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE', 3 );
2703 $hitval = ( !empty( $tz )) ? 7 : 6;
2704 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno );
2705 $input['value'] = array( 'year' => $year, 'month' => $month, 'day' => $day );
2706 if( 3 != $parno ) {
2707 $input['value']['hour'] = ( $hour ) ? $hour : '0';
2708 $input['value']['min'] = ( $min ) ? $min : '0';
2709 $input['value']['sec'] = ( $sec ) ? $sec : '0';
2710 if( !empty( $tz ))
2711 $input['value']['tz'] = $tz;
2712 }
2713 }
2714 if( 3 == $parno ) {
2715 $input['params']['VALUE'] = 'DATE';
2716 unset( $input['value']['tz'] );
2717 unset( $input['params']['TZID'] );
2718 }
2719 elseif( isset( $input['params']['TZID'] ))
2720 unset( $input['value']['tz'] );
2721 if( $localtime ) unset( $input['value']['tz'], $input['params']['TZID'] );
2722 if( isset( $input['value']['tz'] ))
2723 $input['value']['tz'] = (string) $input['value']['tz'];
2724 if( !empty( $input['value']['tz'] ) && ( 'Z' != $input['value']['tz'] ) &&
2725 ( !$this->_isOffset( $input['value']['tz'] )))
2726 $input['params']['TZID'] = $input['value']['tz'];
2727 return $input;
2728 }
2729 /**
2730 * convert format for input date (UTC) to internal date with parameters
2731 *
2732 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2733 * @since 2.4.17 - 2008-10-31
2734 * @param mixed $year
2735 * @param mixed $month optional
2736 * @param int $day optional
2737 * @param int $hour optional
2738 * @param int $min optional
2739 * @param int $sec optional
2740 * @param array $params optional
2741 * @return array
2742 */
2743 function _setDate2( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
2744 $input = null;
2745 if( $this->_isArrayDate( $year )) {
2746 $input['value'] = $this->_date_time_array( $year, 7 );
2747 $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
2748 }
2749 elseif( $this->_isArrayTimestampDate( $year )) {
2750 $input['value'] = $this->_timestamp2date( $year, 7 );
2751 $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
2752 }
2753 elseif( 8 <= strlen( trim( $year ))) { // ex. 2006-08-03 10:12:18
2754 $input['value'] = $this->_date_time_string( $year, 7 );
2755 $input['params'] = $this->_setParams( $month, array( 'VALUE' => 'DATE-TIME' ) );
2756 }
2757 else {
2758 $input['value'] = array( 'year' => $year
2759 , 'month' => $month
2760 , 'day' => $day
2761 , 'hour' => $hour
2762 , 'min' => $min
2763 , 'sec' => $sec );
2764 $input['params'] = $this->_setParams( $params, array( 'VALUE' => 'DATE-TIME' ));
2765 }
2766 $parno = $this->_existRem( $input['params'], 'VALUE', 'DATE-TIME', 7 ); // remove default
2767 if( !isset( $input['value']['hour'] ))
2768 $input['value']['hour'] = 0;
2769 if( !isset( $input['value']['min'] ))
2770 $input['value']['min'] = 0;
2771 if( !isset( $input['value']['sec'] ))
2772 $input['value']['sec'] = 0;
2773 if( !isset( $input['value']['tz'] ) || !$this->_isOffset( $input['value']['tz'] ))
2774 $input['value']['tz'] = 'Z';
2775 return $input;
2776 }
2777 /**
2778 * check index and set (an indexed) content in multiple value array
2779 *
2780 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2781 * @since 2.5.1 - 2008-11-06
2782 * @param array $valArr
2783 * @param mixed $value
2784 * @param array $params
2785 * @param array $defaults
2786 * @param int $index
2787 * @return void
2788 */
2789 function _setMval( & $valArr, $value, $params=FALSE, $defaults=FALSE, $index=FALSE ) {
2790 if( !is_array( $valArr )) $valArr = array();
2791 if( $index )
2792 $index = $index - 1;
2793 elseif( 0 < count( $valArr )) {
2794 $index = end( array_keys( $valArr ));
2795 $index += 1;
2796 }
2797 else
2798 $index = 0;
2799 $valArr[$index] = array( 'value' => $value, 'params' => $this->_setParams( $params, $defaults ));
2800 ksort( $valArr );
2801 }
2802 /**
2803 * set input (formatted) parameters- component property attributes
2804 *
2805 * default parameters can be set, if missing
2806 *
2807 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2808 * @since 1.x.x - 2007-05-01
2809 * @param array $params
2810 * @param array $defaults
2811 * @return array
2812 */
2813 function _setParams( $params, $defaults=FALSE ) {
2814 if( !is_array( $params))
2815 $params = array();
2816 $input = array();
2817 foreach( $params as $paramKey => $paramValue ) {
2818 if( is_array( $paramValue )) {
2819 foreach( $paramValue as $pkey => $pValue ) {
2820 if(( '"' == substr( $pValue, 0, 1 )) && ( '"' == substr( $pValue, -1 )))
2821 $paramValue[$pkey] = substr( $pValue, 1, ( strlen( $pValue ) - 2 ));
2822 }
2823 }
2824 elseif(( '"' == substr( $paramValue, 0, 1 )) && ( '"' == substr( $paramValue, -1 )))
2825 $paramValue = substr( $paramValue, 1, ( strlen( $paramValue ) - 2 ));
2826 if( 'VALUE' == strtoupper( $paramKey ))
2827 $input['VALUE'] = strtoupper( $paramValue );
2828 else
2829 $input[strtoupper( $paramKey )] = $paramValue;
2830 }
2831 if( is_array( $defaults )) {
2832 foreach( $defaults as $paramKey => $paramValue ) {
2833 if( !isset( $input[$paramKey] ))
2834 $input[$paramKey] = $paramValue;
2835 }
2836 }
2837 return (0 < count( $input )) ? $input : null;
2838 }
2839 /**
2840 * convert timestamp to date array
2841 *
2842 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2843 * @since 2.4.16 - 2008-11-01
2844 * @param mixed $timestamp
2845 * @param int $parno
2846 * @return array
2847 */
2848 function _timestamp2date( $timestamp, $parno=6 ) {
2849 if( is_array( $timestamp )) {
2850 if(( 7 == $parno ) && !empty( $timestamp['tz'] ))
2851 $tz = $timestamp['tz'];
2852 $timestamp = $timestamp['timestamp'];
2853 }
2854 $output = array( 'year' => date( 'Y', $timestamp )
2855 , 'month' => date( 'm', $timestamp )
2856 , 'day' => date( 'd', $timestamp ));
2857 if( 3 != $parno ) {
2858 $output['hour'] = date( 'H', $timestamp );
2859 $output['min'] = date( 'i', $timestamp );
2860 $output['sec'] = date( 's', $timestamp );
2861 if( isset( $tz ))
2862 $output['tz'] = $tz;
2863 }
2864 return $output;
2865 }
2866 /**
2867 * convert (numeric) local time offset to seconds correcting localtime to GMT
2868 *
2869 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2870 * @since 2.4.16 - 2008-10-19
2871 * @param string $offset
2872 * @return integer
2873 */
2874 function _tz2offset( $tz ) {
2875 $tz = trim( (string) $tz );
2876 $offset = 0;
2877 if((( 5 != strlen( $tz )) && ( 7 != strlen( $tz ))) ||
2878 (( '+' != substr( $tz, 0, 1 )) && ( '-' != substr( $tz, 0, 1 ))) ||
2879 (( '0000' >= substr( $tz, 1, 4 )) && ( '9999' < substr( $tz, 1, 4 ))) ||
2880 (( 7 == strlen( $tz )) && ( '00' > substr( $tz, 5, 2 )) && ( '99' < substr( $tz, 5, 2 ))))
2881 return $offset;
2882 $hours2sec = (int) substr( $tz, 1, 2 ) * 3600;
2883 $min2sec = (int) substr( $tz, 3, 2 ) * 60;
2884 $sec = ( 7 == strlen( $tz )) ? (int) substr( $tz, -2 ) : '00';
2885 $offset = $hours2sec + $min2sec + $sec;
2886 $offset = ('-' == substr( $tz, 0, 1 )) ? $offset : -1 * $offset;
2887 return $offset;
2888 }
2889 /*********************************************************************************/
2890 /*********************************************************************************/
2891 /**
2892 * get general component config variables or info about subcomponents
2893 *
2894 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2895 * @since 2.5.1 - 2008-11-02
2896 * @param string $config
2897 * @return value
2898 */
2899 function getConfig( $config ) {
2900 switch( strtoupper( $config )) {
2901 case 'ALLOWEMPTY':
2902 return $this->allowEmpty;
2903 break;
2904 case 'COMPSINFO':
2905 unset( $this->compix );
2906 $info = array();
2907 if( isset( $this->components )) {
2908 foreach( $this->components as $cix => $component ) {
2909 if( empty( $component )) continue;
2910 unset( $component->propix );
2911 $info[$cix]['ordno'] = $cix + 1;
2912 $info[$cix]['type'] = $component->objName;
2913 $info[$cix]['uid'] = $component->getProperty( 'uid' );
2914 $info[$cix]['props'] = $component->getConfig( 'propinfo' );
2915 $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
2916 unset( $component->propix );
2917 }
2918 }
2919 return $info;
2920 break;
2921 case 'FORMAT':
2922 return $this->format;
2923 break;
2924 case 'LANGUAGE':
2925 // get language for calendar component as defined in [RFC 1766]
2926 return $this->language;
2927 break;
2928 case 'NL':
2929 case 'NEWLINECHAR':
2930 return $this->nl;
2931 break;
2932 case 'PROPINFO':
2933 $output = array();
2934 if( !in_array( $this->objName, array( 'hc_valarm', 'hc_vtimezone', 'standard', 'daylight' ))) {
2935 if( empty( $this->uid['value'] )) $this->_makeuid();
2936 $output['UID'] = 1;
2937 }
2938 if( !empty( $this->dtstamp )) $output['DTSTAMP'] = 1;
2939 if( !empty( $this->summary )) $output['SUMMARY'] = 1;
2940 if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description );
2941 if( !empty( $this->dtstart )) $output['DTSTART'] = 1;
2942 if( !empty( $this->dtend )) $output['DTEND'] = 1;
2943 if( !empty( $this->duration )) $output['DURATION'] = 1;
2944 if( !empty( $this->attendee )) $output['ATTENDEE'] = count( $this->attendee );
2945 if( !empty( $this->class )) $output['CLASS'] = 1;
2946 if( !empty( $this->comment )) $output['COMMENT'] = count( $this->comment );
2947 if( !empty( $this->completed )) $output['COMPLETED'] = 1;
2948 if( !empty( $this->contact )) $output['CONTACT'] = count( $this->contact );
2949 if( !empty( $this->created )) $output['CREATED'] = 1;
2950 if( !empty( $this->lastmodified )) $output['LAST-MODIFIED'] = 1;
2951 if( !empty( $this->location )) $output['LOCATION'] = 1;
2952 if( !empty( $this->organizer )) $output['ORGANIZER'] = 1;
2953 if( !empty( $this->priority )) $output['PRIORITY'] = 1;
2954 if( !empty( $this->resources )) $output['RESOURCES'] = count( $this->resources );
2955 if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
2956 if( !empty( $this->status )) $output['STATUS'] = 1;
2957 if( !empty( $this->tzid )) $output['TZID'] = 1;
2958 if( !empty( $this->tzname )) $output['TZNAME'] = count( $this->tzname );
2959 if( !empty( $this->tzoffsetfrom )) $output['TZOFFSETTFROM'] = 1;
2960 if( !empty( $this->tzoffsetto )) $output['TZOFFSETTO'] = 1;
2961 if( !empty( $this->tzurl )) $output['TZURL'] = 1;
2962 if( !empty( $this->url )) $output['URL'] = 1;
2963 if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop );
2964 return $output;
2965 break;
2966 case 'UNIQUE_ID':
2967 if( empty( $this->unique_id ))
2968 $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
2969 return $this->unique_id;
2970 break;
2971 }
2972 }
2973 /**
2974 * general component config setting
2975 *
2976 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
2977 * @since 2.4.8 - 2008-10-24
2978 * @param string $config
2979 * @param string $value
2980 * @return void
2981 */
2982 function setConfig( $config, $value ) {
2983 $res = FALSE;
2984 if( null === $value ) $value = '';
2985 switch( strtoupper( $config )) {
2986 case 'ALLOWEMPTY':
2987 $this->allowEmpty = $value;
2988 $subcfg = array( 'ALLOWEMPTY' => $value );
2989 $res = TRUE;
2990 break;
2991 case 'FORMAT':
2992 $value = trim( $value );
2993 $this->format = $value;
2994 $this->_createFormat();
2995 $subcfg = array( 'FORMAT' => $value );
2996 $res = TRUE;
2997 break;
2998 case 'LANGUAGE':
2999 // set language for calendar component as defined in [RFC 1766]
3000 $value = trim( $value );
3001 $this->language = $value;
3002 $subcfg = array( 'LANGUAGE' => $value );
3003 $res = TRUE;
3004 break;
3005 case 'NL':
3006 case 'NEWLINECHAR':
3007 $this->nl = $value;
3008 $subcfg = array( 'NL' => $value );
3009 $res = TRUE;
3010 break;
3011 case 'UNIQUE_ID':
3012 $value = trim( $value );
3013 $this->unique_id = $value;
3014 $subcfg = array( 'UNIQUE_ID' => $value );
3015 $res = TRUE;
3016 break;
3017 }
3018 if( !$res ) return FALSE;
3019 if( isset( $subcfg ) && !empty( $this->components )) {
3020 foreach( $subcfg as $cfgkey => $cfgvalue ) {
3021 foreach( $this->components as $cix => $component ) {
3022 $res = $component->setConfig( $cfgkey, $cfgvalue );
3023 if( !$res )
3024 break 2;
3025 $this->components[$cix] = $component; // PHP4 compliant
3026 }
3027 }
3028 }
3029 return $res;
3030 }
3031
3032 /**
3033 * get component property value/params
3034 *
3035 * if property has multiply values, consequtive function calls are needed
3036 *
3037 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3038 * @since 2.5.1 - 2008-11-02
3039 * @param string $propName, optional
3040 * @param int @propix, optional, if specific property is wanted in case of multiply occurences
3041 * @param bool $inclParam=FALSE
3042 * @param bool $specform=FALSE
3043 * @return mixed
3044 */
3045 function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) {
3046 if( $this->_notExistProp( $propName )) return FALSE;
3047 $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
3048 if( in_array( $propName, array( 'ATTENDEE', 'COMMENT', 'CONTACT', 'DESCRIPTION',
3049 'RESOURCES', 'TZNAME', 'X-PROP' ))) {
3050 if( !$propix )
3051 $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
3052 $this->propix[$propName] = --$propix;
3053 }
3054 switch( $propName ) {
3055 case 'ATTENDEE':
3056 if( !isset( $this->attendee[$propix] )) return FALSE;
3057 return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
3058 break;
3059 case 'CLASS':
3060 if( !empty( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value'];
3061 break;
3062 case 'COMMENT':
3063 if( !isset( $this->comment[$propix] )) return FALSE;
3064 return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value'];
3065 break;
3066 case 'COMPLETED':
3067 if( !empty( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value'];
3068 break;
3069 case 'CONTACT':
3070 if( !isset( $this->contact[$propix] )) return FALSE;
3071 return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value'];
3072 break;
3073 case 'CREATED':
3074 if( !empty( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value'];
3075 break;
3076 case 'DESCRIPTION':
3077 if( !isset( $this->description[$propix] )) return FALSE;
3078 return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value'];
3079 break;
3080 case 'DTEND':
3081 if( !empty( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value'];
3082 break;
3083 case 'DTSTAMP':
3084 if( in_array( $this->objName, array( 'hc_valarm', 'hc_vtimezone', 'standard', 'daylight' )))
3085 return;
3086 if( !isset( $this->dtstamp['value'] ))
3087 $this->_makeDtstamp();
3088 return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value'];
3089 break;
3090 case 'DTSTART':
3091 if( !empty( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value'];
3092 break;
3093 case 'DURATION':
3094 if( !isset( $this->duration['value'] )) return FALSE;
3095 $value = ( $specform ) ? $this->duration2date() : $this->duration['value'];
3096 return ( $inclParam ) ? array( 'value' => $value, 'params' => $this->duration['params'] ) : $value;
3097 break;
3098 case 'LAST-MODIFIED':
3099 if( !empty( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value'];
3100 break;
3101 case 'LOCATION':
3102 if( !empty( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value'];
3103 break;
3104 case 'ORGANIZER':
3105 if( !empty( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value'];
3106 break;
3107 case 'PRIORITY':
3108 if( !empty( $this->priority['value'] )) return ( $inclParam ) ? $this->priority : $this->priority['value'];
3109 break;
3110 case 'RESOURCES':
3111 if( !isset( $this->resources[$propix] )) return FALSE;
3112 return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value'];
3113 break;
3114 case 'SEQUENCE':
3115 if( !empty( $this->sequence['value'] )) return ( $inclParam ) ? $this->sequence : $this->sequence['value'];
3116 break;
3117 case 'STATUS':
3118 if( !empty( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value'];
3119 break;
3120 case 'SUMMARY':
3121 if( !empty( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value'];
3122 break;
3123 case 'TZID':
3124 if( !empty( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value'];
3125 break;
3126 case 'TZNAME':
3127 if( !isset( $this->tzname[$propix] )) return FALSE;
3128 return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
3129 break;
3130 case 'TZOFFSETFROM':
3131 if( !empty( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
3132 break;
3133 case 'TZOFFSETTO':
3134 if( !empty( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value'];
3135 break;
3136 case 'TZURL':
3137 if( !empty( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value'];
3138 break;
3139 case 'UID':
3140 if( in_array( $this->objName, array( 'hc_valarm', 'hc_vtimezone', 'standard', 'daylight' )))
3141 return FALSE;
3142 if( empty( $this->uid['value'] ))
3143 $this->_makeuid();
3144 return ( $inclParam ) ? $this->uid : $this->uid['value'];
3145 break;
3146 case 'URL':
3147 if( !empty( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value'];
3148 break;
3149 default:
3150 if( $propName != 'X-PROP' ) {
3151 if( !isset( $this->xprop[$propName] )) return FALSE;
3152 return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
3153 : array( $propName, $this->xprop[$propName]['value'] );
3154 }
3155 else {
3156 if( empty( $this->xprop )) return FALSE;
3157 $xpropno = 0;
3158 foreach( $this->xprop as $xpropkey => $xpropvalue ) {
3159 if( $propix == $xpropno )
3160 return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
3161 : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
3162 else
3163 $xpropno++;
3164 }
3165 return FALSE; // not found ??
3166 }
3167 }
3168 return FALSE;
3169 }
3170 /**
3171 * general component property setting
3172 *
3173 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3174 * @since 2.5.1 - 2008-11-05
3175 * @param mixed $args variable number of function arguments,
3176 * first argument is ALWAYS component name,
3177 * second ALWAYS component value!
3178 * @return void
3179 */
3180 function setProperty() {
3181 $numargs = func_num_args();
3182 if( 1 > $numargs ) return FALSE;
3183 $arglist = func_get_args();
3184 if( $this->_notExistProp( $arglist[0] )) return FALSE;
3185 if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] )))
3186 return FALSE;
3187 $arglist[0] = strtoupper( $arglist[0] );
3188 for( $argix=$numargs; $argix < 12; $argix++ ) {
3189 if( !isset( $arglist[$argix] ))
3190 $arglist[$argix] = null;
3191 }
3192 switch( $arglist[0] ) {
3193 case 'ATTENDEE':
3194 return $this->setAttendee( $arglist[1], $arglist[2], $arglist[3] );
3195 case 'COMMENT':
3196 return $this->setComment( $arglist[1], $arglist[2], $arglist[3] );
3197 case 'COMPLETED':
3198 return $this->setCompleted( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3199 case 'CONTACT':
3200 return $this->setContact( $arglist[1], $arglist[2], $arglist[3] );
3201 case 'CREATED':
3202 return $this->setCreated( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3203 case 'DESCRIPTION':
3204 return $this->setDescription( $arglist[1], $arglist[2], $arglist[3] );
3205 case 'DTEND':
3206 return $this->setDtend( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
3207 case 'DTSTAMP':
3208 return $this->setDtstamp( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3209 case 'DTSTART':
3210 return $this->setDtstart( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
3211 case 'DURATION':
3212 return $this->setDuration( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] );
3213 case 'LAST-MODIFIED':
3214 return $this->setLastModified( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3215 case 'LOCATION':
3216 return $this->setLocation( $arglist[1], $arglist[2] );
3217 case 'ORGANIZER':
3218 return $this->setOrganizer( $arglist[1], $arglist[2] );
3219 case 'PRIORITY':
3220 return $this->setPriority( $arglist[1], $arglist[2] );
3221 case 'RESOURCES':
3222 return $this->setResources( $arglist[1], $arglist[2], $arglist[3] );
3223 case 'SEQUENCE':
3224 return $this->setSequence( $arglist[1], $arglist[2] );
3225 case 'STATUS':
3226 return $this->setStatus( $arglist[1], $arglist[2] );
3227 case 'SUMMARY':
3228 return $this->setSummary( $arglist[1], $arglist[2] );
3229 case 'TZID':
3230 return $this->setTzid( $arglist[1], $arglist[2] );
3231 case 'TZNAME':
3232 return $this->setTzname( $arglist[1], $arglist[2], $arglist[3] );
3233 case 'TZOFFSETFROM':
3234 return $this->setTzoffsetfrom( $arglist[1], $arglist[2] );
3235 case 'TZOFFSETTO':
3236 return $this->setTzoffsetto( $arglist[1], $arglist[2] );
3237 case 'TZURL':
3238 return $this->setTzurl( $arglist[1], $arglist[2] );
3239 case 'UID':
3240 return $this->setUid( $arglist[1], $arglist[2] );
3241 case 'URL':
3242 return $this->setUrl( $arglist[1], $arglist[2] );
3243 default:
3244 return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
3245 }
3246 return FALSE;
3247 }
3248 /*********************************************************************************/
3249 /*********************************************************************************/
3250 /**
3251 * return a copy of this component
3252 *
3253 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3254 * @since 2.2.16 - 2007-11-07
3255 * @return object
3256 */
3257 function copy() {
3258 $serialized_contents = serialize($this);
3259 $copy = unserialize($serialized_contents);
3260 unset( $copy->propix );
3261 return $copy;
3262 }
3263 /**
3264 * get calendar component subcomponent from component container
3265 *
3266 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3267 * @since 2.5.1 - 2008-10-15
3268 * @param mixed $arg1 optional, ordno/component type/ component uid
3269 * @param mixed $arg2 optional, ordno if arg1 = component type
3270 * @return object
3271 */
3272 function getComponent ( $arg1=FALSE, $arg2=FALSE ) {
3273 if( !isset( $this->components )) return FALSE;
3274 $index = $argType = null;
3275 if ( !$arg1 ) {
3276 $argType = 'INDEX';
3277 $index = $this->compix['INDEX'] =
3278 ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
3279 }
3280 elseif ( ctype_digit( (string) $arg1 )) {
3281 $argType = 'INDEX';
3282 $index = (int) $arg1;
3283 unset( $this->compix );
3284 }
3285 elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
3286 unset( $this->compix['INDEX'] );
3287 $argType = strtolower( $arg1 );
3288 if( !$arg2 )
3289 $index = $this->compix[$argType] =
3290 ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
3291 else
3292 $index = (int) $arg2;
3293 }
3294 $index -= 1;
3295 $ckeys = array_keys( $this->components );
3296 if( !empty( $index) && ( $index > end( $ckeys )))
3297 return FALSE;
3298 $cix2gC = 0;
3299 foreach( $this->components as $cix => $component ) {
3300 if( empty( $component )) continue;
3301 unset( $component->propix );
3302 if(( 'INDEX' == $argType ) && ( $index == $cix ))
3303 return $component->copy();
3304 elseif( $argType == $component->objName ) {
3305 if( $index == $cix2gC )
3306 return $component->copy();
3307 $cix2gC++;
3308 }
3309 elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' ))) {
3310 unset( $component->propix );
3311 return $component->copy();
3312 }
3313 }
3314 /* not found.. . */
3315 unset( $this->compix );
3316 return false;
3317 }
3318 /**
3319 * add calendar component as subcomponent to container for subcomponents
3320 *
3321 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3322 * @since 2.4.13 - 2008-09-24
3323 * @param object $component calendar component
3324 * @param mixed $arg1 optional, ordno/component type/ component uid
3325 * @param mixed $arg2 optional, ordno if arg1 = component type
3326 * @return bool
3327 */
3328 function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
3329 if( !isset( $this->components )) return FALSE;
3330 if( '' >= $component->getConfig( 'language'))
3331 $component->setConfig( 'language', $this->getConfig( 'language' ));
3332 $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
3333 $component->setConfig( 'nl', $this->getConfig( 'nl' ));
3334 $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
3335 $component->setConfig( 'format', $this->getConfig( 'format' ));
3336 if( !in_array( $component->objName, array( 'hc_valarm', 'hc_vtimezone', 'standard', 'daylight' ))) {
3337 unset( $component->propix );
3338 /* make sure dtstamp and uid is set */
3339 $dummy = $component->getProperty( 'dtstamp' );
3340 $dummy = $component->getProperty( 'uid' );
3341 }
3342 if( !$arg1 ) {
3343 $this->components[] = $component->copy();
3344 return TRUE;
3345 }
3346 $argType = $index = null;
3347 if ( ctype_digit( (string) $arg1 )) {
3348 $argType = 'INDEX';
3349 $index = (int) $arg1 - 1;
3350 }
3351 elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
3352 $argType = strtolower( $arg1 );
3353 $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
3354 }
3355 $cix2sC = 0;
3356 foreach ( $this->components as $cix => $component2 ) {
3357 if( empty( $component2 )) continue;
3358 unset( $component2->propix );
3359 if(( 'INDEX' == $argType ) && ( $index == $cix )) {
3360 $this->components[$cix] = $component->copy();
3361 return TRUE;
3362 }
3363 elseif( $argType == $component2->objName ) {
3364 if( $index == $cix2sC ) {
3365 $this->components[$cix] = $component->copy();
3366 return TRUE;
3367 }
3368 $cix2sC++;
3369 }
3370 elseif( !$argType && ($arg1 == $component2->getProperty( 'uid' ))) {
3371 $this->components[$cix] = $component->copy();
3372 return TRUE;
3373 }
3374 }
3375 /* not found.. . insert anyway.. .*/
3376 $this->components[] = $component->copy();
3377 return TRUE;
3378 }
3379 /**
3380 * creates formatted output for subcomponents
3381 *
3382 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3383 * @since 2.4.10 - 2008-08-06
3384 * @return string
3385 */
3386 function createSubComponent() {
3387 $output = null;
3388 foreach( $this->components as $component ) {
3389 if( empty( $component )) continue;
3390 if( '' >= $component->getConfig( 'language'))
3391 $component->setConfig( 'language', $this->getConfig( 'language' ));
3392 $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
3393 $component->setConfig( 'nl', $this->getConfig( 'nl' ));
3394 $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
3395 $component->setConfig( 'format', $this->getConfig( 'format' ));
3396 $output .= $component->createComponent( $this->xcaldecl );
3397 }
3398 return $output;
3399 }
3400 /********************************************************************************/
3401 /**
3402 * break lines at pos 75
3403 *
3404 * Lines of text SHOULD NOT be longer than 75 octets, excluding the line
3405 * break. Long content lines SHOULD be split into a multiple line
3406 * representations using a line "folding" technique. That is, a long
3407 * line can be split between any two characters by inserting a CRLF
3408 * immediately followed by a single linear white space character (i.e.,
3409 * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
3410 * of CRLF followed immediately by a single linear white space character
3411 * is ignored (i.e., removed) when processing the content type.
3412 *
3413 * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where
3414 * the reserved expression "\n" in the arg $string could be broken up by the
3415 * folding of lines, causing ambiguity in the return string.
3416 * Fix uses public $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be.
3417 *
3418 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3419 * @since 2.2.8 - 2006-09-03
3420 * @param string $value
3421 * @return string
3422 */
3423 function _size75( $string ) {
3424 $strlen = strlen( $string );
3425 $tmp = $string;
3426 $string = null;
3427 while( $strlen > 75 ) {
3428 $breakAtChar = 75;
3429 if( substr( $tmp, ( $breakAtChar - 1 ), strlen( '\n' )) == '\n' )
3430 $breakAtChar = $breakAtChar - 1;
3431 $string .= substr( $tmp, 0, $breakAtChar );
3432 $string .= $this->nl;
3433 $tmp = ' '.substr( $tmp, $breakAtChar );
3434 $strlen = strlen( $tmp );
3435 } // while
3436 $string .= rtrim( $tmp ); // the rest
3437 if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
3438 $string .= $this->nl;
3439 return $string;
3440 }
3441 /**
3442 * special characters management output
3443 *
3444 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3445 * @since 2.3.3 - 2007-12-20
3446 * @param string $string
3447 * @return string
3448 */
3449 function _strrep( $string ) {
3450 switch( $this->format ) {
3451 case 'xcal':
3452 $string = str_replace( '\n', $this->nl, $string);
3453 $string = htmlspecialchars( strip_tags( stripslashes( urldecode ( $string ))));
3454 break;
3455 default:
3456 $pos = 0;
3457 while( $pos <= strlen( $string )) {
3458 $pos = strpos( $string, "\\", $pos );
3459 if( FALSE === $pos )
3460 break;
3461 if( !in_array( $string[($pos + 1)], array( 'n', 'N', 'r', ',', ';' ))) {
3462 $string = substr( $string, 0, $pos )."\\".substr( $string, ( $pos + 1 ));
3463 $pos += 1;
3464 }
3465 $pos += 1;
3466 }
3467 if( FALSE !== strpos( $string, '"' ))
3468 $string = str_replace('"', "'", $string);
3469 if( FALSE !== strpos( $string, ',' ))
3470 $string = str_replace(',', '\,', $string);
3471 if( FALSE !== strpos( $string, ';' ))
3472 $string = str_replace(';', '\;', $string);
3473 if( FALSE !== strpos( $string, "\r\n" ))
3474 $string = str_replace( "\r\n", '\n', $string);
3475 elseif( FALSE !== strpos( $string, "\r" ))
3476 $string = str_replace( "\r", '\n', $string);
3477 if( FALSE !== strpos( $string, '\N' ))
3478 $string = str_replace( '\N', '\n', $string);
3479 // if( FALSE !== strpos( $string, $this->nl ))
3480 $string = str_replace( $this->nl, '\n', $string);
3481 break;
3482 }
3483 return $string;
3484 }
3485 /**
3486 * special characters management input (from iCal file)
3487 *
3488 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3489 * @since 2.3.3 - 2007-11-23
3490 * @param string $string
3491 * @return string
3492 */
3493 function _strunrep( $string ) {
3494 $string = str_replace( '\\\\', '\\', $string);
3495 $string = str_replace( '\,', ',', $string);
3496 $string = str_replace( '\;', ';', $string);
3497 // $string = str_replace( '\n', $this->nl, $string); // ??
3498 return $string;
3499 }
3500 }
3501 /*********************************************************************************/
3502 /*********************************************************************************/
3503 /**
3504 * class for calendar component VEVENT
3505 *
3506 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3507 * @since 2.5.1 - 2008-10-12
3508 */
3509 class hc_vevent extends hc_calendarComponent {
3510 public $attendee;
3511 public $comment;
3512 public $contact;
3513 public $class;
3514 public $created;
3515 public $description;
3516 public $dtend;
3517 public $dtstart;
3518 public $duration;
3519 public $lastmodified;
3520 public $location;
3521 public $organizer;
3522 public $priority;
3523 public $resources;
3524 public $sequence;
3525 public $status;
3526 public $summary;
3527 public $url;
3528 public $xprop;
3529 // component subcomponents container
3530 public $components;
3531 /**
3532 * constructor for calendar component VEVENT object
3533 *
3534 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3535 * @since 2.5.1 - 2008-10-31
3536 * @return void
3537 */
3538 function __construct() {
3539 parent::__construct();
3540
3541 $this->attendee = '';
3542 $this->class = '';
3543 $this->comment = '';
3544 $this->contact = '';
3545 $this->created = '';
3546 $this->description = '';
3547 $this->dtstart = '';
3548 $this->dtend = '';
3549 $this->duration = '';
3550 $this->lastmodified = '';
3551 $this->location = '';
3552 $this->organizer = '';
3553 $this->priority = '';
3554 $this->resources = '';
3555 $this->sequence = '';
3556 $this->status = '';
3557 $this->summary = '';
3558 $this->url = '';
3559 $this->xprop = '';
3560
3561 $this->components = array();
3562
3563 }
3564 /**
3565 * create formatted output for calendar component VEVENT object instance
3566 *
3567 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3568 * @since 2.5.1 - 2008-11-07
3569 * @param array $xcaldecl
3570 * @return string
3571 */
3572 function createComponent( &$xcaldecl ) {
3573 $objectname = $this->_createFormat();
3574 $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
3575 $component .= $this->createUid();
3576 $component .= $this->createDtstamp();
3577 $component .= $this->createAttendee();
3578 $component .= $this->createComment();
3579 $component .= $this->createContact();
3580 $component .= $this->createCreated();
3581 $component .= $this->createDescription();
3582 $component .= $this->createDtstart();
3583 $component .= $this->createDtend();
3584 $component .= $this->createDuration();
3585 $component .= $this->createLastModified();
3586 $component .= $this->createLocation();
3587 $component .= $this->createOrganizer();
3588 $component .= $this->createPriority();
3589 $component .= $this->createResources();
3590 $component .= $this->createSequence();
3591 $component .= $this->createStatus();
3592 $component .= $this->createSummary();
3593 $component .= $this->createUrl();
3594 $component .= $this->createXprop();
3595 $component .= $this->createSubComponent();
3596 $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
3597 if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
3598 foreach( $this->xcaldecl as $localxcaldecl )
3599 $xcaldecl[] = $localxcaldecl;
3600 }
3601 return $component;
3602 }
3603 }
3604
3605 /*********************************************************************************/
3606 /*********************************************************************************/
3607 /**
3608 * class for calendar component VALARM
3609 *
3610 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3611 * @since 2.5.1 - 2008-10-12
3612 */
3613 class hc_valarm extends hc_calendarComponent {
3614 public $attendee;
3615 public $description;
3616 public $duration;
3617 public $summary;
3618 public $trigger;
3619 public $xprop;
3620 /**
3621 * constructor for calendar component VALARM object
3622 *
3623 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3624 * @since 2.5.1 - 2008-10-31
3625 * @return void
3626 */
3627 function __construct() {
3628 parent::__construct();
3629
3630 $this->attendee = '';
3631 $this->description = '';
3632 $this->duration = '';
3633 $this->summary = '';
3634 $this->xprop = '';
3635 }
3636 /**
3637 * create formatted output for calendar component VALARM object instance
3638 *
3639 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3640 * @since 2.5.1 - 2008-10-22
3641 * @param array $xcaldecl
3642 * @return string
3643 */
3644 function createComponent( &$xcaldecl ) {
3645 $objectname = $this->_createFormat();
3646 $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
3647 $component .= $this->createAttendee();
3648 $component .= $this->createDescription();
3649 $component .= $this->createDuration();
3650 $component .= $this->createSummary();
3651 $component .= $this->createXprop();
3652 $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
3653 return $component;
3654 }
3655 }
3656 /**********************************************************************************
3657 /*********************************************************************************/
3658 /**
3659 * class for calendar component VTIMEZONE
3660 *
3661 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3662 * @since 2.5.1 - 2008-10-12
3663 */
3664 class hc_vtimezone extends hc_calendarComponent {
3665 public $timezonetype;
3666
3667 public $comment;
3668 public $dtstart;
3669 public $lastmodified;
3670 public $tzid;
3671 public $tzname;
3672 public $tzoffsetfrom;
3673 public $tzoffsetto;
3674 public $tzurl;
3675 public $xprop;
3676 // component subcomponents container
3677 public $components;
3678 /**
3679 * constructor for calendar component VTIMEZONE object
3680 *
3681 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3682 * @since 2.5.1 - 2008-10-31
3683 * @param string $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT )
3684 * @return void
3685 */
3686 function __construct( $timezonetype=FALSE ) {
3687 if( !$timezonetype )
3688 $this->timezonetype = 'VTIMEZONE';
3689 else
3690 $this->timezonetype = strtoupper( $timezonetype );
3691 parent::__construct();
3692
3693 $this->comment = '';
3694 $this->dtstart = '';
3695 $this->lastmodified = '';
3696 $this->tzid = '';
3697 $this->tzname = '';
3698 $this->tzoffsetfrom = '';
3699 $this->tzoffsetto = '';
3700 $this->tzurl = '';
3701 $this->xprop = '';
3702
3703 $this->components = array();
3704 }
3705 /**
3706 * create formatted output for calendar component VTIMEZONE object instance
3707 *
3708 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3709 * @since 2.5.1 - 2008-10-25
3710 * @param array $xcaldecl
3711 * @return string
3712 */
3713 function createComponent( &$xcaldecl ) {
3714 $objectname = $this->_createFormat();
3715 $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
3716 $component .= $this->createTzid();
3717 $component .= $this->createLastModified();
3718 $component .= $this->createTzurl();
3719 $component .= $this->createDtstart();
3720 $component .= $this->createTzoffsetfrom();
3721 $component .= $this->createTzoffsetto();
3722 $component .= $this->createComment();
3723 $component .= $this->createTzname();
3724 $component .= $this->createXprop();
3725 $component .= $this->createSubComponent();
3726
3727 $tz_obj = new DateTimeZone( $this->tzid['value'] );
3728 $from = $to = time();
3729 $year = 86400 * 360;
3730 $transitions = $tz_obj->getTransitions($from - $year, $to + $year);
3731 // $transitions = array();
3732 $components = array();
3733
3734 $std = null; $dst = null;
3735 foreach( $transitions as $i => $trans ){
3736 $cmp = null;
3737
3738 // skip the first entry...
3739 if ($i == 0) {
3740 // ... but remember the offset for the next TZOFFSETFROM value
3741 $tzfrom = $trans['offset'] / 3600;
3742 continue;
3743 }
3744
3745 $cmp = array();
3746 // daylight saving time definition
3747 if( $trans['isdst'] ){
3748 $t_dst = $trans['ts'];
3749 // $dst = new VObject\Component('DAYLIGHT');
3750 // $cmp = $dst;
3751 $cmp_name = 'DAYLIGHT';
3752 }
3753 // standard time definition
3754 else {
3755 $t_std = $trans['ts'];
3756 // $std = new VObject\Component('STANDARD');
3757 // $cmp = $std;
3758 $cmp_name = 'STANDARD';
3759 }
3760
3761 $dt = new DateTime($trans['time']);
3762 $offset = $trans['offset'] / 3600;
3763
3764 $cmp['DTSTART'] = $dt->format('Ymd\THis');
3765 $tzfrom_mod = $tzfrom >= 0 ? $tzfrom : - $tzfrom;
3766 $offset_mod = $offset >= 0 ? $offset : - $offset;
3767 $tzoffsetfrom = sprintf('%s%02d%02d', $tzfrom >= 0 ? '+' : '-', floor($tzfrom_mod), ($tzfrom_mod - floor($tzfrom_mod)) * 60);
3768 $tzoffsetto = sprintf('%s%02d%02d', $offset >= 0 ? '+' : '-', floor($offset_mod), ($offset_mod - floor($offset_mod)) * 60);
3769
3770 $cmp['TZOFFSETFROM'] = $tzoffsetfrom;
3771 $cmp['TZOFFSETTO'] = $tzoffsetto;
3772
3773 // add abbreviated timezone name if available
3774 if (!empty($trans['abbr'])) {
3775 // $cmp['TZNAME'] = $trans['abbr'];
3776 }
3777
3778 $tzfrom = $offset;
3779
3780 $components[] = array( $cmp_name, $cmp );
3781 // $vt[$cmp_name] = $cmp;
3782 // $vt->add($cmp);
3783
3784 // we covered the entire date range
3785 if ($std && $dst && min($t_std, $t_dst) < $from && max($t_std, $t_dst) > $to) {
3786 break;
3787 }
3788 }
3789
3790 $use_tz_details = FALSE;
3791
3792 if( $use_tz_details ){
3793 $vtz2 = array();
3794 // $vtz2[] = 'BEGIN' . ':' . 'VTIMEZONE';
3795 foreach( $components as $cmp_array ){
3796 list( $cmp_name, $cmp ) = $cmp_array;
3797
3798 $vtz2[] = 'BEGIN' . ':' . $cmp_name;
3799 foreach( $cmp as $k => $v ){
3800 $vtz2[] = $k . ':' . $v;
3801 }
3802 $vtz2[] = 'END' . ':' . $cmp_name;
3803 }
3804 // $vtz2[] = 'END' . ':' . 'VTIMEZONE';
3805 $vtz2 = join($this->nl, $vtz2) . $this->nl;
3806 $component .= $vtz2;
3807 }
3808
3809 $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
3810 if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
3811 foreach( $this->xcaldecl as $localxcaldecl )
3812 $xcaldecl[] = $localxcaldecl;
3813 }
3814 return $component;
3815 }
3816 }
3817 ?>