PluginProbe
ShiftController Employee Shift Scheduling / 4.9.24
ShiftController Employee Shift Scheduling v4.9.24
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.24, at sh4/ical/lib/icalcreator.php

3,816 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 switch( strtoupper( $config )) {
2985 case 'ALLOWEMPTY':
2986 $this->allowEmpty = $value;
2987 $subcfg = array( 'ALLOWEMPTY' => $value );
2988 $res = TRUE;
2989 break;
2990 case 'FORMAT':
2991 $value = trim( $value );
2992 $this->format = $value;
2993 $this->_createFormat();
2994 $subcfg = array( 'FORMAT' => $value );
2995 $res = TRUE;
2996 break;
2997 case 'LANGUAGE':
2998 // set language for calendar component as defined in [RFC 1766]
2999 $value = trim( $value );
3000 $this->language = $value;
3001 $subcfg = array( 'LANGUAGE' => $value );
3002 $res = TRUE;
3003 break;
3004 case 'NL':
3005 case 'NEWLINECHAR':
3006 $this->nl = $value;
3007 $subcfg = array( 'NL' => $value );
3008 $res = TRUE;
3009 break;
3010 case 'UNIQUE_ID':
3011 $value = trim( $value );
3012 $this->unique_id = $value;
3013 $subcfg = array( 'UNIQUE_ID' => $value );
3014 $res = TRUE;
3015 break;
3016 }
3017 if( !$res ) return FALSE;
3018 if( isset( $subcfg ) && !empty( $this->components )) {
3019 foreach( $subcfg as $cfgkey => $cfgvalue ) {
3020 foreach( $this->components as $cix => $component ) {
3021 $res = $component->setConfig( $cfgkey, $cfgvalue );
3022 if( !$res )
3023 break 2;
3024 $this->components[$cix] = $component; // PHP4 compliant
3025 }
3026 }
3027 }
3028 return $res;
3029 }
3030
3031 /**
3032 * get component property value/params
3033 *
3034 * if property has multiply values, consequtive function calls are needed
3035 *
3036 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3037 * @since 2.5.1 - 2008-11-02
3038 * @param string $propName, optional
3039 * @param int @propix, optional, if specific property is wanted in case of multiply occurences
3040 * @param bool $inclParam=FALSE
3041 * @param bool $specform=FALSE
3042 * @return mixed
3043 */
3044 function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) {
3045 if( $this->_notExistProp( $propName )) return FALSE;
3046 $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
3047 if( in_array( $propName, array( 'ATTENDEE', 'COMMENT', 'CONTACT', 'DESCRIPTION',
3048 'RESOURCES', 'TZNAME', 'X-PROP' ))) {
3049 if( !$propix )
3050 $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
3051 $this->propix[$propName] = --$propix;
3052 }
3053 switch( $propName ) {
3054 case 'ATTENDEE':
3055 if( !isset( $this->attendee[$propix] )) return FALSE;
3056 return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
3057 break;
3058 case 'CLASS':
3059 if( !empty( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value'];
3060 break;
3061 case 'COMMENT':
3062 if( !isset( $this->comment[$propix] )) return FALSE;
3063 return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value'];
3064 break;
3065 case 'COMPLETED':
3066 if( !empty( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value'];
3067 break;
3068 case 'CONTACT':
3069 if( !isset( $this->contact[$propix] )) return FALSE;
3070 return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value'];
3071 break;
3072 case 'CREATED':
3073 if( !empty( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value'];
3074 break;
3075 case 'DESCRIPTION':
3076 if( !isset( $this->description[$propix] )) return FALSE;
3077 return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value'];
3078 break;
3079 case 'DTEND':
3080 if( !empty( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value'];
3081 break;
3082 case 'DTSTAMP':
3083 if( in_array( $this->objName, array( 'hc_valarm', 'hc_vtimezone', 'standard', 'daylight' )))
3084 return;
3085 if( !isset( $this->dtstamp['value'] ))
3086 $this->_makeDtstamp();
3087 return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value'];
3088 break;
3089 case 'DTSTART':
3090 if( !empty( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value'];
3091 break;
3092 case 'DURATION':
3093 if( !isset( $this->duration['value'] )) return FALSE;
3094 $value = ( $specform ) ? $this->duration2date() : $this->duration['value'];
3095 return ( $inclParam ) ? array( 'value' => $value, 'params' => $this->duration['params'] ) : $value;
3096 break;
3097 case 'LAST-MODIFIED':
3098 if( !empty( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value'];
3099 break;
3100 case 'LOCATION':
3101 if( !empty( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value'];
3102 break;
3103 case 'ORGANIZER':
3104 if( !empty( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value'];
3105 break;
3106 case 'PRIORITY':
3107 if( !empty( $this->priority['value'] )) return ( $inclParam ) ? $this->priority : $this->priority['value'];
3108 break;
3109 case 'RESOURCES':
3110 if( !isset( $this->resources[$propix] )) return FALSE;
3111 return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value'];
3112 break;
3113 case 'SEQUENCE':
3114 if( !empty( $this->sequence['value'] )) return ( $inclParam ) ? $this->sequence : $this->sequence['value'];
3115 break;
3116 case 'STATUS':
3117 if( !empty( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value'];
3118 break;
3119 case 'SUMMARY':
3120 if( !empty( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value'];
3121 break;
3122 case 'TZID':
3123 if( !empty( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value'];
3124 break;
3125 case 'TZNAME':
3126 if( !isset( $this->tzname[$propix] )) return FALSE;
3127 return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
3128 break;
3129 case 'TZOFFSETFROM':
3130 if( !empty( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
3131 break;
3132 case 'TZOFFSETTO':
3133 if( !empty( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value'];
3134 break;
3135 case 'TZURL':
3136 if( !empty( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value'];
3137 break;
3138 case 'UID':
3139 if( in_array( $this->objName, array( 'hc_valarm', 'hc_vtimezone', 'standard', 'daylight' )))
3140 return FALSE;
3141 if( empty( $this->uid['value'] ))
3142 $this->_makeuid();
3143 return ( $inclParam ) ? $this->uid : $this->uid['value'];
3144 break;
3145 case 'URL':
3146 if( !empty( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value'];
3147 break;
3148 default:
3149 if( $propName != 'X-PROP' ) {
3150 if( !isset( $this->xprop[$propName] )) return FALSE;
3151 return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
3152 : array( $propName, $this->xprop[$propName]['value'] );
3153 }
3154 else {
3155 if( empty( $this->xprop )) return FALSE;
3156 $xpropno = 0;
3157 foreach( $this->xprop as $xpropkey => $xpropvalue ) {
3158 if( $propix == $xpropno )
3159 return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
3160 : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
3161 else
3162 $xpropno++;
3163 }
3164 return FALSE; // not found ??
3165 }
3166 }
3167 return FALSE;
3168 }
3169 /**
3170 * general component property setting
3171 *
3172 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3173 * @since 2.5.1 - 2008-11-05
3174 * @param mixed $args variable number of function arguments,
3175 * first argument is ALWAYS component name,
3176 * second ALWAYS component value!
3177 * @return void
3178 */
3179 function setProperty() {
3180 $numargs = func_num_args();
3181 if( 1 > $numargs ) return FALSE;
3182 $arglist = func_get_args();
3183 if( $this->_notExistProp( $arglist[0] )) return FALSE;
3184 if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] )))
3185 return FALSE;
3186 $arglist[0] = strtoupper( $arglist[0] );
3187 for( $argix=$numargs; $argix < 12; $argix++ ) {
3188 if( !isset( $arglist[$argix] ))
3189 $arglist[$argix] = null;
3190 }
3191 switch( $arglist[0] ) {
3192 case 'ATTENDEE':
3193 return $this->setAttendee( $arglist[1], $arglist[2], $arglist[3] );
3194 case 'COMMENT':
3195 return $this->setComment( $arglist[1], $arglist[2], $arglist[3] );
3196 case 'COMPLETED':
3197 return $this->setCompleted( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3198 case 'CONTACT':
3199 return $this->setContact( $arglist[1], $arglist[2], $arglist[3] );
3200 case 'CREATED':
3201 return $this->setCreated( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3202 case 'DESCRIPTION':
3203 return $this->setDescription( $arglist[1], $arglist[2], $arglist[3] );
3204 case 'DTEND':
3205 return $this->setDtend( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
3206 case 'DTSTAMP':
3207 return $this->setDtstamp( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3208 case 'DTSTART':
3209 return $this->setDtstart( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
3210 case 'DURATION':
3211 return $this->setDuration( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] );
3212 case 'LAST-MODIFIED':
3213 return $this->setLastModified( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3214 case 'LOCATION':
3215 return $this->setLocation( $arglist[1], $arglist[2] );
3216 case 'ORGANIZER':
3217 return $this->setOrganizer( $arglist[1], $arglist[2] );
3218 case 'PRIORITY':
3219 return $this->setPriority( $arglist[1], $arglist[2] );
3220 case 'RESOURCES':
3221 return $this->setResources( $arglist[1], $arglist[2], $arglist[3] );
3222 case 'SEQUENCE':
3223 return $this->setSequence( $arglist[1], $arglist[2] );
3224 case 'STATUS':
3225 return $this->setStatus( $arglist[1], $arglist[2] );
3226 case 'SUMMARY':
3227 return $this->setSummary( $arglist[1], $arglist[2] );
3228 case 'TZID':
3229 return $this->setTzid( $arglist[1], $arglist[2] );
3230 case 'TZNAME':
3231 return $this->setTzname( $arglist[1], $arglist[2], $arglist[3] );
3232 case 'TZOFFSETFROM':
3233 return $this->setTzoffsetfrom( $arglist[1], $arglist[2] );
3234 case 'TZOFFSETTO':
3235 return $this->setTzoffsetto( $arglist[1], $arglist[2] );
3236 case 'TZURL':
3237 return $this->setTzurl( $arglist[1], $arglist[2] );
3238 case 'UID':
3239 return $this->setUid( $arglist[1], $arglist[2] );
3240 case 'URL':
3241 return $this->setUrl( $arglist[1], $arglist[2] );
3242 default:
3243 return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
3244 }
3245 return FALSE;
3246 }
3247 /*********************************************************************************/
3248 /*********************************************************************************/
3249 /**
3250 * return a copy of this component
3251 *
3252 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3253 * @since 2.2.16 - 2007-11-07
3254 * @return object
3255 */
3256 function copy() {
3257 $serialized_contents = serialize($this);
3258 $copy = unserialize($serialized_contents);
3259 unset( $copy->propix );
3260 return $copy;
3261 }
3262 /**
3263 * get calendar component subcomponent from component container
3264 *
3265 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3266 * @since 2.5.1 - 2008-10-15
3267 * @param mixed $arg1 optional, ordno/component type/ component uid
3268 * @param mixed $arg2 optional, ordno if arg1 = component type
3269 * @return object
3270 */
3271 function getComponent ( $arg1=FALSE, $arg2=FALSE ) {
3272 if( !isset( $this->components )) return FALSE;
3273 $index = $argType = null;
3274 if ( !$arg1 ) {
3275 $argType = 'INDEX';
3276 $index = $this->compix['INDEX'] =
3277 ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
3278 }
3279 elseif ( ctype_digit( (string) $arg1 )) {
3280 $argType = 'INDEX';
3281 $index = (int) $arg1;
3282 unset( $this->compix );
3283 }
3284 elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
3285 unset( $this->compix['INDEX'] );
3286 $argType = strtolower( $arg1 );
3287 if( !$arg2 )
3288 $index = $this->compix[$argType] =
3289 ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
3290 else
3291 $index = (int) $arg2;
3292 }
3293 $index -= 1;
3294 $ckeys = array_keys( $this->components );
3295 if( !empty( $index) && ( $index > end( $ckeys )))
3296 return FALSE;
3297 $cix2gC = 0;
3298 foreach( $this->components as $cix => $component ) {
3299 if( empty( $component )) continue;
3300 unset( $component->propix );
3301 if(( 'INDEX' == $argType ) && ( $index == $cix ))
3302 return $component->copy();
3303 elseif( $argType == $component->objName ) {
3304 if( $index == $cix2gC )
3305 return $component->copy();
3306 $cix2gC++;
3307 }
3308 elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' ))) {
3309 unset( $component->propix );
3310 return $component->copy();
3311 }
3312 }
3313 /* not found.. . */
3314 unset( $this->compix );
3315 return false;
3316 }
3317 /**
3318 * add calendar component as subcomponent to container for subcomponents
3319 *
3320 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3321 * @since 2.4.13 - 2008-09-24
3322 * @param object $component calendar component
3323 * @param mixed $arg1 optional, ordno/component type/ component uid
3324 * @param mixed $arg2 optional, ordno if arg1 = component type
3325 * @return bool
3326 */
3327 function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
3328 if( !isset( $this->components )) return FALSE;
3329 if( '' >= $component->getConfig( 'language'))
3330 $component->setConfig( 'language', $this->getConfig( 'language' ));
3331 $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
3332 $component->setConfig( 'nl', $this->getConfig( 'nl' ));
3333 $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
3334 $component->setConfig( 'format', $this->getConfig( 'format' ));
3335 if( !in_array( $component->objName, array( 'hc_valarm', 'hc_vtimezone', 'standard', 'daylight' ))) {
3336 unset( $component->propix );
3337 /* make sure dtstamp and uid is set */
3338 $dummy = $component->getProperty( 'dtstamp' );
3339 $dummy = $component->getProperty( 'uid' );
3340 }
3341 if( !$arg1 ) {
3342 $this->components[] = $component->copy();
3343 return TRUE;
3344 }
3345 $argType = $index = null;
3346 if ( ctype_digit( (string) $arg1 )) {
3347 $argType = 'INDEX';
3348 $index = (int) $arg1 - 1;
3349 }
3350 elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
3351 $argType = strtolower( $arg1 );
3352 $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
3353 }
3354 $cix2sC = 0;
3355 foreach ( $this->components as $cix => $component2 ) {
3356 if( empty( $component2 )) continue;
3357 unset( $component2->propix );
3358 if(( 'INDEX' == $argType ) && ( $index == $cix )) {
3359 $this->components[$cix] = $component->copy();
3360 return TRUE;
3361 }
3362 elseif( $argType == $component2->objName ) {
3363 if( $index == $cix2sC ) {
3364 $this->components[$cix] = $component->copy();
3365 return TRUE;
3366 }
3367 $cix2sC++;
3368 }
3369 elseif( !$argType && ($arg1 == $component2->getProperty( 'uid' ))) {
3370 $this->components[$cix] = $component->copy();
3371 return TRUE;
3372 }
3373 }
3374 /* not found.. . insert anyway.. .*/
3375 $this->components[] = $component->copy();
3376 return TRUE;
3377 }
3378 /**
3379 * creates formatted output for subcomponents
3380 *
3381 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3382 * @since 2.4.10 - 2008-08-06
3383 * @return string
3384 */
3385 function createSubComponent() {
3386 $output = null;
3387 foreach( $this->components as $component ) {
3388 if( empty( $component )) continue;
3389 if( '' >= $component->getConfig( 'language'))
3390 $component->setConfig( 'language', $this->getConfig( 'language' ));
3391 $component->setConfig( 'allowEmpty', $this->getConfig( 'allowEmpty' ));
3392 $component->setConfig( 'nl', $this->getConfig( 'nl' ));
3393 $component->setConfig( 'unique_id', $this->getConfig( 'unique_id' ));
3394 $component->setConfig( 'format', $this->getConfig( 'format' ));
3395 $output .= $component->createComponent( $this->xcaldecl );
3396 }
3397 return $output;
3398 }
3399 /********************************************************************************/
3400 /**
3401 * break lines at pos 75
3402 *
3403 * Lines of text SHOULD NOT be longer than 75 octets, excluding the line
3404 * break. Long content lines SHOULD be split into a multiple line
3405 * representations using a line "folding" technique. That is, a long
3406 * line can be split between any two characters by inserting a CRLF
3407 * immediately followed by a single linear white space character (i.e.,
3408 * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
3409 * of CRLF followed immediately by a single linear white space character
3410 * is ignored (i.e., removed) when processing the content type.
3411 *
3412 * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where
3413 * the reserved expression "\n" in the arg $string could be broken up by the
3414 * folding of lines, causing ambiguity in the return string.
3415 * Fix uses public $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be.
3416 *
3417 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3418 * @since 2.2.8 - 2006-09-03
3419 * @param string $value
3420 * @return string
3421 */
3422 function _size75( $string ) {
3423 $strlen = strlen( $string );
3424 $tmp = $string;
3425 $string = null;
3426 while( $strlen > 75 ) {
3427 $breakAtChar = 75;
3428 if( substr( $tmp, ( $breakAtChar - 1 ), strlen( '\n' )) == '\n' )
3429 $breakAtChar = $breakAtChar - 1;
3430 $string .= substr( $tmp, 0, $breakAtChar );
3431 $string .= $this->nl;
3432 $tmp = ' '.substr( $tmp, $breakAtChar );
3433 $strlen = strlen( $tmp );
3434 } // while
3435 $string .= rtrim( $tmp ); // the rest
3436 if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
3437 $string .= $this->nl;
3438 return $string;
3439 }
3440 /**
3441 * special characters management output
3442 *
3443 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3444 * @since 2.3.3 - 2007-12-20
3445 * @param string $string
3446 * @return string
3447 */
3448 function _strrep( $string ) {
3449 switch( $this->format ) {
3450 case 'xcal':
3451 $string = str_replace( '\n', $this->nl, $string);
3452 $string = htmlspecialchars( strip_tags( stripslashes( urldecode ( $string ))));
3453 break;
3454 default:
3455 $pos = 0;
3456 while( $pos <= strlen( $string )) {
3457 $pos = strpos( $string, "\\", $pos );
3458 if( FALSE === $pos )
3459 break;
3460 if( !in_array( $string[($pos + 1)], array( 'n', 'N', 'r', ',', ';' ))) {
3461 $string = substr( $string, 0, $pos )."\\".substr( $string, ( $pos + 1 ));
3462 $pos += 1;
3463 }
3464 $pos += 1;
3465 }
3466 if( FALSE !== strpos( $string, '"' ))
3467 $string = str_replace('"', "'", $string);
3468 if( FALSE !== strpos( $string, ',' ))
3469 $string = str_replace(',', '\,', $string);
3470 if( FALSE !== strpos( $string, ';' ))
3471 $string = str_replace(';', '\;', $string);
3472 if( FALSE !== strpos( $string, "\r\n" ))
3473 $string = str_replace( "\r\n", '\n', $string);
3474 elseif( FALSE !== strpos( $string, "\r" ))
3475 $string = str_replace( "\r", '\n', $string);
3476 if( FALSE !== strpos( $string, '\N' ))
3477 $string = str_replace( '\N', '\n', $string);
3478 // if( FALSE !== strpos( $string, $this->nl ))
3479 $string = str_replace( $this->nl, '\n', $string);
3480 break;
3481 }
3482 return $string;
3483 }
3484 /**
3485 * special characters management input (from iCal file)
3486 *
3487 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3488 * @since 2.3.3 - 2007-11-23
3489 * @param string $string
3490 * @return string
3491 */
3492 function _strunrep( $string ) {
3493 $string = str_replace( '\\\\', '\\', $string);
3494 $string = str_replace( '\,', ',', $string);
3495 $string = str_replace( '\;', ';', $string);
3496 // $string = str_replace( '\n', $this->nl, $string); // ??
3497 return $string;
3498 }
3499 }
3500 /*********************************************************************************/
3501 /*********************************************************************************/
3502 /**
3503 * class for calendar component VEVENT
3504 *
3505 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3506 * @since 2.5.1 - 2008-10-12
3507 */
3508 class hc_vevent extends hc_calendarComponent {
3509 public $attendee;
3510 public $comment;
3511 public $contact;
3512 public $class;
3513 public $created;
3514 public $description;
3515 public $dtend;
3516 public $dtstart;
3517 public $duration;
3518 public $lastmodified;
3519 public $location;
3520 public $organizer;
3521 public $priority;
3522 public $resources;
3523 public $sequence;
3524 public $status;
3525 public $summary;
3526 public $url;
3527 public $xprop;
3528 // component subcomponents container
3529 public $components;
3530 /**
3531 * constructor for calendar component VEVENT object
3532 *
3533 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3534 * @since 2.5.1 - 2008-10-31
3535 * @return void
3536 */
3537 function __construct() {
3538 parent::__construct();
3539
3540 $this->attendee = '';
3541 $this->class = '';
3542 $this->comment = '';
3543 $this->contact = '';
3544 $this->created = '';
3545 $this->description = '';
3546 $this->dtstart = '';
3547 $this->dtend = '';
3548 $this->duration = '';
3549 $this->lastmodified = '';
3550 $this->location = '';
3551 $this->organizer = '';
3552 $this->priority = '';
3553 $this->resources = '';
3554 $this->sequence = '';
3555 $this->status = '';
3556 $this->summary = '';
3557 $this->url = '';
3558 $this->xprop = '';
3559
3560 $this->components = array();
3561
3562 }
3563 /**
3564 * create formatted output for calendar component VEVENT object instance
3565 *
3566 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3567 * @since 2.5.1 - 2008-11-07
3568 * @param array $xcaldecl
3569 * @return string
3570 */
3571 function createComponent( &$xcaldecl ) {
3572 $objectname = $this->_createFormat();
3573 $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
3574 $component .= $this->createUid();
3575 $component .= $this->createDtstamp();
3576 $component .= $this->createAttendee();
3577 $component .= $this->createComment();
3578 $component .= $this->createContact();
3579 $component .= $this->createCreated();
3580 $component .= $this->createDescription();
3581 $component .= $this->createDtstart();
3582 $component .= $this->createDtend();
3583 $component .= $this->createDuration();
3584 $component .= $this->createLastModified();
3585 $component .= $this->createLocation();
3586 $component .= $this->createOrganizer();
3587 $component .= $this->createPriority();
3588 $component .= $this->createResources();
3589 $component .= $this->createSequence();
3590 $component .= $this->createStatus();
3591 $component .= $this->createSummary();
3592 $component .= $this->createUrl();
3593 $component .= $this->createXprop();
3594 $component .= $this->createSubComponent();
3595 $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
3596 if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
3597 foreach( $this->xcaldecl as $localxcaldecl )
3598 $xcaldecl[] = $localxcaldecl;
3599 }
3600 return $component;
3601 }
3602 }
3603
3604 /*********************************************************************************/
3605 /*********************************************************************************/
3606 /**
3607 * class for calendar component VALARM
3608 *
3609 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3610 * @since 2.5.1 - 2008-10-12
3611 */
3612 class hc_valarm extends hc_calendarComponent {
3613 public $attendee;
3614 public $description;
3615 public $duration;
3616 public $summary;
3617 public $trigger;
3618 public $xprop;
3619 /**
3620 * constructor for calendar component VALARM object
3621 *
3622 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3623 * @since 2.5.1 - 2008-10-31
3624 * @return void
3625 */
3626 function __construct() {
3627 parent::__construct();
3628
3629 $this->attendee = '';
3630 $this->description = '';
3631 $this->duration = '';
3632 $this->summary = '';
3633 $this->xprop = '';
3634 }
3635 /**
3636 * create formatted output for calendar component VALARM object instance
3637 *
3638 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3639 * @since 2.5.1 - 2008-10-22
3640 * @param array $xcaldecl
3641 * @return string
3642 */
3643 function createComponent( &$xcaldecl ) {
3644 $objectname = $this->_createFormat();
3645 $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
3646 $component .= $this->createAttendee();
3647 $component .= $this->createDescription();
3648 $component .= $this->createDuration();
3649 $component .= $this->createSummary();
3650 $component .= $this->createXprop();
3651 $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
3652 return $component;
3653 }
3654 }
3655 /**********************************************************************************
3656 /*********************************************************************************/
3657 /**
3658 * class for calendar component VTIMEZONE
3659 *
3660 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3661 * @since 2.5.1 - 2008-10-12
3662 */
3663 class hc_vtimezone extends hc_calendarComponent {
3664 public $timezonetype;
3665
3666 public $comment;
3667 public $dtstart;
3668 public $lastmodified;
3669 public $tzid;
3670 public $tzname;
3671 public $tzoffsetfrom;
3672 public $tzoffsetto;
3673 public $tzurl;
3674 public $xprop;
3675 // component subcomponents container
3676 public $components;
3677 /**
3678 * constructor for calendar component VTIMEZONE object
3679 *
3680 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3681 * @since 2.5.1 - 2008-10-31
3682 * @param string $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT )
3683 * @return void
3684 */
3685 function __construct( $timezonetype=FALSE ) {
3686 if( !$timezonetype )
3687 $this->timezonetype = 'VTIMEZONE';
3688 else
3689 $this->timezonetype = strtoupper( $timezonetype );
3690 parent::__construct();
3691
3692 $this->comment = '';
3693 $this->dtstart = '';
3694 $this->lastmodified = '';
3695 $this->tzid = '';
3696 $this->tzname = '';
3697 $this->tzoffsetfrom = '';
3698 $this->tzoffsetto = '';
3699 $this->tzurl = '';
3700 $this->xprop = '';
3701
3702 $this->components = array();
3703 }
3704 /**
3705 * create formatted output for calendar component VTIMEZONE object instance
3706 *
3707 * @author Kjell-Inge Gustafsson <ical@kigkonsult.se>
3708 * @since 2.5.1 - 2008-10-25
3709 * @param array $xcaldecl
3710 * @return string
3711 */
3712 function createComponent( &$xcaldecl ) {
3713 $objectname = $this->_createFormat();
3714 $component = $this->componentStart1.$objectname.$this->componentStart2.$this->nl;
3715 $component .= $this->createTzid();
3716 $component .= $this->createLastModified();
3717 $component .= $this->createTzurl();
3718 $component .= $this->createDtstart();
3719 $component .= $this->createTzoffsetfrom();
3720 $component .= $this->createTzoffsetto();
3721 $component .= $this->createComment();
3722 $component .= $this->createTzname();
3723 $component .= $this->createXprop();
3724 $component .= $this->createSubComponent();
3725
3726 $tz_obj = new DateTimeZone( $this->tzid['value'] );
3727 $from = $to = time();
3728 $year = 86400 * 360;
3729 $transitions = $tz_obj->getTransitions($from - $year, $to + $year);
3730 // $transitions = array();
3731 $components = array();
3732
3733 $std = null; $dst = null;
3734 foreach( $transitions as $i => $trans ){
3735 $cmp = null;
3736
3737 // skip the first entry...
3738 if ($i == 0) {
3739 // ... but remember the offset for the next TZOFFSETFROM value
3740 $tzfrom = $trans['offset'] / 3600;
3741 continue;
3742 }
3743
3744 $cmp = array();
3745 // daylight saving time definition
3746 if( $trans['isdst'] ){
3747 $t_dst = $trans['ts'];
3748 // $dst = new VObject\Component('DAYLIGHT');
3749 // $cmp = $dst;
3750 $cmp_name = 'DAYLIGHT';
3751 }
3752 // standard time definition
3753 else {
3754 $t_std = $trans['ts'];
3755 // $std = new VObject\Component('STANDARD');
3756 // $cmp = $std;
3757 $cmp_name = 'STANDARD';
3758 }
3759
3760 $dt = new DateTime($trans['time']);
3761 $offset = $trans['offset'] / 3600;
3762
3763 $cmp['DTSTART'] = $dt->format('Ymd\THis');
3764 $tzfrom_mod = $tzfrom >= 0 ? $tzfrom : - $tzfrom;
3765 $offset_mod = $offset >= 0 ? $offset : - $offset;
3766 $tzoffsetfrom = sprintf('%s%02d%02d', $tzfrom >= 0 ? '+' : '-', floor($tzfrom_mod), ($tzfrom_mod - floor($tzfrom_mod)) * 60);
3767 $tzoffsetto = sprintf('%s%02d%02d', $offset >= 0 ? '+' : '-', floor($offset_mod), ($offset_mod - floor($offset_mod)) * 60);
3768
3769 $cmp['TZOFFSETFROM'] = $tzoffsetfrom;
3770 $cmp['TZOFFSETTO'] = $tzoffsetto;
3771
3772 // add abbreviated timezone name if available
3773 if (!empty($trans['abbr'])) {
3774 // $cmp['TZNAME'] = $trans['abbr'];
3775 }
3776
3777 $tzfrom = $offset;
3778
3779 $components[] = array( $cmp_name, $cmp );
3780 // $vt[$cmp_name] = $cmp;
3781 // $vt->add($cmp);
3782
3783 // we covered the entire date range
3784 if ($std && $dst && min($t_std, $t_dst) < $from && max($t_std, $t_dst) > $to) {
3785 break;
3786 }
3787 }
3788
3789 $use_tz_details = FALSE;
3790
3791 if( $use_tz_details ){
3792 $vtz2 = array();
3793 // $vtz2[] = 'BEGIN' . ':' . 'VTIMEZONE';
3794 foreach( $components as $cmp_array ){
3795 list( $cmp_name, $cmp ) = $cmp_array;
3796
3797 $vtz2[] = 'BEGIN' . ':' . $cmp_name;
3798 foreach( $cmp as $k => $v ){
3799 $vtz2[] = $k . ':' . $v;
3800 }
3801 $vtz2[] = 'END' . ':' . $cmp_name;
3802 }
3803 // $vtz2[] = 'END' . ':' . 'VTIMEZONE';
3804 $vtz2 = join($this->nl, $vtz2) . $this->nl;
3805 $component .= $vtz2;
3806 }
3807
3808 $component .= $this->componentEnd1.$objectname.$this->componentEnd2;
3809 if( is_array( $this->xcaldecl ) && ( 0 < count( $this->xcaldecl ))) {
3810 foreach( $this->xcaldecl as $localxcaldecl )
3811 $xcaldecl[] = $localxcaldecl;
3812 }
3813 return $component;
3814 }
3815 }
3816 ?>