3 /*********************************************************************************/
4 /*********************************************************************************/
6 * abstract class for calendar components
8 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
9 * @since 2.9.6 - 2011-05-14
11 class calendarComponent {
12 // component property variables
16 // component config variables
22 var $objName; // created automatically at instance creation
23 var $dtzid; // default (local) timezone
24 // component internal variables
33 var $intAttrDelimiter;
34 var $attributeDelimiter;
36 // component xCal declaration container
39 * constructor for calendar component object
41 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
42 * @since 2.9.6 - 2011-05-17
44 function calendarComponent() {
45 $this->objName = ( isset( $this->timezonetype )) ?
46 strtolower( $this->timezonetype ) : get_class ( $this );
48 $this->dtstamp = array();
50 $this->language = null;
52 $this->unique_id = null;
55 $this->allowEmpty = TRUE;
56 $this->xcaldecl = array();
58 $this->_createFormat();
59 $this->_makeDtstamp();
61 /*********************************************************************************/
63 * Property Name: ACTION
66 * creates formatted output for calendar component property action
68 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
69 * @since 2.4.8 - 2008-10-22
72 function createAction() {
73 if( empty( $this->action )) return FALSE;
74 if( empty( $this->action['value'] ))
75 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ACTION' ) : FALSE;
76 $attributes = $this->_createParams( $this->action['params'] );
77 return $this->_createElement( 'ACTION', $attributes, $this->action['value'] );
80 * set calendar component property action
82 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
83 * @since 2.4.8 - 2008-11-04
84 * @param string $value "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
85 * @param mixed $params
88 function setAction( $value, $params=FALSE ) {
89 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
90 $this->action = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
93 /*********************************************************************************/
95 * Property Name: ATTACH
98 * creates formatted output for calendar component property attach
100 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
101 * @since 0.9.7 - 2006-11-23
104 function createAttach() {
105 if( empty( $this->attach )) return FALSE;
107 foreach( $this->attach as $attachPart ) {
108 if(! empty( $attachPart['value'] )) {
109 $attributes = $this->_createParams( $attachPart['params'] );
110 $output .= $this->_createElement( 'ATTACH', $attributes, $attachPart['value'] );
112 elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'ATTACH' );
117 * set calendar component property attach
119 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
120 * @since 2.5.1 - 2008-11-06
121 * @param string $value
122 * @param array $params, optional
123 * @param integer $index, optional
126 function setAttach( $value, $params=FALSE, $index=FALSE ) {
127 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
128 iCal_UtilityFunctions::_setMval( $this->attach, $value, $params, FALSE, $index );
131 /*********************************************************************************/
133 * Property Name: ATTENDEE
136 * creates formatted output for calendar component property attendee
138 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
139 * @since 2.9.8 - 2011-05-30
142 function createAttendee() {
143 if( empty( $this->attendee )) return FALSE;
145 foreach( $this->attendee as $attendeePart ) { // start foreach 1
146 if( empty( $attendeePart['value'] )) {
147 if( $this->getConfig( 'allowEmpty' ))
148 $output .= $this->_createElement( 'ATTENDEE' );
151 $attendee1 = $attendee2 = null;
152 foreach( $attendeePart as $paramlabel => $paramvalue ) { // start foreach 2
153 if( 'value' == $paramlabel )
154 $attendee2 .= $paramvalue;
155 elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) { // start elseif
156 // set attenddee parameters in rfc2445 order
157 if( isset( $paramvalue['CUTYPE'] ))
158 $attendee1 .= $this->intAttrDelimiter.'CUTYPE='.$paramvalue['CUTYPE'];
159 if( isset( $paramvalue['MEMBER'] )) {
160 $attendee1 .= $this->intAttrDelimiter.'MEMBER=';
161 foreach( $paramvalue['MEMBER'] as $cix => $opv )
162 $attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
164 if( isset( $paramvalue['ROLE'] ))
165 $attendee1 .= $this->intAttrDelimiter.'ROLE='.$paramvalue['ROLE'];
166 if( isset( $paramvalue['PARTSTAT'] ))
167 $attendee1 .= $this->intAttrDelimiter.'PARTSTAT='.$paramvalue['PARTSTAT'];
168 if( isset( $paramvalue['RSVP'] ))
169 $attendee1 .= $this->intAttrDelimiter.'RSVP='.$paramvalue['RSVP'];
170 if( isset( $paramvalue['DELEGATED-TO'] )) {
171 $attendee1 .= $this->intAttrDelimiter.'DELEGATED-TO=';
172 foreach( $paramvalue['DELEGATED-TO'] as $cix => $opv )
173 $attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
175 if( isset( $paramvalue['DELEGATED-FROM'] )) {
176 $attendee1 .= $this->intAttrDelimiter.'DELEGATED-FROM=';
177 foreach( $paramvalue['DELEGATED-FROM'] as $cix => $opv )
178 $attendee1 .= ( $cix ) ? ', "'.$opv.'"' : '"'.$opv.'"' ;
180 if( isset( $paramvalue['SENT-BY'] ))
181 $attendee1 .= $this->intAttrDelimiter.'SENT-BY="'.$paramvalue['SENT-BY'].'"';
182 if( isset( $paramvalue['CN'] ))
183 $attendee1 .= $this->intAttrDelimiter.'CN="'.$paramvalue['CN'].'"';
184 if( isset( $paramvalue['DIR'] ))
185 $attendee1 .= $this->intAttrDelimiter.'DIR="'.$paramvalue['DIR'].'"';
186 if( isset( $paramvalue['LANGUAGE'] ))
187 $attendee1 .= $this->intAttrDelimiter.'LANGUAGE='.$paramvalue['LANGUAGE'];
189 foreach( $paramvalue as $optparamlabel => $optparamvalue ) { // start foreach 3
190 if( ctype_digit( (string) $optparamlabel )) {
191 $xparams[] = $optparamvalue;
194 if( !in_array( $optparamlabel, array( 'CUTYPE', 'MEMBER', 'ROLE', 'PARTSTAT', 'RSVP', 'DELEGATED-TO', 'DELEGATED-FROM', 'SENT-BY', 'CN', 'DIR', 'LANGUAGE' )))
195 $xparams[$optparamlabel] = $optparamvalue;
197 ksort( $xparams, SORT_STRING );
198 foreach( $xparams as $paramKey => $paramValue ) {
199 if( ctype_digit( (string) $paramKey ))
200 $attendee1 .= $this->intAttrDelimiter.$paramValue;
202 $attendee1 .= $this->intAttrDelimiter."$paramKey=$paramValue";
204 } // end elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue )))
206 $output .= $this->_createElement( 'ATTENDEE', $attendee1, $attendee2 );
211 * set calendar component property attach
213 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
214 * @since 2.6.34 - 2010-12-18
215 * @param string $value
216 * @param array $params, optional
217 * @param integer $index, optional
220 function setAttendee( $value, $params=FALSE, $index=FALSE ) {
221 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
222 // ftp://, http://, mailto:, file://, gopher://, news:, nntp://, telnet://, wais://, prospero:// may exist.. . also in params
223 if( FALSE !== ( $pos = strpos( substr( $value, 0, 9 ), ':' )))
224 $value = strtoupper( substr( $value, 0, $pos )).substr( $value, $pos );
225 elseif( !empty( $value ))
226 $value = 'MAILTO:'.$value;
228 if( is_array($params )) {
229 $optarrays = array();
230 foreach( $params as $optparamlabel => $optparamvalue ) {
231 $optparamlabel = strtoupper( $optparamlabel );
232 switch( $optparamlabel ) {
235 case 'DELEGATED-FROM':
236 if( !is_array( $optparamvalue ))
237 $optparamvalue = array( $optparamvalue );
238 foreach( $optparamvalue as $part ) {
239 $part = trim( $part );
240 if(( '"' == substr( $part, 0, 1 )) &&
241 ( '"' == substr( $part, -1 )))
242 $part = substr( $part, 1, ( strlen( $part ) - 2 ));
243 if( 'mailto:' != strtolower( substr( $part, 0, 7 )))
244 $part = "MAILTO:$part";
246 $part = 'MAILTO:'.substr( $part, 7 );
247 $optarrays[$optparamlabel][] = $part;
251 if(( '"' == substr( $optparamvalue, 0, 1 )) &&
252 ( '"' == substr( $optparamvalue, -1 )))
253 $optparamvalue = substr( $optparamvalue, 1, ( strlen( $optparamvalue ) - 2 ));
254 if( 'SENT-BY' == $optparamlabel ) {
255 if( 'mailto:' != strtolower( substr( $optparamvalue, 0, 7 )))
256 $optparamvalue = "MAILTO:$optparamvalue";
258 $optparamvalue = 'MAILTO:'.substr( $optparamvalue, 7 );
260 $params2[$optparamlabel] = $optparamvalue;
262 } // end switch( $optparamlabel.. .
263 } // end foreach( $optparam.. .
264 foreach( $optarrays as $optparamlabel => $optparams )
265 $params2[$optparamlabel] = $optparams;
268 iCal_UtilityFunctions::_existRem( $params2, 'CUTYPE', 'INDIVIDUAL' );
269 iCal_UtilityFunctions::_existRem( $params2, 'PARTSTAT', 'NEEDS-ACTION' );
270 iCal_UtilityFunctions::_existRem( $params2, 'ROLE', 'REQ-PARTICIPANT' );
271 iCal_UtilityFunctions::_existRem( $params2, 'RSVP', 'FALSE' );
272 // check language setting
273 if( isset( $params2['CN' ] )) {
274 $lang = $this->getConfig( 'language' );
275 if( !isset( $params2['LANGUAGE' ] ) && !empty( $lang ))
276 $params2['LANGUAGE' ] = $lang;
278 iCal_UtilityFunctions::_setMval( $this->attendee, $value, $params2, FALSE, $index );
281 /*********************************************************************************/
283 * Property Name: CATEGORIES
286 * creates formatted output for calendar component property categories
288 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
289 * @since 2.4.8 - 2008-10-22
292 function createCategories() {
293 if( empty( $this->categories )) return FALSE;
295 foreach( $this->categories as $category ) {
296 if( empty( $category['value'] )) {
297 if ( $this->getConfig( 'allowEmpty' ))
298 $output .= $this->_createElement( 'CATEGORIES' );
301 $attributes = $this->_createParams( $category['params'], array( 'LANGUAGE' ));
302 if( is_array( $category['value'] )) {
303 foreach( $category['value'] as $cix => $categoryPart )
304 $category['value'][$cix] = $this->_strrep( $categoryPart );
305 $content = implode( ',', $category['value'] );
308 $content = $this->_strrep( $category['value'] );
309 $output .= $this->_createElement( 'CATEGORIES', $attributes, $content );
314 * set calendar component property categories
316 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
317 * @since 2.5.1 - 2008-11-06
318 * @param mixed $value
319 * @param array $params, optional
320 * @param integer $index, optional
323 function setCategories( $value, $params=FALSE, $index=FALSE ) {
324 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
325 iCal_UtilityFunctions::_setMval( $this->categories, $value, $params, FALSE, $index );
328 /*********************************************************************************/
330 * Property Name: CLASS
333 * creates formatted output for calendar component property class
335 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
336 * @since 0.9.7 - 2006-11-20
339 function createClass() {
340 if( empty( $this->class )) return FALSE;
341 if( empty( $this->class['value'] ))
342 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'CLASS' ) : FALSE;
343 $attributes = $this->_createParams( $this->class['params'] );
344 return $this->_createElement( 'CLASS', $attributes, $this->class['value'] );
347 * set calendar component property class
349 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
350 * @since 2.4.8 - 2008-11-04
351 * @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name
352 * @param array $params optional
355 function setClass( $value, $params=FALSE ) {
356 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
357 $this->class = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
360 /*********************************************************************************/
362 * Property Name: COMMENT
365 * creates formatted output for calendar component property comment
367 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
368 * @since 2.4.8 - 2008-10-22
371 function createComment() {
372 if( empty( $this->comment )) return FALSE;
374 foreach( $this->comment as $commentPart ) {
375 if( empty( $commentPart['value'] )) {
376 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'COMMENT' );
379 $attributes = $this->_createParams( $commentPart['params'], array( 'ALTREP', 'LANGUAGE' ));
380 $content = $this->_strrep( $commentPart['value'] );
381 $output .= $this->_createElement( 'COMMENT', $attributes, $content );
386 * set calendar component property comment
388 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
389 * @since 2.5.1 - 2008-11-06
390 * @param string $value
391 * @param array $params, optional
392 * @param integer $index, optional
395 function setComment( $value, $params=FALSE, $index=FALSE ) {
396 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
397 iCal_UtilityFunctions::_setMval( $this->comment, $value, $params, FALSE, $index );
400 /*********************************************************************************/
402 * Property Name: COMPLETED
405 * creates formatted output for calendar component property completed
407 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
408 * @since 2.4.8 - 2008-10-22
411 function createCompleted( ) {
412 if( empty( $this->completed )) return FALSE;
413 if( !isset( $this->completed['value']['year'] ) &&
414 !isset( $this->completed['value']['month'] ) &&
415 !isset( $this->completed['value']['day'] ) &&
416 !isset( $this->completed['value']['hour'] ) &&
417 !isset( $this->completed['value']['min'] ) &&
418 !isset( $this->completed['value']['sec'] ))
419 if( $this->getConfig( 'allowEmpty' ))
420 return $this->_createElement( 'COMPLETED' );
422 $formatted = iCal_UtilityFunctions::_format_date_time( $this->completed['value'], 7 );
423 $attributes = $this->_createParams( $this->completed['params'] );
424 return $this->_createElement( 'COMPLETED', $attributes, $formatted );
427 * set calendar component property completed
429 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
430 * @since 2.4.8 - 2008-10-23
432 * @param mixed $month optional
433 * @param int $day optional
434 * @param int $hour optional
435 * @param int $min optional
436 * @param int $sec optional
437 * @param array $params optional
440 function setCompleted( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
441 if( empty( $year )) {
442 if( $this->getConfig( 'allowEmpty' )) {
443 $this->completed = array( 'value' => null, 'params' => iCal_UtilityFunctions::_setParams( $params ));
449 $this->completed = iCal_UtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
452 /*********************************************************************************/
454 * Property Name: CONTACT
457 * creates formatted output for calendar component property contact
459 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
460 * @since 2.4.8 - 2008-10-23
463 function createContact() {
464 if( empty( $this->contact )) return FALSE;
466 foreach( $this->contact as $contact ) {
467 if( !empty( $contact['value'] )) {
468 $attributes = $this->_createParams( $contact['params'], array( 'ALTREP', 'LANGUAGE' ));
469 $content = $this->_strrep( $contact['value'] );
470 $output .= $this->_createElement( 'CONTACT', $attributes, $content );
472 elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'CONTACT' );
477 * set calendar component property contact
479 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
480 * @since 2.5.1 - 2008-11-05
481 * @param string $value
482 * @param array $params, optional
483 * @param integer $index, optional
486 function setContact( $value, $params=FALSE, $index=FALSE ) {
487 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
488 iCal_UtilityFunctions::_setMval( $this->contact, $value, $params, FALSE, $index );
491 /*********************************************************************************/
493 * Property Name: CREATED
496 * creates formatted output for calendar component property created
498 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
499 * @since 2.4.8 - 2008-10-21
502 function createCreated() {
503 if( empty( $this->created )) return FALSE;
504 $formatted = iCal_UtilityFunctions::_format_date_time( $this->created['value'], 7 );
505 $attributes = $this->_createParams( $this->created['params'] );
506 return $this->_createElement( 'CREATED', $attributes, $formatted );
509 * set calendar component property created
511 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
512 * @since 2.4.8 - 2008-10-23
513 * @param mixed $year optional
514 * @param mixed $month optional
515 * @param int $day optional
516 * @param int $hour optional
517 * @param int $min optional
518 * @param int $sec optional
519 * @param mixed $params optional
522 function setCreated( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
523 if( !isset( $year )) {
524 $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
526 $this->created = iCal_UtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
529 /*********************************************************************************/
531 * Property Name: DESCRIPTION
534 * creates formatted output for calendar component property description
536 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
537 * @since 2.4.8 - 2008-10-22
540 function createDescription() {
541 if( empty( $this->description )) return FALSE;
543 foreach( $this->description as $description ) {
544 if( !empty( $description['value'] )) {
545 $attributes = $this->_createParams( $description['params'], array( 'ALTREP', 'LANGUAGE' ));
546 $content = $this->_strrep( $description['value'] );
547 $output .= $this->_createElement( 'DESCRIPTION', $attributes, $content );
549 elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'DESCRIPTION' );
554 * set calendar component property description
556 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
557 * @since 2.6.24 - 2010-11-06
558 * @param string $value
559 * @param array $params, optional
560 * @param integer $index, optional
563 function setDescription( $value, $params=FALSE, $index=FALSE ) {
564 if( empty( $value )) { if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE; }
565 if( 'vjournal' != $this->objName )
567 iCal_UtilityFunctions::_setMval( $this->description, $value, $params, FALSE, $index );
570 /*********************************************************************************/
572 * Property Name: DTEND
575 * creates formatted output for calendar component property dtend
577 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
578 * @since 2.9.6 - 2011-05-14
581 function createDtend() {
582 if( empty( $this->dtend )) return FALSE;
583 if( !isset( $this->dtend['value']['year'] ) &&
584 !isset( $this->dtend['value']['month'] ) &&
585 !isset( $this->dtend['value']['day'] ) &&
586 !isset( $this->dtend['value']['hour'] ) &&
587 !isset( $this->dtend['value']['min'] ) &&
588 !isset( $this->dtend['value']['sec'] ))
589 if( $this->getConfig( 'allowEmpty' ))
590 return $this->_createElement( 'DTEND' );
592 $formatted = iCal_UtilityFunctions::_format_date_time( $this->dtend['value'] );
593 if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
594 ( !isset( $this->dtend['params']['VALUE'] ) || ( $this->dtend['params']['VALUE'] != 'DATE' )) &&
595 !isset( $this->dtend['params']['TZID'] ))
596 $this->dtend['params']['TZID'] = $tzid;
597 $attributes = $this->_createParams( $this->dtend['params'] );
598 return $this->_createElement( 'DTEND', $attributes, $formatted );
601 * set calendar component property dtend
603 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
604 * @since 2.9.6 - 2011-05-14
606 * @param mixed $month optional
607 * @param int $day optional
608 * @param int $hour optional
609 * @param int $min optional
610 * @param int $sec optional
611 * @param string $tz optional
612 * @param array params optional
615 function setDtend( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
616 if( empty( $year )) {
617 if( $this->getConfig( 'allowEmpty' )) {
618 $this->dtend = array( 'value' => null, 'params' => iCal_UtilityFunctions::_setParams( $params ));
624 $this->dtend = iCal_UtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
627 /*********************************************************************************/
629 * Property Name: DTSTAMP
632 * creates formatted output for calendar component property dtstamp
634 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
635 * @since 2.4.4 - 2008-03-07
638 function createDtstamp() {
639 if( !isset( $this->dtstamp['value']['year'] ) &&
640 !isset( $this->dtstamp['value']['month'] ) &&
641 !isset( $this->dtstamp['value']['day'] ) &&
642 !isset( $this->dtstamp['value']['hour'] ) &&
643 !isset( $this->dtstamp['value']['min'] ) &&
644 !isset( $this->dtstamp['value']['sec'] ))
645 $this->_makeDtstamp();
646 $formatted = iCal_UtilityFunctions::_format_date_time( $this->dtstamp['value'], 7 );
647 $attributes = $this->_createParams( $this->dtstamp['params'] );
648 return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
651 * computes datestamp for calendar component object instance dtstamp
653 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
654 * @since 2.10.9 - 2011-08-10
657 function _makeDtstamp() {
658 $d = mktime( date('H'), date('i'), (date('s') - date( 'Z' )), date('m'), date('d'), date('Y'));
659 $this->dtstamp['value'] = array( 'year' => date( 'Y', $d )
660 , 'month' => date( 'm', $d )
661 , 'day' => date( 'd', $d )
662 , 'hour' => date( 'H', $d )
663 , 'min' => date( 'i', $d )
664 , 'sec' => date( 's', $d ));
665 $this->dtstamp['params'] = null;
668 * set calendar component property dtstamp
670 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
671 * @since 2.4.8 - 2008-10-23
673 * @param mixed $month optional
674 * @param int $day optional
675 * @param int $hour optional
676 * @param int $min optional
677 * @param int $sec optional
678 * @param array $params optional
681 function setDtstamp( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
683 $this->_makeDtstamp();
685 $this->dtstamp = iCal_UtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
688 /*********************************************************************************/
690 * Property Name: DTSTART
693 * creates formatted output for calendar component property dtstart
695 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
696 * @since 2.9.6 - 2011-05-15
699 function createDtstart() {
700 if( empty( $this->dtstart )) return FALSE;
701 if( !isset( $this->dtstart['value']['year'] ) &&
702 !isset( $this->dtstart['value']['month'] ) &&
703 !isset( $this->dtstart['value']['day'] ) &&
704 !isset( $this->dtstart['value']['hour'] ) &&
705 !isset( $this->dtstart['value']['min'] ) &&
706 !isset( $this->dtstart['value']['sec'] )) {
707 if( $this->getConfig( 'allowEmpty' ))
708 return $this->_createElement( 'DTSTART' );
711 if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
712 unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
713 elseif(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
714 ( !isset( $this->dtstart['params']['VALUE'] ) || ( $this->dtstart['params']['VALUE'] != 'DATE' )) &&
715 !isset( $this->dtstart['params']['TZID'] ))
716 $this->dtstart['params']['TZID'] = $tzid;
717 $formatted = iCal_UtilityFunctions::_format_date_time( $this->dtstart['value'] );
718 $attributes = $this->_createParams( $this->dtstart['params'] );
719 return $this->_createElement( 'DTSTART', $attributes, $formatted );
722 * set calendar component property dtstart
724 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
725 * @since 2.6.22 - 2010-09-22
727 * @param mixed $month optional
728 * @param int $day optional
729 * @param int $hour optional
730 * @param int $min optional
731 * @param int $sec optional
732 * @param string $tz optional
733 * @param array $params optional
736 function setDtstart( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
737 if( empty( $year )) {
738 if( $this->getConfig( 'allowEmpty' )) {
739 $this->dtstart = array( 'value' => null, 'params' => iCal_UtilityFunctions::_setParams( $params ));
745 $this->dtstart = iCal_UtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart', $this->objName, $this->getConfig( 'TZID' ));
748 /*********************************************************************************/
753 * creates formatted output for calendar component property due
755 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
756 * @since 2.4.8 - 2008-10-22
759 function createDue() {
760 if( empty( $this->due )) return FALSE;
761 if( !isset( $this->due['value']['year'] ) &&
762 !isset( $this->due['value']['month'] ) &&
763 !isset( $this->due['value']['day'] ) &&
764 !isset( $this->due['value']['hour'] ) &&
765 !isset( $this->due['value']['min'] ) &&
766 !isset( $this->due['value']['sec'] )) {
767 if( $this->getConfig( 'allowEmpty' ))
768 return $this->_createElement( 'DUE' );
772 $formatted = iCal_UtilityFunctions::_format_date_time( $this->due['value'] );
773 if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
774 ( !isset( $this->due['params']['VALUE'] ) || ( $this->due['params']['VALUE'] != 'DATE' )) &&
775 !isset( $this->due['params']['TZID'] ))
776 $this->due['params']['TZID'] = $tzid;
777 $attributes = $this->_createParams( $this->due['params'] );
778 return $this->_createElement( 'DUE', $attributes, $formatted );
781 * set calendar component property due
783 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
784 * @since 2.4.8 - 2008-11-04
786 * @param mixed $month optional
787 * @param int $day optional
788 * @param int $hour optional
789 * @param int $min optional
790 * @param int $sec optional
791 * @param array $params optional
794 function setDue( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
795 if( empty( $year )) {
796 if( $this->getConfig( 'allowEmpty' )) {
797 $this->due = array( 'value' => null, 'params' => iCal_UtilityFunctions::_setParams( $params ));
803 $this->due = iCal_UtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
806 /*********************************************************************************/
808 * Property Name: DURATION
811 * creates formatted output for calendar component property duration
813 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
814 * @since 2.4.8 - 2008-10-21
817 function createDuration() {
818 if( empty( $this->duration )) return FALSE;
819 if( !isset( $this->duration['value']['week'] ) &&
820 !isset( $this->duration['value']['day'] ) &&
821 !isset( $this->duration['value']['hour'] ) &&
822 !isset( $this->duration['value']['min'] ) &&
823 !isset( $this->duration['value']['sec'] ))
824 if( $this->getConfig( 'allowEmpty' ))
825 return $this->_createElement( 'DURATION', array(), null );
827 $attributes = $this->_createParams( $this->duration['params'] );
828 return $this->_createElement( 'DURATION', $attributes, iCal_UtilityFunctions::_format_duration( $this->duration['value'] ));
831 * set calendar component property duration
833 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
834 * @since 2.4.8 - 2008-11-04
836 * @param mixed $day optional
837 * @param int $hour optional
838 * @param int $min optional
839 * @param int $sec optional
840 * @param array $params optional
843 function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
844 if( empty( $week )) if( $this->getConfig( 'allowEmpty' )) $week = null; else return FALSE;
845 if( is_array( $week ) && ( 1 <= count( $week )))
846 $this->duration = array( 'value' => iCal_UtilityFunctions::_duration_array( $week ), 'params' => iCal_UtilityFunctions::_setParams( $day ));
847 elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
848 $week = trim( $week );
849 if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
850 $week = substr( $week, 1 );
851 $this->duration = array( 'value' => iCal_UtilityFunctions::_duration_string( $week ), 'params' => iCal_UtilityFunctions::_setParams( $day ));
853 elseif( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec ))
856 $this->duration = array( 'value' => iCal_UtilityFunctions::_duration_array( array( $week, $day, $hour, $min, $sec )), 'params' => iCal_UtilityFunctions::_setParams( $params ));
859 /*********************************************************************************/
861 * Property Name: EXDATE
864 * creates formatted output for calendar component property exdate
866 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
867 * @since 2.4.8 - 2008-10-22
870 function createExdate() {
871 if( empty( $this->exdate )) return FALSE;
873 foreach( $this->exdate as $ex => $theExdate ) {
874 if( empty( $theExdate['value'] )) {
875 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'EXDATE' );
878 $content = $attributes = null;
879 foreach( $theExdate['value'] as $eix => $exdatePart ) {
880 $parno = count( $exdatePart );
881 $formatted = iCal_UtilityFunctions::_format_date_time( $exdatePart, $parno );
882 if( isset( $theExdate['params']['TZID'] ))
883 $formatted = str_replace( 'Z', '', $formatted);
885 if( isset( $theExdate['value'][0]['tz'] )) {
886 if( ctype_digit( substr( $theExdate['value'][0]['tz'], -4 )) ||
887 ( 'Z' == $theExdate['value'][0]['tz'] )) {
888 if( 'Z' != substr( $formatted, -1 ))
892 $formatted = str_replace( 'Z', '', $formatted );
895 $formatted = str_replace( 'Z', '', $formatted );
897 $content .= ( 0 < $eix ) ? ','.$formatted : $formatted;
899 $attributes .= $this->_createParams( $theExdate['params'] );
900 $output .= $this->_createElement( 'EXDATE', $attributes, $content );
905 * set calendar component property exdate
907 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
908 * @since 2.5.1 - 2008-11-05
909 * @param array exdates
910 * @param array $params, optional
911 * @param integer $index, optional
914 function setExdate( $exdates, $params=FALSE, $index=FALSE ) {
915 if( empty( $exdates )) {
916 if( $this->getConfig( 'allowEmpty' )) {
917 iCal_UtilityFunctions::_setMval( $this->exdate, null, $params, FALSE, $index );
923 $input = array( 'params' => iCal_UtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
924 /* ev. check 1:st date and save ev. timezone **/
925 iCal_UtilityFunctions::_chkdatecfg( reset( $exdates ), $parno, $input['params'] );
926 iCal_UtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter
927 foreach( $exdates as $eix => $theExdate ) {
928 if( iCal_UtilityFunctions::_isArrayTimestampDate( $theExdate ))
929 $exdatea = iCal_UtilityFunctions::_timestamp2date( $theExdate, $parno );
930 elseif( is_array( $theExdate ))
931 $exdatea = iCal_UtilityFunctions::_date_time_array( $theExdate, $parno );
932 elseif( 8 <= strlen( trim( $theExdate ))) // ex. 2006-08-03 10:12:18
933 $exdatea = iCal_UtilityFunctions::_date_time_string( $theExdate, $parno );
935 unset( $exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz'] );
936 elseif( isset( $exdatea['tz'] ))
937 $exdatea['tz'] = (string) $exdatea['tz'];
938 if( isset( $input['params']['TZID'] ) ||
939 ( isset( $exdatea['tz'] ) && !iCal_UtilityFunctions::_isOffset( $exdatea['tz'] )) ||
940 ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
941 ( isset( $input['value'][0]['tz'] ) && !iCal_UtilityFunctions::_isOffset( $input['value'][0]['tz'] )))
942 unset( $exdatea['tz'] );
943 $input['value'][] = $exdatea;
945 if( 0 >= count( $input['value'] ))
948 $input['params']['VALUE'] = 'DATE';
949 unset( $input['params']['TZID'] );
951 iCal_UtilityFunctions::_setMval( $this->exdate, $input['value'], $input['params'], FALSE, $index );
954 /*********************************************************************************/
956 * Property Name: EXRULE
959 * creates formatted output for calendar component property exrule
961 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
962 * @since 2.4.8 - 2008-10-22
965 function createExrule() {
966 if( empty( $this->exrule )) return FALSE;
967 return $this->_format_recur( 'EXRULE', $this->exrule );
970 * set calendar component property exdate
972 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
973 * @since 2.5.1 - 2008-11-05
974 * @param array $exruleset
975 * @param array $params, optional
976 * @param integer $index, optional
979 function setExrule( $exruleset, $params=FALSE, $index=FALSE ) {
980 if( empty( $exruleset )) if( $this->getConfig( 'allowEmpty' )) $exruleset = null; else return FALSE;
981 iCal_UtilityFunctions::_setMval( $this->exrule, iCal_UtilityFunctions::_setRexrule( $exruleset ), $params, FALSE, $index );
984 /*********************************************************************************/
986 * Property Name: FREEBUSY
989 * creates formatted output for calendar component property freebusy
991 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
992 * @since 2.4.8 - 2008-10-22
995 function createFreebusy() {
996 if( empty( $this->freebusy )) return FALSE;
998 foreach( $this->freebusy as $freebusyPart ) {
999 if( empty( $freebusyPart['value'] )) {
1000 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'FREEBUSY' );
1003 $attributes = $content = null;
1004 if( isset( $freebusyPart['value']['fbtype'] )) {
1005 $attributes .= $this->intAttrDelimiter.'FBTYPE='.$freebusyPart['value']['fbtype'];
1006 unset( $freebusyPart['value']['fbtype'] );
1007 $freebusyPart['value'] = array_values( $freebusyPart['value'] );
1010 $attributes .= $this->intAttrDelimiter.'FBTYPE=BUSY';
1011 $attributes .= $this->_createParams( $freebusyPart['params'] );
1013 $cnt = count( $freebusyPart['value']);
1014 foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) {
1015 $formatted = iCal_UtilityFunctions::_format_date_time( $freebusyPeriod[0] );
1016 $content .= $formatted;
1018 $cnt2 = count( $freebusyPeriod[1]);
1019 if( array_key_exists( 'year', $freebusyPeriod[1] )) // date-time
1021 elseif( array_key_exists( 'week', $freebusyPeriod[1] )) // duration
1023 if(( 7 == $cnt2 ) && // period= -> date-time
1024 isset( $freebusyPeriod[1]['year'] ) &&
1025 isset( $freebusyPeriod[1]['month'] ) &&
1026 isset( $freebusyPeriod[1]['day'] )) {
1027 $content .= iCal_UtilityFunctions::_format_date_time( $freebusyPeriod[1] );
1029 else { // period= -> dur-time
1030 $content .= iCal_UtilityFunctions::_format_duration( $freebusyPeriod[1] );
1036 $output .= $this->_createElement( 'FREEBUSY', $attributes, $content );
1041 * set calendar component property freebusy
1043 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1044 * @since 2.8.10 - 2011-03-24
1045 * @param string $fbType
1046 * @param array $fbValues
1047 * @param array $params, optional
1048 * @param integer $index, optional
1051 function setFreebusy( $fbType, $fbValues, $params=FALSE, $index=FALSE ) {
1052 if( empty( $fbValues )) {
1053 if( $this->getConfig( 'allowEmpty' )) {
1054 iCal_UtilityFunctions::_setMval( $this->freebusy, null, $params, FALSE, $index );
1060 $fbType = strtoupper( $fbType );
1061 if(( !in_array( $fbType, array( 'FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE' ))) &&
1062 ( 'X-' != substr( $fbType, 0, 2 )))
1064 $input = array( 'fbtype' => $fbType );
1065 foreach( $fbValues as $fbPeriod ) { // periods => period
1066 if( empty( $fbPeriod ))
1068 $freebusyPeriod = array();
1069 foreach( $fbPeriod as $fbMember ) { // pairs => singlepart
1070 $freebusyPairMember = array();
1071 if( is_array( $fbMember )) {
1072 if( iCal_UtilityFunctions::_isArrayDate( $fbMember )) { // date-time value
1073 $freebusyPairMember = iCal_UtilityFunctions::_date_time_array( $fbMember, 7 );
1074 $freebusyPairMember['tz'] = 'Z';
1076 elseif( iCal_UtilityFunctions::_isArrayTimestampDate( $fbMember )) { // timestamp value
1077 $freebusyPairMember = iCal_UtilityFunctions::_timestamp2date( $fbMember['timestamp'], 7 );
1078 $freebusyPairMember['tz'] = 'Z';
1080 else { // array format duration
1081 $freebusyPairMember = iCal_UtilityFunctions::_duration_array( $fbMember );
1084 elseif(( 3 <= strlen( trim( $fbMember ))) && // string format duration
1085 ( in_array( $fbMember{0}, array( 'P', '+', '-' )))) {
1086 if( 'P' != $fbMember{0} )
1087 $fbmember = substr( $fbMember, 1 );
1088 $freebusyPairMember = iCal_UtilityFunctions::_duration_string( $fbMember );
1090 elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18
1091 $freebusyPairMember = iCal_UtilityFunctions::_date_time_string( $fbMember, 7 );
1092 $freebusyPairMember['tz'] = 'Z';
1094 $freebusyPeriod[] = $freebusyPairMember;
1096 $input[] = $freebusyPeriod;
1098 iCal_UtilityFunctions::_setMval( $this->freebusy, $input, $params, FALSE, $index );
1101 /*********************************************************************************/
1103 * Property Name: GEO
1106 * creates formatted output for calendar component property geo
1108 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1109 * @since 2.4.8 - 2008-10-21
1112 function createGeo() {
1113 if( empty( $this->geo )) return FALSE;
1114 if( empty( $this->geo['value'] ))
1115 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'GEO' ) : FALSE;
1116 $attributes = $this->_createParams( $this->geo['params'] );
1118 $content .= number_format( (float) $this->geo['value']['latitude'], 6, '.', '');
1120 $content .= number_format( (float) $this->geo['value']['longitude'], 6, '.', '');
1121 return $this->_createElement( 'GEO', $attributes, $content );
1124 * set calendar component property geo
1126 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1127 * @since 2.4.8 - 2008-11-04
1128 * @param float $latitude
1129 * @param float $longitude
1130 * @param array $params optional
1133 function setGeo( $latitude, $longitude, $params=FALSE ) {
1134 if( !empty( $latitude ) && !empty( $longitude )) {
1135 if( !is_array( $this->geo )) $this->geo = array();
1136 $this->geo['value']['latitude'] = $latitude;
1137 $this->geo['value']['longitude'] = $longitude;
1138 $this->geo['params'] = iCal_UtilityFunctions::_setParams( $params );
1140 elseif( $this->getConfig( 'allowEmpty' ))
1141 $this->geo = array( 'value' => null, 'params' => iCal_UtilityFunctions::_setParams( $params ) );
1146 /*********************************************************************************/
1148 * Property Name: LAST-MODIFIED
1151 * creates formatted output for calendar component property last-modified
1153 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1154 * @since 2.4.8 - 2008-10-21
1157 function createLastModified() {
1158 if( empty( $this->lastmodified )) return FALSE;
1159 $attributes = $this->_createParams( $this->lastmodified['params'] );
1160 $formatted = iCal_UtilityFunctions::_format_date_time( $this->lastmodified['value'], 7 );
1161 return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
1164 * set calendar component property completed
1166 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1167 * @since 2.4.8 - 2008-10-23
1168 * @param mixed $year optional
1169 * @param mixed $month optional
1170 * @param int $day optional
1171 * @param int $hour optional
1172 * @param int $min optional
1173 * @param int $sec optional
1174 * @param array $params optional
1177 function setLastModified( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1179 $year = date('Ymd\THis', mktime( date( 'H' ), date( 'i' ), date( 's' ) - date( 'Z'), date( 'm' ), date( 'd' ), date( 'Y' )));
1180 $this->lastmodified = iCal_UtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
1183 /*********************************************************************************/
1185 * Property Name: LOCATION
1188 * creates formatted output for calendar component property location
1190 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1191 * @since 2.4.8 - 2008-10-22
1194 function createLocation() {
1195 if( empty( $this->location )) return FALSE;
1196 if( empty( $this->location['value'] ))
1197 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'LOCATION' ) : FALSE;
1198 $attributes = $this->_createParams( $this->location['params'], array( 'ALTREP', 'LANGUAGE' ));
1199 $content = $this->_strrep( $this->location['value'] );
1200 return $this->_createElement( 'LOCATION', $attributes, $content );
1203 * set calendar component property location
1205 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1206 * @since 2.4.8 - 2008-11-04
1207 * @param string $value
1208 * @param array params optional
1211 function setLocation( $value, $params=FALSE ) {
1212 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1213 $this->location = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1216 /*********************************************************************************/
1218 * Property Name: ORGANIZER
1221 * creates formatted output for calendar component property organizer
1223 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1224 * @since 2.6.33 - 2010-12-17
1227 function createOrganizer() {
1228 if( empty( $this->organizer )) return FALSE;
1229 if( empty( $this->organizer['value'] ))
1230 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ORGANIZER' ) : FALSE;
1231 $attributes = $this->_createParams( $this->organizer['params']
1232 , array( 'CN', 'DIR', 'SENT-BY', 'LANGUAGE' ));
1233 return $this->_createElement( 'ORGANIZER', $attributes, $this->organizer['value'] );
1236 * set calendar component property organizer
1238 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1239 * @since 2.6.27 - 2010-11-29
1240 * @param string $value
1241 * @param array params optional
1244 function setOrganizer( $value, $params=FALSE ) {
1245 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1246 if( FALSE === ( $pos = strpos( substr( $value, 0, 9 ), ':' )))
1247 $value = 'MAILTO:'.$value;
1249 $value = strtolower( substr( $value, 0, $pos )).substr( $value, $pos );
1250 $value = str_replace( 'mailto:', 'MAILTO:', $value );
1251 $this->organizer = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1252 if( isset( $this->organizer['params']['SENT-BY'] )){
1253 if( 'mailto:' !== strtolower( substr( $this->organizer['params']['SENT-BY'], 0, 7 )))
1254 $this->organizer['params']['SENT-BY'] = 'MAILTO:'.$this->organizer['params']['SENT-BY'];
1256 $this->organizer['params']['SENT-BY'] = 'MAILTO:'.substr( $this->organizer['params']['SENT-BY'], 7 );
1260 /*********************************************************************************/
1262 * Property Name: PERCENT-COMPLETE
1265 * creates formatted output for calendar component property percent-complete
1267 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1268 * @since 2.9.3 - 2011-05-14
1271 function createPercentComplete() {
1272 if( !isset($this->percentcomplete) || ( empty( $this->percentcomplete ) && !is_numeric( $this->percentcomplete ))) return FALSE;
1273 if( !isset( $this->percentcomplete['value'] ) || ( empty( $this->percentcomplete['value'] ) && !is_numeric( $this->percentcomplete['value'] )))
1274 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PERCENT-COMPLETE' ) : FALSE;
1275 $attributes = $this->_createParams( $this->percentcomplete['params'] );
1276 return $this->_createElement( 'PERCENT-COMPLETE', $attributes, $this->percentcomplete['value'] );
1279 * set calendar component property percent-complete
1281 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1282 * @since 2.9.3 - 2011-05-14
1284 * @param array $params optional
1287 function setPercentComplete( $value, $params=FALSE ) {
1288 if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1289 $this->percentcomplete = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1292 /*********************************************************************************/
1294 * Property Name: PRIORITY
1297 * creates formatted output for calendar component property priority
1299 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1300 * @since 2.9.3 - 2011-05-14
1303 function createPriority() {
1304 if( !isset($this->priority) || ( empty( $this->priority ) && !is_numeric( $this->priority ))) return FALSE;
1305 if( !isset( $this->priority['value'] ) || ( empty( $this->priority['value'] ) && !is_numeric( $this->priority['value'] )))
1306 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PRIORITY' ) : FALSE;
1307 $attributes = $this->_createParams( $this->priority['params'] );
1308 return $this->_createElement( 'PRIORITY', $attributes, $this->priority['value'] );
1311 * set calendar component property priority
1313 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1314 * @since 2.9.3 - 2011-05-14
1316 * @param array $params optional
1319 function setPriority( $value, $params=FALSE ) {
1320 if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1321 $this->priority = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1324 /*********************************************************************************/
1326 * Property Name: RDATE
1329 * creates formatted output for calendar component property rdate
1331 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1332 * @since 2.4.16 - 2008-10-26
1335 function createRdate() {
1336 if( empty( $this->rdate )) return FALSE;
1337 $utctime = ( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
1340 unset( $this->rdate['params']['TZID'] );
1341 foreach( $this->rdate as $theRdate ) {
1342 if( empty( $theRdate['value'] )) {
1343 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' );
1347 unset( $theRdate['params']['TZID'] );
1348 $attributes = $this->_createParams( $theRdate['params'] );
1349 $cnt = count( $theRdate['value'] );
1352 foreach( $theRdate['value'] as $rpix => $rdatePart ) {
1353 $contentPart = null;
1354 if( is_array( $rdatePart ) &&
1355 isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD
1357 unset( $rdatePart[0]['tz'] );
1358 $formatted = iCal_UtilityFunctions::_format_date_time( $rdatePart[0]); // PERIOD part 1
1359 if( $utctime || !empty( $theRdate['params']['TZID'] ))
1360 $formatted = str_replace( 'Z', '', $formatted);
1362 if( !empty( $rdatePart[0]['tz'] ) && iCal_UtilityFunctions::_isOffset( $rdatePart[0]['tz'] )) {
1363 if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
1366 $formatted = str_replace( 'Z', '', $formatted );
1368 $contentPart .= $formatted;
1369 $contentPart .= '/';
1370 $cnt2 = count( $rdatePart[1]);
1371 if( array_key_exists( 'year', $rdatePart[1] )) {
1372 if( array_key_exists( 'hour', $rdatePart[1] ))
1373 $cnt2 = 7; // date-time
1377 elseif( array_key_exists( 'week', $rdatePart[1] )) // duration
1379 if(( 7 == $cnt2 ) && // period= -> date-time
1380 isset( $rdatePart[1]['year'] ) &&
1381 isset( $rdatePart[1]['month'] ) &&
1382 isset( $rdatePart[1]['day'] )) {
1384 unset( $rdatePart[1]['tz'] );
1385 $formatted = iCal_UtilityFunctions::_format_date_time( $rdatePart[1] ); // PERIOD part 2
1386 if( $utctime || !empty( $theRdate['params']['TZID'] ))
1387 $formatted = str_replace( 'Z', '', $formatted);
1388 if( !empty( $rdatePart[0]['tz'] ) && iCal_UtilityFunctions::_isOffset( $rdatePart[0]['tz'] )) {
1389 if( 'Z' != substr( $formatted, -1 )) $formatted .= 'Z';
1392 $formatted = str_replace( 'Z', '', $formatted );
1393 $contentPart .= $formatted;
1395 else { // period= -> dur-time
1396 $contentPart .= iCal_UtilityFunctions::_format_duration( $rdatePart[1] );
1399 else { // SINGLE date start
1401 unset( $rdatePart['tz'] );
1402 $formatted = iCal_UtilityFunctions::_format_date_time( $rdatePart);
1403 if( $utctime || !empty( $theRdate['params']['TZID'] ))
1404 $formatted = str_replace( 'Z', '', $formatted);
1405 if( !$utctime && ( 0 < $rpix )) {
1406 if( !empty( $theRdate['value'][0]['tz'] ) && iCal_UtilityFunctions::_isOffset( $theRdate['value'][0]['tz'] )) {
1407 if( 'Z' != substr( $formatted, -1 ))
1411 $formatted = str_replace( 'Z', '', $formatted );
1413 $contentPart .= $formatted;
1415 $content .= $contentPart;
1420 $output .= $this->_createElement( 'RDATE', $attributes, $content );
1425 * set calendar component property rdate
1427 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1428 * @since 2.5.1 - 2008-11-07
1429 * @param array $rdates
1430 * @param array $params, optional
1431 * @param integer $index, optional
1434 function setRdate( $rdates, $params=FALSE, $index=FALSE ) {
1435 if( empty( $rdates )) {
1436 if( $this->getConfig( 'allowEmpty' )) {
1437 iCal_UtilityFunctions::_setMval( $this->rdate, null, $params, FALSE, $index );
1443 $input = array( 'params' => iCal_UtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
1444 if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) {
1445 unset( $input['params']['TZID'] );
1446 $input['params']['VALUE'] = 'DATE-TIME';
1448 /* check if PERIOD, if not set */
1449 if((!isset( $input['params']['VALUE'] ) || !in_array( $input['params']['VALUE'], array( 'DATE', 'PERIOD' ))) &&
1450 isset( $rdates[0] ) && is_array( $rdates[0] ) && ( 2 == count( $rdates[0] )) &&
1451 isset( $rdates[0][0] ) && isset( $rdates[0][1] ) && !isset( $rdates[0]['timestamp'] ) &&
1452 (( is_array( $rdates[0][0] ) && ( isset( $rdates[0][0]['timestamp'] ) ||
1453 iCal_UtilityFunctions::_isArrayDate( $rdates[0][0] ))) ||
1454 ( is_string( $rdates[0][0] ) && ( 8 <= strlen( trim( $rdates[0][0] ))))) &&
1455 ( is_array( $rdates[0][1] ) || ( is_string( $rdates[0][1] ) && ( 3 <= strlen( trim( $rdates[0][1] ))))))
1456 $input['params']['VALUE'] = 'PERIOD';
1457 /* check 1:st date, upd. $parno (opt) and save ev. timezone **/
1458 $date = reset( $rdates );
1459 if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) // PERIOD
1460 $date = reset( $date );
1461 iCal_UtilityFunctions::_chkdatecfg( $date, $parno, $input['params'] );
1462 if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
1463 unset( $input['params']['TZID'] );
1464 iCal_UtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default
1465 foreach( $rdates as $rpix => $theRdate ) {
1467 if( is_array( $theRdate )) {
1468 if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) { // PERIOD
1469 foreach( $theRdate as $rix => $rPeriod ) {
1470 if( is_array( $rPeriod )) {
1471 if( iCal_UtilityFunctions::_isArrayTimestampDate( $rPeriod )) // timestamp
1472 $inputab = ( isset( $rPeriod['tz'] )) ? iCal_UtilityFunctions::_timestamp2date( $rPeriod, $parno ) : iCal_UtilityFunctions::_timestamp2date( $rPeriod, 6 );
1473 elseif( iCal_UtilityFunctions::_isArrayDate( $rPeriod ))
1474 $inputab = ( 3 < count ( $rPeriod )) ? iCal_UtilityFunctions::_date_time_array( $rPeriod, $parno ) : iCal_UtilityFunctions::_date_time_array( $rPeriod, 6 );
1475 elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) // text-date
1476 $inputab = iCal_UtilityFunctions::_date_time_string( reset( $rPeriod ), $parno );
1477 else // array format duration
1478 $inputab = iCal_UtilityFunctions::_duration_array( $rPeriod );
1480 elseif(( 3 <= strlen( trim( $rPeriod ))) && // string format duration
1481 ( in_array( $rPeriod[0], array( 'P', '+', '-' )))) {
1482 if( 'P' != $rPeriod[0] )
1483 $rPeriod = substr( $rPeriod, 1 );
1484 $inputab = iCal_UtilityFunctions::_duration_string( $rPeriod );
1486 elseif( 8 <= strlen( trim( $rPeriod ))) // text date ex. 2006-08-03 10:12:18
1487 $inputab = iCal_UtilityFunctions::_date_time_string( $rPeriod, $parno );
1488 if( isset( $input['params']['TZID'] ) ||
1489 ( isset( $inputab['tz'] ) && !iCal_UtilityFunctions::_isOffset( $inputab['tz'] )) ||
1490 ( isset( $inputa[0] ) && ( !isset( $inputa[0]['tz'] ))) ||
1491 ( isset( $inputa[0]['tz'] ) && !iCal_UtilityFunctions::_isOffset( $inputa[0]['tz'] )))
1492 unset( $inputab['tz'] );
1493 $inputa[] = $inputab;
1496 elseif ( iCal_UtilityFunctions::_isArrayTimestampDate( $theRdate )) // timestamp
1497 $inputa = iCal_UtilityFunctions::_timestamp2date( $theRdate, $parno );
1499 $inputa = iCal_UtilityFunctions::_date_time_array( $theRdate, $parno );
1501 elseif( 8 <= strlen( trim( $theRdate ))) // text date ex. 2006-08-03 10:12:18
1502 $inputa = iCal_UtilityFunctions::_date_time_string( $theRdate, $parno );
1503 if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD
1505 unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
1506 elseif( isset( $inputa['tz'] ))
1507 $inputa['tz'] = (string) $inputa['tz'];
1508 if( isset( $input['params']['TZID'] ) ||
1509 ( isset( $inputa['tz'] ) && !iCal_UtilityFunctions::_isOffset( $inputa['tz'] )) ||
1510 ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
1511 ( isset( $input['value'][0]['tz'] ) && !iCal_UtilityFunctions::_isOffset( $input['value'][0]['tz'] )))
1512 unset( $inputa['tz'] );
1514 $input['value'][] = $inputa;
1517 $input['params']['VALUE'] = 'DATE';
1518 unset( $input['params']['TZID'] );
1520 iCal_UtilityFunctions::_setMval( $this->rdate, $input['value'], $input['params'], FALSE, $index );
1523 /*********************************************************************************/
1525 * Property Name: RECURRENCE-ID
1528 * creates formatted output for calendar component property recurrence-id
1530 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1531 * @since 2.9.6 - 2011-05-15
1534 function createRecurrenceid() {
1535 if( empty( $this->recurrenceid )) return FALSE;
1536 if( empty( $this->recurrenceid['value'] ))
1537 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE;
1538 $formatted = iCal_UtilityFunctions::_format_date_time( $this->recurrenceid['value'] );
1539 if(( FALSE !== ( $tzid = $this->getConfig( 'TZID' ))) &&
1540 ( !isset( $this->recurrenceid['params']['VALUE'] ) || ( $this->recurrenceid['params']['VALUE'] != 'DATE' )) &&
1541 !isset( $this->recurrenceid['params']['TZID'] ))
1542 $this->recurrenceid['params']['TZID'] = $tzid;
1543 $attributes = $this->_createParams( $this->recurrenceid['params'] );
1544 return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted );
1547 * set calendar component property recurrence-id
1549 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1550 * @since 2.9.6 - 2011-05-15
1551 * @param mixed $year
1552 * @param mixed $month optional
1553 * @param int $day optional
1554 * @param int $hour optional
1555 * @param int $min optional
1556 * @param int $sec optional
1557 * @param array $params optional
1560 function setRecurrenceid( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
1561 if( empty( $year )) {
1562 if( $this->getConfig( 'allowEmpty' )) {
1563 $this->recurrenceid = array( 'value' => null, 'params' => null );
1569 $this->recurrenceid = iCal_UtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
1572 /*********************************************************************************/
1574 * Property Name: RELATED-TO
1577 * creates formatted output for calendar component property related-to
1579 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1580 * @since 2.4.8 - 2008-10-23
1583 function createRelatedTo() {
1584 if( empty( $this->relatedto )) return FALSE;
1586 foreach( $this->relatedto as $relation ) {
1587 if( empty( $relation['value'] )) {
1588 if( $this->getConfig( 'allowEmpty' )) $output.= $this->_createElement( 'RELATED-TO', $this->_createParams( $relation['params'] ));
1591 $attributes = $this->_createParams( $relation['params'] );
1592 $content = ( 'xcal' != $this->format ) ? '<' : '';
1593 $content .= $this->_strrep( $relation['value'] );
1594 $content .= ( 'xcal' != $this->format ) ? '>' : '';
1595 $output .= $this->_createElement( 'RELATED-TO', $attributes, $content );
1600 * set calendar component property related-to
1602 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1603 * @since 2.5.1 - 2008-11-07
1604 * @param float $relid
1605 * @param array $params, optional
1606 * @param index $index, optional
1609 function setRelatedTo( $value, $params=FALSE, $index=FALSE ) {
1610 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1611 if(( '<' == substr( $value, 0, 1 )) && ( '>' == substr( $value, -1 )))
1612 $value = substr( $value, 1, ( strlen( $value ) - 2 ));
1613 iCal_UtilityFunctions::_existRem( $params, 'RELTYPE', 'PARENT', TRUE ); // remove default
1614 iCal_UtilityFunctions::_setMval( $this->relatedto, $value, $params, FALSE, $index );
1617 /*********************************************************************************/
1619 * Property Name: REPEAT
1622 * creates formatted output for calendar component property repeat
1624 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1625 * @since 2.9.3 - 2011-05-14
1628 function createRepeat() {
1629 if( !isset( $this->repeat ) || ( empty( $this->repeat ) && !is_numeric( $this->repeat ))) return FALSE;
1630 if( !isset( $this->repeat['value']) || ( empty( $this->repeat['value'] ) && !is_numeric( $this->repeat['value'] )))
1631 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'REPEAT' ) : FALSE;
1632 $attributes = $this->_createParams( $this->repeat['params'] );
1633 return $this->_createElement( 'REPEAT', $attributes, $this->repeat['value'] );
1636 * set calendar component property transp
1638 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1639 * @since 2.9.3 - 2011-05-14
1640 * @param string $value
1641 * @param array $params optional
1644 function setRepeat( $value, $params=FALSE ) {
1645 if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1646 $this->repeat = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1649 /*********************************************************************************/
1651 * Property Name: REQUEST-STATUS
1654 * creates formatted output for calendar component property request-status
1655 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1656 * @since 2.4.8 - 2008-10-23
1659 function createRequestStatus() {
1660 if( empty( $this->requeststatus )) return FALSE;
1662 foreach( $this->requeststatus as $rstat ) {
1663 if( empty( $rstat['value']['statcode'] )) {
1664 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'REQUEST-STATUS' );
1667 $attributes = $this->_createParams( $rstat['params'], array( 'LANGUAGE' ));
1668 $content = number_format( (float) $rstat['value']['statcode'], 2, '.', '');
1669 $content .= ';'.$this->_strrep( $rstat['value']['text'] );
1670 if( isset( $rstat['value']['extdata'] ))
1671 $content .= ';'.$this->_strrep( $rstat['value']['extdata'] );
1672 $output .= $this->_createElement( 'REQUEST-STATUS', $attributes, $content );
1677 * set calendar component property request-status
1679 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1680 * @since 2.5.1 - 2008-11-05
1681 * @param float $statcode
1682 * @param string $text
1683 * @param string $extdata, optional
1684 * @param array $params, optional
1685 * @param integer $index, optional
1688 function setRequestStatus( $statcode, $text, $extdata=FALSE, $params=FALSE, $index=FALSE ) {
1689 if( empty( $statcode ) || empty( $text )) if( $this->getConfig( 'allowEmpty' )) $statcode = $text = null; else return FALSE;
1690 $input = array( 'statcode' => $statcode, 'text' => $text );
1692 $input['extdata'] = $extdata;
1693 iCal_UtilityFunctions::_setMval( $this->requeststatus, $input, $params, FALSE, $index );
1696 /*********************************************************************************/
1698 * Property Name: RESOURCES
1701 * creates formatted output for calendar component property resources
1703 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1704 * @since 2.4.8 - 2008-10-23
1707 function createResources() {
1708 if( empty( $this->resources )) return FALSE;
1710 foreach( $this->resources as $resource ) {
1711 if( empty( $resource['value'] )) {
1712 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RESOURCES' );
1715 $attributes = $this->_createParams( $resource['params'], array( 'ALTREP', 'LANGUAGE' ));
1716 if( is_array( $resource['value'] )) {
1717 foreach( $resource['value'] as $rix => $resourcePart )
1718 $resource['value'][$rix] = $this->_strrep( $resourcePart );
1719 $content = implode( ',', $resource['value'] );
1722 $content = $this->_strrep( $resource['value'] );
1723 $output .= $this->_createElement( 'RESOURCES', $attributes, $content );
1728 * set calendar component property recources
1730 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1731 * @since 2.5.1 - 2008-11-05
1732 * @param mixed $value
1733 * @param array $params, optional
1734 * @param integer $index, optional
1737 function setResources( $value, $params=FALSE, $index=FALSE ) {
1738 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1739 iCal_UtilityFunctions::_setMval( $this->resources, $value, $params, FALSE, $index );
1742 /*********************************************************************************/
1744 * Property Name: RRULE
1747 * creates formatted output for calendar component property rrule
1749 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1750 * @since 2.4.8 - 2008-10-21
1753 function createRrule() {
1754 if( empty( $this->rrule )) return FALSE;
1755 return $this->_format_recur( 'RRULE', $this->rrule );
1758 * set calendar component property rrule
1760 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1761 * @since 2.5.1 - 2008-11-05
1762 * @param array $rruleset
1763 * @param array $params, optional
1764 * @param integer $index, optional
1767 function setRrule( $rruleset, $params=FALSE, $index=FALSE ) {
1768 if( empty( $rruleset )) if( $this->getConfig( 'allowEmpty' )) $rruleset = null; else return FALSE;
1769 iCal_UtilityFunctions::_setMval( $this->rrule, iCal_UtilityFunctions::_setRexrule( $rruleset ), $params, FALSE, $index );
1772 /*********************************************************************************/
1774 * Property Name: SEQUENCE
1777 * creates formatted output for calendar component property sequence
1778 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1779 * @since 2.9.3 - 2011-05-14
1782 function createSequence() {
1783 if( !isset( $this->sequence ) || ( empty( $this->sequence ) && !is_numeric( $this->sequence ))) return FALSE;
1784 if(( !isset($this->sequence['value'] ) || ( empty( $this->sequence['value'] ) && !is_numeric( $this->sequence['value'] ))) &&
1785 ( '0' != $this->sequence['value'] ))
1786 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SEQUENCE' ) : FALSE;
1787 $attributes = $this->_createParams( $this->sequence['params'] );
1788 return $this->_createElement( 'SEQUENCE', $attributes, $this->sequence['value'] );
1791 * set calendar component property sequence
1792 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1793 * @since 2.10.8 - 2011-09-19
1794 * @param int $value optional
1795 * @param array $params optional
1798 function setSequence( $value=FALSE, $params=FALSE ) {
1799 if(( empty( $value ) && !is_numeric( $value )) && ( '0' != $value ))
1800 $value = ( isset( $this->sequence['value'] ) && ( -1 < $this->sequence['value'] )) ? $this->sequence['value'] + 1 : '0';
1801 $this->sequence = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1804 /*********************************************************************************/
1806 * Property Name: STATUS
1809 * creates formatted output for calendar component property status
1811 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1812 * @since 2.4.8 - 2008-10-21
1815 function createStatus() {
1816 if( empty( $this->status )) return FALSE;
1817 if( empty( $this->status['value'] ))
1818 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'STATUS' ) : FALSE;
1819 $attributes = $this->_createParams( $this->status['params'] );
1820 return $this->_createElement( 'STATUS', $attributes, $this->status['value'] );
1823 * set calendar component property status
1825 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1826 * @since 2.4.8 - 2008-11-04
1827 * @param string $value
1828 * @param array $params optional
1831 function setStatus( $value, $params=FALSE ) {
1832 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1833 $this->status = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1836 /*********************************************************************************/
1838 * Property Name: SUMMARY
1841 * creates formatted output for calendar component property summary
1843 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1844 * @since 2.4.8 - 2008-10-21
1847 function createSummary() {
1848 if( empty( $this->summary )) return FALSE;
1849 if( empty( $this->summary['value'] ))
1850 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SUMMARY' ) : FALSE;
1851 $attributes = $this->_createParams( $this->summary['params'], array( 'ALTREP', 'LANGUAGE' ));
1852 $content = $this->_strrep( $this->summary['value'] );
1853 return $this->_createElement( 'SUMMARY', $attributes, $content );
1856 * set calendar component property summary
1858 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1859 * @since 2.4.8 - 2008-11-04
1860 * @param string $value
1861 * @param string $params optional
1864 function setSummary( $value, $params=FALSE ) {
1865 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1866 $this->summary = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1869 /*********************************************************************************/
1871 * Property Name: TRANSP
1874 * creates formatted output for calendar component property transp
1876 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1877 * @since 2.4.8 - 2008-10-21
1880 function createTransp() {
1881 if( empty( $this->transp )) return FALSE;
1882 if( empty( $this->transp['value'] ))
1883 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRANSP' ) : FALSE;
1884 $attributes = $this->_createParams( $this->transp['params'] );
1885 return $this->_createElement( 'TRANSP', $attributes, $this->transp['value'] );
1888 * set calendar component property transp
1890 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1891 * @since 2.4.8 - 2008-11-04
1892 * @param string $value
1893 * @param string $params optional
1896 function setTransp( $value, $params=FALSE ) {
1897 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
1898 $this->transp = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
1901 /*********************************************************************************/
1903 * Property Name: TRIGGER
1906 * creates formatted output for calendar component property trigger
1908 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1909 * @since 2.4.16 - 2008-10-21
1912 function createTrigger() {
1913 if( empty( $this->trigger )) return FALSE;
1914 if( empty( $this->trigger['value'] ))
1915 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRIGGER' ) : FALSE;
1916 $content = $attributes = null;
1917 if( isset( $this->trigger['value']['year'] ) &&
1918 isset( $this->trigger['value']['month'] ) &&
1919 isset( $this->trigger['value']['day'] ))
1920 $content .= iCal_UtilityFunctions::_format_date_time( $this->trigger['value'] );
1922 if( TRUE !== $this->trigger['value']['relatedStart'] )
1923 $attributes .= $this->intAttrDelimiter.'RELATED=END';
1924 if( $this->trigger['value']['before'] )
1926 $content .= iCal_UtilityFunctions::_format_duration( $this->trigger['value'] );
1928 $attributes .= $this->_createParams( $this->trigger['params'] );
1929 return $this->_createElement( 'TRIGGER', $attributes, $content );
1932 * set calendar component property trigger
1934 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1935 * @since 2.9.9 - 2011-06-17
1936 * @param mixed $year
1937 * @param mixed $month optional
1938 * @param int $day optional
1939 * @param int $week optional
1940 * @param int $hour optional
1941 * @param int $min optional
1942 * @param int $sec optional
1943 * @param bool $relatedStart optional
1944 * @param bool $before optional
1945 * @param array $params optional
1948 function setTrigger( $year, $month=null, $day=null, $week=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $relatedStart=TRUE, $before=TRUE, $params=FALSE ) {
1949 if( empty( $year ) && empty( $month ) && empty( $day ) && empty( $week ) && empty( $hour ) && empty( $min ) && empty( $sec ))
1950 if( $this->getConfig( 'allowEmpty' )) {
1951 $this->trigger = array( 'value' => null, 'params' => iCal_UtilityFunctions::_setParams( $params ) );
1956 if( iCal_UtilityFunctions::_isArrayTimestampDate( $year )) { // timestamp
1957 $params = iCal_UtilityFunctions::_setParams( $month );
1958 $date = iCal_UtilityFunctions::_timestamp2date( $year, 7 );
1959 foreach( $date as $k => $v )
1962 elseif( is_array( $year ) && ( is_array( $month ) || empty( $month ))) {
1963 $params = iCal_UtilityFunctions::_setParams( $month );
1964 if(!(array_key_exists( 'year', $year ) && // exclude date-time
1965 array_key_exists( 'month', $year ) &&
1966 array_key_exists( 'day', $year ))) { // when this must be a duration
1967 if( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] )))
1968 $relatedStart = FALSE;
1970 $relatedStart = ( array_key_exists( 'relatedStart', $year ) && ( TRUE !== $year['relatedStart'] )) ? FALSE : TRUE;
1971 $before = ( array_key_exists( 'before', $year ) && ( TRUE !== $year['before'] )) ? FALSE : TRUE;
1973 $SSYY = ( array_key_exists( 'year', $year )) ? $year['year'] : null;
1974 $month = ( array_key_exists( 'month', $year )) ? $year['month'] : null;
1975 $day = ( array_key_exists( 'day', $year )) ? $year['day'] : null;
1976 $week = ( array_key_exists( 'week', $year )) ? $year['week'] : null;
1977 $hour = ( array_key_exists( 'hour', $year )) ? $year['hour'] : 0; //null;
1978 $min = ( array_key_exists( 'min', $year )) ? $year['min'] : 0; //null;
1979 $sec = ( array_key_exists( 'sec', $year )) ? $year['sec'] : 0; //null;
1982 elseif(is_string( $year ) && ( is_array( $month ) || empty( $month ))) { // duration or date in a string
1983 $params = iCal_UtilityFunctions::_setParams( $month );
1984 if( in_array( $year[0], array( 'P', '+', '-' ))) { // duration
1985 $relatedStart = ( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] ))) ? FALSE : TRUE;
1986 $before = ( '-' == $year[0] ) ? TRUE : FALSE;
1987 if( 'P' != $year[0] )
1988 $year = substr( $year, 1 );
1989 $date = iCal_UtilityFunctions::_duration_string( $year);
1992 $date = iCal_UtilityFunctions::_date_time_string( $year, 7 );
1993 unset( $year, $month, $day );
1997 foreach( $date as $k => $v )
2000 else // single values in function input parameters
2001 $params = iCal_UtilityFunctions::_setParams( $params );
2002 if( !empty( $year ) && !empty( $month ) && !empty( $day )) { // date
2003 $params['VALUE'] = 'DATE-TIME';
2004 $hour = ( $hour ) ? $hour : 0;
2005 $min = ( $min ) ? $min : 0;
2006 $sec = ( $sec ) ? $sec : 0;
2007 $this->trigger = array( 'params' => $params );
2008 $this->trigger['value'] = array( 'year' => $year
2017 elseif(( empty( $year ) && empty( $month )) && // duration
2018 (( !empty( $week ) || ( 0 == $week )) ||
2019 ( !empty( $day ) || ( 0 == $day )) ||
2020 ( !empty( $hour ) || ( 0 == $hour )) ||
2021 ( !empty( $min ) || ( 0 == $min )) ||
2022 ( !empty( $sec ) || ( 0 == $sec )))) {
2023 unset( $params['RELATED'] ); // set at output creation (END only)
2024 unset( $params['VALUE'] ); // 'DURATION' default
2025 $this->trigger = array( 'params' => $params );
2026 $this->trigger['value'] = array();
2027 if( !empty( $week )) $this->trigger['value']['week'] = $week;
2028 if( !empty( $day )) $this->trigger['value']['day'] = $day;
2029 if( !empty( $hour )) $this->trigger['value']['hour'] = $hour;
2030 if( !empty( $min )) $this->trigger['value']['min'] = $min;
2031 if( !empty( $sec )) $this->trigger['value']['sec'] = $sec;
2032 if( empty( $this->trigger['value'] )) {
2033 $this->trigger['value']['sec'] = 0;
2036 $relatedStart = ( FALSE !== $relatedStart ) ? TRUE : FALSE;
2037 $before = ( FALSE !== $before ) ? TRUE : FALSE;
2038 $this->trigger['value']['relatedStart'] = $relatedStart;
2039 $this->trigger['value']['before'] = $before;
2044 /*********************************************************************************/
2046 * Property Name: TZID
2049 * creates formatted output for calendar component property tzid
2051 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2052 * @since 2.4.8 - 2008-10-21
2055 function createTzid() {
2056 if( empty( $this->tzid )) return FALSE;
2057 if( empty( $this->tzid['value'] ))
2058 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZID' ) : FALSE;
2059 $attributes = $this->_createParams( $this->tzid['params'] );
2060 return $this->_createElement( 'TZID', $attributes, $this->_strrep( $this->tzid['value'] ));
2063 * set calendar component property tzid
2065 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2066 * @since 2.4.8 - 2008-11-04
2067 * @param string $value
2068 * @param array $params optional
2071 function setTzid( $value, $params=FALSE ) {
2072 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2073 $this->tzid = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
2076 /*********************************************************************************/
2079 * Property Name: TZNAME
2082 * creates formatted output for calendar component property tzname
2084 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2085 * @since 2.4.8 - 2008-10-21
2088 function createTzname() {
2089 if( empty( $this->tzname )) return FALSE;
2091 foreach( $this->tzname as $theName ) {
2092 if( !empty( $theName['value'] )) {
2093 $attributes = $this->_createParams( $theName['params'], array( 'LANGUAGE' ));
2094 $output .= $this->_createElement( 'TZNAME', $attributes, $this->_strrep( $theName['value'] ));
2096 elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'TZNAME' );
2101 * set calendar component property tzname
2103 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2104 * @since 2.5.1 - 2008-11-05
2105 * @param string $value
2106 * @param string $params, optional
2107 * @param integer $index, optional
2110 function setTzname( $value, $params=FALSE, $index=FALSE ) {
2111 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2112 iCal_UtilityFunctions::_setMval( $this->tzname, $value, $params, FALSE, $index );
2115 /*********************************************************************************/
2117 * Property Name: TZOFFSETFROM
2120 * creates formatted output for calendar component property tzoffsetfrom
2122 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2123 * @since 2.4.8 - 2008-10-21
2126 function createTzoffsetfrom() {
2127 if( empty( $this->tzoffsetfrom )) return FALSE;
2128 if( empty( $this->tzoffsetfrom['value'] ))
2129 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETFROM' ) : FALSE;
2130 $attributes = $this->_createParams( $this->tzoffsetfrom['params'] );
2131 return $this->_createElement( 'TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value'] );
2134 * set calendar component property tzoffsetfrom
2136 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2137 * @since 2.4.8 - 2008-11-04
2138 * @param string $value
2139 * @param string $params optional
2142 function setTzoffsetfrom( $value, $params=FALSE ) {
2143 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2144 $this->tzoffsetfrom = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
2147 /*********************************************************************************/
2149 * Property Name: TZOFFSETTO
2152 * creates formatted output for calendar component property tzoffsetto
2154 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2155 * @since 2.4.8 - 2008-10-21
2158 function createTzoffsetto() {
2159 if( empty( $this->tzoffsetto )) return FALSE;
2160 if( empty( $this->tzoffsetto['value'] ))
2161 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETTO' ) : FALSE;
2162 $attributes = $this->_createParams( $this->tzoffsetto['params'] );
2163 return $this->_createElement( 'TZOFFSETTO', $attributes, $this->tzoffsetto['value'] );
2166 * set calendar component property tzoffsetto
2168 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2169 * @since 2.4.8 - 2008-11-04
2170 * @param string $value
2171 * @param string $params optional
2174 function setTzoffsetto( $value, $params=FALSE ) {
2175 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2176 $this->tzoffsetto = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
2179 /*********************************************************************************/
2181 * Property Name: TZURL
2184 * creates formatted output for calendar component property tzurl
2186 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2187 * @since 2.4.8 - 2008-10-21
2190 function createTzurl() {
2191 if( empty( $this->tzurl )) return FALSE;
2192 if( empty( $this->tzurl['value'] ))
2193 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZURL' ) : FALSE;
2194 $attributes = $this->_createParams( $this->tzurl['params'] );
2195 return $this->_createElement( 'TZURL', $attributes, $this->tzurl['value'] );
2198 * set calendar component property tzurl
2200 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2201 * @since 2.4.8 - 2008-11-04
2202 * @param string $value
2203 * @param string $params optional
2206 function setTzurl( $value, $params=FALSE ) {
2207 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2208 $this->tzurl = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
2211 /*********************************************************************************/
2213 * Property Name: UID
2216 * creates formatted output for calendar component property uid
2218 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2219 * @since 0.9.7 - 2006-11-20
2222 function createUid() {
2223 if( 0 >= count( $this->uid ))
2225 $attributes = $this->_createParams( $this->uid['params'] );
2226 return $this->_createElement( 'UID', $attributes, $this->uid['value'] );
2229 * create an unique id for this calendar component object instance
2231 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2232 * @since 2.2.7 - 2007-09-04
2235 function _makeUid() {
2236 $date = date('Ymd\THisT');
2237 $unique = substr(microtime(), 2, 4);
2238 $base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890';
2240 $end = strlen( $base ) - 1;
2243 for( $p = 0; $p < $length; $p++ )
2244 $unique .= $base{mt_rand( $start, $end )};
2245 $this->uid = array( 'params' => null );
2246 $this->uid['value'] = $date.'-'.$unique.'@'.$this->getConfig( 'unique_id' );
2249 * set calendar component property uid
2251 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2252 * @since 2.4.8 - 2008-11-04
2253 * @param string $value
2254 * @param string $params optional
2257 function setUid( $value, $params=FALSE ) {
2258 if( empty( $value )) return FALSE; // no allowEmpty check here !!!!
2259 $this->uid = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
2262 /*********************************************************************************/
2264 * Property Name: URL
2267 * creates formatted output for calendar component property url
2269 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2270 * @since 2.4.8 - 2008-10-21
2273 function createUrl() {
2274 if( empty( $this->url )) return FALSE;
2275 if( empty( $this->url['value'] ))
2276 return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'URL' ) : FALSE;
2277 $attributes = $this->_createParams( $this->url['params'] );
2278 return $this->_createElement( 'URL', $attributes, $this->url['value'] );
2281 * set calendar component property url
2283 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2284 * @since 2.4.8 - 2008-11-04
2285 * @param string $value
2286 * @param string $params optional
2289 function setUrl( $value, $params=FALSE ) {
2290 if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2291 $this->url = array( 'value' => $value, 'params' => iCal_UtilityFunctions::_setParams( $params ));
2294 /*********************************************************************************/
2296 * Property Name: x-prop
2299 * creates formatted output for calendar component property x-prop
2301 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2302 * @since 2.9.3 - 2011-05-14
2305 function createXprop() {
2306 if( empty( $this->xprop )) return FALSE;
2308 foreach( $this->xprop as $label => $xpropPart ) {
2309 if( !isset($xpropPart['value']) || ( empty( $xpropPart['value'] ) && !is_numeric( $xpropPart['value'] ))) {
2310 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $label );
2313 $attributes = $this->_createParams( $xpropPart['params'], array( 'LANGUAGE' ));
2314 if( is_array( $xpropPart['value'] )) {
2315 foreach( $xpropPart['value'] as $pix => $theXpart )
2316 $xpropPart['value'][$pix] = $this->_strrep( $theXpart );
2317 $xpropPart['value'] = implode( ',', $xpropPart['value'] );
2320 $xpropPart['value'] = $this->_strrep( $xpropPart['value'] );
2321 $output .= $this->_createElement( $label, $attributes, $xpropPart['value'] );
2326 * set calendar component property x-prop
2328 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2329 * @since 2.9.3 - 2011-05-14
2330 * @param string $label
2331 * @param mixed $value
2332 * @param array $params optional
2335 function setXprop( $label, $value, $params=FALSE ) {
2336 if( empty( $label )) return;
2337 if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = null; else return FALSE;
2338 $xprop = array( 'value' => $value );
2339 $xprop['params'] = iCal_UtilityFunctions::_setParams( $params );
2340 if( !is_array( $this->xprop )) $this->xprop = array();
2341 $this->xprop[strtoupper( $label )] = $xprop;
2344 /*********************************************************************************/
2345 /*********************************************************************************/
2347 * create element format parts
2349 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2350 * @since 2.0.6 - 2006-06-20
2353 function _createFormat() {
2355 switch( $this->format ) {
2357 $objectname = ( isset( $this->timezonetype )) ?
2358 strtolower( $this->timezonetype ) : strtolower( $this->objName );
2359 $this->componentStart1 = $this->elementStart1 = '<';
2360 $this->componentStart2 = $this->elementStart2 = '>';
2361 $this->componentEnd1 = $this->elementEnd1 = '</';
2362 $this->componentEnd2 = $this->elementEnd2 = '>'.$this->nl;
2363 $this->intAttrDelimiter = '<!-- -->';
2364 $this->attributeDelimiter = $this->nl;
2365 $this->valueInit = null;
2368 $objectname = ( isset( $this->timezonetype )) ?
2369 strtoupper( $this->timezonetype ) : strtoupper( $this->objName );
2370 $this->componentStart1 = 'BEGIN:';
2371 $this->componentStart2 = null;
2372 $this->componentEnd1 = 'END:';
2373 $this->componentEnd2 = $this->nl;
2374 $this->elementStart1 = null;
2375 $this->elementStart2 = null;
2376 $this->elementEnd1 = null;
2377 $this->elementEnd2 = $this->nl;
2378 $this->intAttrDelimiter = '<!-- -->';
2379 $this->attributeDelimiter = ';';
2380 $this->valueInit = ':';
2386 * creates formatted output for calendar component property
2388 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2389 * @since 2.6.22 - 2010-12-06
2390 * @param string $label property name
2391 * @param string $attributes property attributes
2392 * @param string $content property content (optional)
2395 function _createElement( $label, $attributes=null, $content=FALSE ) {
2396 switch( $this->format ) {
2398 $label = strtolower( $label );
2401 $label = strtoupper( $label );
2404 $output = $this->elementStart1.$label;
2405 $categoriesAttrLang = null;
2406 $attachInlineBinary = FALSE;
2407 $attachfmttype = null;
2408 if( !empty( $attributes )) {
2409 $attributes = trim( $attributes );
2410 if ( 'xcal' == $this->format) {
2411 $attributes2 = explode( $this->intAttrDelimiter, $attributes );
2413 foreach( $attributes2 as $attribute ) {
2414 $attrKVarr = explode( '=', $attribute );
2415 if( empty( $attrKVarr[0] ))
2417 if( !isset( $attrKVarr[1] )) {
2418 $attrValue = $attrKVarr[0];
2421 elseif( 2 == count( $attrKVarr)) {
2422 $attrKey = strtolower( $attrKVarr[0] );
2423 $attrValue = $attrKVarr[1];
2426 $attrKey = strtolower( $attrKVarr[0] );
2427 unset( $attrKVarr[0] );
2428 $attrValue = implode( '=', $attrKVarr );
2430 if(( 'attach' == $label ) && ( in_array( $attrKey, array( 'fmttype', 'encoding', 'value' )))) {
2431 $attachInlineBinary = TRUE;
2432 if( 'fmttype' == $attrKey )
2433 $attachfmttype = $attrKey.'='.$attrValue;
2436 elseif(( 'categories' == $label ) && ( 'language' == $attrKey ))
2437 $categoriesAttrLang = $attrKey.'='.$attrValue;
2439 $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
2440 $attributes .= ( !empty( $attrKey )) ? $attrKey.'=' : null;
2441 if(( '"' == substr( $attrValue, 0, 1 )) && ( '"' == substr( $attrValue, -1 ))) {
2442 $attrValue = substr( $attrValue, 1, ( strlen( $attrValue ) - 2 ));
2443 $attrValue = str_replace( '"', '', $attrValue );
2445 $attributes .= '"'.htmlspecialchars( $attrValue ).'"';
2450 $attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes );
2453 if(((( 'attach' == $label ) && !$attachInlineBinary ) ||
2454 ( in_array( $label, array( 'tzurl', 'url' )))) && ( 'xcal' == $this->format)) {
2455 $pos = strrpos($content, "/");
2456 $docname = ( $pos !== false) ? substr( $content, (1 - strlen( $content ) + $pos )) : $content;
2457 $this->xcaldecl[] = array( 'xmldecl' => 'ENTITY'
2460 , 'external' => $content
2462 , 'type2' => 'BINERY' );
2463 $attributes .= ( empty( $attributes )) ? ' ' : $this->attributeDelimiter.' ';
2464 $attributes .= 'uri="'.$docname.'"';
2466 if( 'attach' == $label ) {
2467 $attributes = str_replace( $this->attributeDelimiter, $this->intAttrDelimiter, $attributes );
2468 $content = $this->_createElement( 'extref', $attributes, null );
2472 elseif(( 'attach' == $label ) && $attachInlineBinary && ( 'xcal' == $this->format)) {
2473 $content = $this->nl.$this->_createElement( 'b64bin', $attachfmttype, $content ); // max one attribute
2475 $output .= $attributes;
2476 if( !$content && ( '0' != $content )) {
2477 switch( $this->format ) {
2480 $output .= $this->elementStart2;
2484 $output .= $this->elementStart2.$this->valueInit;
2485 return $this->_size75( $output );
2489 $output .= $this->elementStart2;
2490 $output .= $this->valueInit.$content;
2491 switch( $this->format ) {
2493 return $output.$this->elementEnd1.$label.$this->elementEnd2;
2496 return $this->_size75( $output );
2501 * creates formatted output for calendar component property parameters
2503 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2504 * @since 2.6.33 - 2010-12-18
2505 * @param array $params optional
2506 * @param array $ctrKeys optional
2509 function _createParams( $params=array(), $ctrKeys=array() ) {
2510 if( !is_array( $params ) || empty( $params ))
2512 $attrLANG = $attr1 = $attr2 = $lang = null;
2513 $CNattrKey = ( in_array( 'CN', $ctrKeys )) ? TRUE : FALSE ;
2514 $LANGattrKey = ( in_array( 'LANGUAGE', $ctrKeys )) ? TRUE : FALSE ;
2515 $CNattrExist = $LANGattrExist = FALSE;
2517 foreach( $params as $paramKey => $paramValue ) {
2518 if( ctype_digit( (string) $paramKey )) {
2519 $xparams[] = $paramValue;
2522 $paramKey = strtoupper( $paramKey );
2523 if( !in_array( $paramKey, array( 'ALTREP', 'CN', 'DIR', 'ENCODING', 'FMTTYPE', 'LANGUAGE', 'RANGE', 'RELTYPE', 'SENT-BY', 'TZID', 'VALUE' )))
2524 $xparams[$paramKey] = $paramValue;
2526 $params[$paramKey] = $paramValue;
2528 ksort( $xparams, SORT_STRING );
2529 foreach( $xparams as $paramKey => $paramValue ) {
2530 if( ctype_digit( (string) $paramKey ))
2531 $attr2 .= $this->intAttrDelimiter.$paramValue;
2533 $attr2 .= $this->intAttrDelimiter."$paramKey=$paramValue";
2535 if( isset( $params['FMTTYPE'] ) && !in_array( 'FMTTYPE', $ctrKeys )) {
2536 $attr1 .= $this->intAttrDelimiter.'FMTTYPE='.$params['FMTTYPE'].$attr2;
2539 if( isset( $params['ENCODING'] ) && !in_array( 'ENCODING', $ctrKeys )) {
2540 if( !empty( $attr2 )) {
2544 $attr1 .= $this->intAttrDelimiter.'ENCODING='.$params['ENCODING'];
2546 if( isset( $params['VALUE'] ) && !in_array( 'VALUE', $ctrKeys ))
2547 $attr1 .= $this->intAttrDelimiter.'VALUE='.$params['VALUE'];
2548 if( isset( $params['TZID'] ) && !in_array( 'TZID', $ctrKeys ))
2549 $attr1 .= $this->intAttrDelimiter.'TZID='.$params['TZID'];
2550 if( isset( $params['RANGE'] ) && !in_array( 'RANGE', $ctrKeys ))
2551 $attr1 .= $this->intAttrDelimiter.'RANGE='.$params['RANGE'];
2552 if( isset( $params['RELTYPE'] ) && !in_array( 'RELTYPE', $ctrKeys ))
2553 $attr1 .= $this->intAttrDelimiter.'RELTYPE='.$params['RELTYPE'];
2554 if( isset( $params['CN'] ) && $CNattrKey ) {
2555 $attr1 = $this->intAttrDelimiter.'CN="'.$params['CN'].'"';
2556 $CNattrExist = TRUE;
2558 if( isset( $params['DIR'] ) && in_array( 'DIR', $ctrKeys ))
2559 $attr1 .= $this->intAttrDelimiter.'DIR="'.$params['DIR'].'"';
2560 if( isset( $params['SENT-BY'] ) && in_array( 'SENT-BY', $ctrKeys ))
2561 $attr1 .= $this->intAttrDelimiter.'SENT-BY="'.$params['SENT-BY'].'"';
2562 if( isset( $params['ALTREP'] ) && in_array( 'ALTREP', $ctrKeys ))
2563 $attr1 .= $this->intAttrDelimiter.'ALTREP="'.$params['ALTREP'].'"';
2564 if( isset( $params['LANGUAGE'] ) && $LANGattrKey ) {
2565 $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$params['LANGUAGE'];
2566 $LANGattrExist = TRUE;
2568 if( !$LANGattrExist ) {
2569 $lang = $this->getConfig( 'language' );
2570 if(( $CNattrExist || $LANGattrKey ) && $lang )
2571 $attrLANG .= $this->intAttrDelimiter.'LANGUAGE='.$lang;
2573 return $attr1.$attrLANG.$attr2;
2576 * creates formatted output for calendar component property data value type recur
2578 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2579 * @since 2.4.8 - 2008-10-22
2580 * @param array $recurlabel
2581 * @param array $recurdata
2584 function _format_recur( $recurlabel, $recurdata ) {
2586 foreach( $recurdata as $therule ) {
2587 if( empty( $therule['value'] )) {
2588 if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $recurlabel );
2591 $attributes = ( isset( $therule['params'] )) ? $this->_createParams( $therule['params'] ) : null;
2592 $content1 = $content2 = null;
2593 foreach( $therule['value'] as $rulelabel => $rulevalue ) {
2594 switch( $rulelabel ) {
2596 $content1 .= "FREQ=$rulevalue";
2600 $content2 .= ";UNTIL=";
2601 $content2 .= iCal_UtilityFunctions::_format_date_time( $rulevalue );
2607 $content2 .= ";$rulelabel=$rulevalue";
2618 $content2 .= ";$rulelabel=";
2619 if( is_array( $rulevalue )) {
2620 foreach( $rulevalue as $vix => $valuePart ) {
2621 $content2 .= ( $vix ) ? ',' : null;
2622 $content2 .= $valuePart;
2626 $content2 .= $rulevalue;
2630 $content2 .= ";$rulelabel=";
2632 foreach( $rulevalue as $vix => $valuePart ) {
2633 $content21 = $content22 = null;
2634 if( is_array( $valuePart )) {
2635 $content2 .= ( $bydaycnt ) ? ',' : null;
2636 foreach( $valuePart as $vix2 => $valuePart2 ) {
2637 if( 'DAY' != strtoupper( $vix2 ))
2638 $content21 .= $valuePart2;
2640 $content22 .= $valuePart2;
2642 $content2 .= $content21.$content22;
2646 $content2 .= ( $bydaycnt ) ? ',' : null;
2647 if( 'DAY' != strtoupper( $vix ))
2648 $content21 .= $valuePart;
2650 $content22 .= $valuePart;
2653 $content2 .= $content21.$content22;
2659 $content2 .= ";$rulelabel=$rulevalue";
2664 $output .= $this->_createElement( $recurlabel, $attributes, $content1.$content2 );
2669 * check if property not exists within component
2671 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2672 * @since 2.5.1 - 2008-10-15
2673 * @param string $propName
2676 function _notExistProp( $propName ) {
2677 if( empty( $propName )) return FALSE; // when deleting x-prop, an empty propName may be used=allowed
2678 $propName = strtolower( $propName );
2679 if( 'last-modified' == $propName ) { if( !isset( $this->lastmodified )) return TRUE; }
2680 elseif( 'percent-complete' == $propName ) { if( !isset( $this->percentcomplete )) return TRUE; }
2681 elseif( 'recurrence-id' == $propName ) { if( !isset( $this->recurrenceid )) return TRUE; }
2682 elseif( 'related-to' == $propName ) { if( !isset( $this->relatedto )) return TRUE; }
2683 elseif( 'request-status' == $propName ) { if( !isset( $this->requeststatus )) return TRUE; }
2684 elseif(( 'x-' != substr($propName,0,2)) && !isset( $this->$propName )) return TRUE;
2687 /*********************************************************************************/
2688 /*********************************************************************************/
2690 * get general component config variables or info about subcomponents
2692 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2693 * @since 2.9.6 - 2011-05-14
2694 * @param mixed $config
2697 function getConfig( $config = FALSE) {
2700 $return['ALLOWEMPTY'] = $this->getConfig( 'ALLOWEMPTY' );
2701 $return['FORMAT'] = $this->getConfig( 'FORMAT' );
2702 if( FALSE !== ( $lang = $this->getConfig( 'LANGUAGE' )))
2703 $return['LANGUAGE'] = $lang;
2704 $return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' );
2705 $return['TZTD'] = $this->getConfig( 'TZID' );
2706 $return['UNIQUE_ID'] = $this->getConfig( 'UNIQUE_ID' );
2709 switch( strtoupper( $config )) {
2711 return $this->allowEmpty;
2714 unset( $this->compix );
2716 if( isset( $this->components )) {
2717 foreach( $this->components as $cix => $component ) {
2718 if( empty( $component )) continue;
2719 $info[$cix]['ordno'] = $cix + 1;
2720 $info[$cix]['type'] = $component->objName;
2721 $info[$cix]['uid'] = $component->getProperty( 'uid' );
2722 $info[$cix]['props'] = $component->getConfig( 'propinfo' );
2723 $info[$cix]['sub'] = $component->getConfig( 'compsinfo' );
2729 return $this->format;
2732 // get language for calendar component as defined in [RFC 1766]
2733 return $this->language;
2741 if( !in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
2742 if( empty( $this->uid['value'] )) $this->_makeuid();
2745 if( !empty( $this->dtstamp )) $output['DTSTAMP'] = 1;
2746 if( !empty( $this->summary )) $output['SUMMARY'] = 1;
2747 if( !empty( $this->description )) $output['DESCRIPTION'] = count( $this->description );
2748 if( !empty( $this->dtstart )) $output['DTSTART'] = 1;
2749 if( !empty( $this->dtend )) $output['DTEND'] = 1;
2750 if( !empty( $this->due )) $output['DUE'] = 1;
2751 if( !empty( $this->duration )) $output['DURATION'] = 1;
2752 if( !empty( $this->rrule )) $output['RRULE'] = count( $this->rrule );
2753 if( !empty( $this->rdate )) $output['RDATE'] = count( $this->rdate );
2754 if( !empty( $this->exdate )) $output['EXDATE'] = count( $this->exdate );
2755 if( !empty( $this->exrule )) $output['EXRULE'] = count( $this->exrule );
2756 if( !empty( $this->action )) $output['ACTION'] = 1;
2757 if( !empty( $this->attach )) $output['ATTACH'] = count( $this->attach );
2758 if( !empty( $this->attendee )) $output['ATTENDEE'] = count( $this->attendee );
2759 if( !empty( $this->categories )) $output['CATEGORIES'] = count( $this->categories );
2760 if( !empty( $this->class )) $output['CLASS'] = 1;
2761 if( !empty( $this->comment )) $output['COMMENT'] = count( $this->comment );
2762 if( !empty( $this->completed )) $output['COMPLETED'] = 1;
2763 if( !empty( $this->contact )) $output['CONTACT'] = count( $this->contact );
2764 if( !empty( $this->created )) $output['CREATED'] = 1;
2765 if( !empty( $this->freebusy )) $output['FREEBUSY'] = count( $this->freebusy );
2766 if( !empty( $this->geo )) $output['GEO'] = 1;
2767 if( !empty( $this->lastmodified )) $output['LAST-MODIFIED'] = 1;
2768 if( !empty( $this->location )) $output['LOCATION'] = 1;
2769 if( !empty( $this->organizer )) $output['ORGANIZER'] = 1;
2770 if( !empty( $this->percentcomplete )) $output['PERCENT-COMPLETE'] = 1;
2771 if( !empty( $this->priority )) $output['PRIORITY'] = 1;
2772 if( !empty( $this->recurrenceid )) $output['RECURRENCE-ID'] = 1;
2773 if( !empty( $this->relatedto )) $output['RELATED-TO'] = count( $this->relatedto );
2774 if( !empty( $this->repeat )) $output['REPEAT'] = 1;
2775 if( !empty( $this->requeststatus )) $output['REQUEST-STATUS'] = count( $this->requeststatus );
2776 if( !empty( $this->resources )) $output['RESOURCES'] = count( $this->resources );
2777 if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
2778 if( !empty( $this->sequence )) $output['SEQUENCE'] = 1;
2779 if( !empty( $this->status )) $output['STATUS'] = 1;
2780 if( !empty( $this->transp )) $output['TRANSP'] = 1;
2781 if( !empty( $this->trigger )) $output['TRIGGER'] = 1;
2782 if( !empty( $this->tzid )) $output['TZID'] = 1;
2783 if( !empty( $this->tzname )) $output['TZNAME'] = count( $this->tzname );
2784 if( !empty( $this->tzoffsetfrom )) $output['TZOFFSETFROM'] = 1;
2785 if( !empty( $this->tzoffsetto )) $output['TZOFFSETTO'] = 1;
2786 if( !empty( $this->tzurl )) $output['TZURL'] = 1;
2787 if( !empty( $this->url )) $output['URL'] = 1;
2788 if( !empty( $this->xprop )) $output['X-PROP'] = count( $this->xprop );
2792 return $this->dtzid;
2795 if( empty( $this->unique_id ))
2796 $this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
2797 return $this->unique_id;
2802 * general component config setting
2804 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2805 * @since 2.9.6 - 2011-05-14
2806 * @param mixed $config
2807 * @param string $value
2808 * @param bool $softUpdate
2811 function setConfig( $config, $value = FALSE, $softUpdate = FALSE ) {
2812 if( is_array( $config )) {
2813 foreach( $config as $cKey => $cValue ) {
2814 if( FALSE === $this->setConfig( $cKey, $cValue, $softUpdate ))
2820 switch( strtoupper( $config )) {
2822 $this->allowEmpty = $value;
2823 $subcfg = array( 'ALLOWEMPTY' => $value );
2827 $value = trim( strtolower( $value ));
2828 $this->format = $value;
2829 $this->_createFormat();
2830 $subcfg = array( 'FORMAT' => $value );
2834 // set language for calendar component as defined in [RFC 1766]
2835 $value = trim( $value );
2836 if( empty( $this->language ) || !$softUpdate )
2837 $this->language = $value;
2838 $subcfg = array( 'LANGUAGE' => $value );
2844 $subcfg = array( 'NL' => $value );
2848 $this->dtzid = $value;
2849 $subcfg = array( 'TZID' => $value );
2853 $value = trim( $value );
2854 $this->unique_id = $value;
2855 $subcfg = array( 'UNIQUE_ID' => $value );
2858 default: // any unvalid config key.. .
2861 if( !$res ) return FALSE;
2862 if( isset( $subcfg ) && !empty( $this->components )) {
2863 foreach( $subcfg as $cfgkey => $cfgvalue ) {
2864 foreach( $this->components as $cix => $component ) {
2865 $res = $component->setConfig( $cfgkey, $cfgvalue, $softUpdate );
2868 $this->components[$cix] = $component->copy(); // PHP4 compliant
2874 /*********************************************************************************/
2876 * delete component property value
2878 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2879 * @since 2.8.8 - 2011-03-15
2880 * @param mixed $propName, bool FALSE => X-property
2881 * @param int $propix, optional, if specific property is wanted in case of multiply occurences
2882 * @return bool, if successfull delete TRUE
2884 function deleteProperty( $propName=FALSE, $propix=FALSE ) {
2885 if( $this->_notExistProp( $propName )) return FALSE;
2886 $propName = strtoupper( $propName );
2887 if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
2888 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
2890 $propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1;
2891 $this->propdelix[$propName] = --$propix;
2894 switch( $propName ) {
2896 if( !empty( $this->action )) {
2902 return $this->deletePropertyM( $this->attach, $this->propdelix[$propName] );
2905 return $this->deletePropertyM( $this->attendee, $this->propdelix[$propName] );
2908 return $this->deletePropertyM( $this->categories, $this->propdelix[$propName] );
2911 if( !empty( $this->class )) {
2917 return $this->deletePropertyM( $this->comment, $this->propdelix[$propName] );
2920 if( !empty( $this->completed )) {
2921 $this->completed = '';
2926 return $this->deletePropertyM( $this->contact, $this->propdelix[$propName] );
2929 if( !empty( $this->created )) {
2930 $this->created = '';
2935 return $this->deletePropertyM( $this->description, $this->propdelix[$propName] );
2938 if( !empty( $this->dtend )) {
2944 if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
2946 if( !empty( $this->dtstamp )) {
2947 $this->dtstamp = '';
2952 if( !empty( $this->dtstart )) {
2953 $this->dtstart = '';
2958 if( !empty( $this->due )) {
2964 if( !empty( $this->duration )) {
2965 $this->duration = '';
2970 return $this->deletePropertyM( $this->exdate, $this->propdelix[$propName] );
2973 return $this->deletePropertyM( $this->exrule, $this->propdelix[$propName] );
2976 return $this->deletePropertyM( $this->freebusy, $this->propdelix[$propName] );
2979 if( !empty( $this->geo )) {
2984 case 'LAST-MODIFIED':
2985 if( !empty( $this->lastmodified )) {
2986 $this->lastmodified = '';
2991 if( !empty( $this->location )) {
2992 $this->location = '';
2997 if( !empty( $this->organizer )) {
2998 $this->organizer = '';
3002 case 'PERCENT-COMPLETE':
3003 if( !empty( $this->percentcomplete )) {
3004 $this->percentcomplete = '';
3009 if( !empty( $this->priority )) {
3010 $this->priority = '';
3015 return $this->deletePropertyM( $this->rdate, $this->propdelix[$propName] );
3017 case 'RECURRENCE-ID':
3018 if( !empty( $this->recurrenceid )) {
3019 $this->recurrenceid = '';
3024 return $this->deletePropertyM( $this->relatedto, $this->propdelix[$propName] );
3027 if( !empty( $this->repeat )) {
3032 case 'REQUEST-STATUS':
3033 return $this->deletePropertyM( $this->requeststatus, $this->propdelix[$propName] );
3036 return $this->deletePropertyM( $this->resources, $this->propdelix[$propName] );
3039 return $this->deletePropertyM( $this->rrule, $this->propdelix[$propName] );
3042 if( !empty( $this->sequence )) {
3043 $this->sequence = '';
3048 if( !empty( $this->status )) {
3054 if( !empty( $this->summary )) {
3055 $this->summary = '';
3060 if( !empty( $this->transp )) {
3066 if( !empty( $this->trigger )) {
3067 $this->trigger = '';
3072 if( !empty( $this->tzid )) {
3078 return $this->deletePropertyM( $this->tzname, $this->propdelix[$propName] );
3080 case 'TZOFFSETFROM':
3081 if( !empty( $this->tzoffsetfrom )) {
3082 $this->tzoffsetfrom = '';
3087 if( !empty( $this->tzoffsetto )) {
3088 $this->tzoffsetto = '';
3093 if( !empty( $this->tzurl )) {
3099 if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
3101 if( !empty( $this->uid )) {
3107 if( !empty( $this->url )) {
3114 if( $propName != 'X-PROP' ) {
3115 if( !isset( $this->xprop[$propName] )) return FALSE;
3116 foreach( $this->xprop as $k => $a ) {
3117 if(( $k != $propName ) && !empty( $a ))
3122 if( count( $this->xprop ) <= $propix ) { unset( $this->propdelix[$propName] ); return FALSE; }
3124 foreach( $this->xprop as $xpropkey => $xpropvalue ) {
3125 if( $propix != $xpropno )
3126 $reduced[$xpropkey] = $xpropvalue;
3130 $this->xprop = $reduced;
3131 if( empty( $this->xprop )) {
3132 unset( $this->propdelix[$propName] );
3139 /*********************************************************************************/
3141 * delete component property value, fixing components with multiple occurencies
3143 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3144 * @since 2.8.8 - 2011-03-15
3145 * @param array $multiprop, reference to a component property
3146 * @param int $propix, reference to removal counter
3149 function deletePropertyM( & $multiprop, & $propix ) {
3150 if( isset( $multiprop[$propix] ))
3151 unset( $multiprop[$propix] );
3152 if( empty( $multiprop )) {
3161 * get component property value/params
3163 * if property has multiply values, consequtive function calls are needed
3165 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3166 * @since 2.10.1 - 2011-07-16
3167 * @param string $propName, optional
3168 * @param int @propix, optional, if specific property is wanted in case of multiply occurences
3169 * @param bool $inclParam=FALSE
3170 * @param bool $specform=FALSE
3173 function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) {
3174 if( $this->_notExistProp( $propName )) return FALSE;
3175 $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
3176 if( in_array( $propName, array( 'ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE',
3177 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP' ))) {
3179 $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
3180 $this->propix[$propName] = --$propix;
3182 switch( $propName ) {
3184 if( !empty( $this->action['value'] )) return ( $inclParam ) ? $this->action : $this->action['value'];
3187 $ak = ( is_array( $this->attach )) ? array_keys( $this->attach ) : array();
3188 while( is_array( $this->attach ) && !isset( $this->attach[$propix] ) && ( 0 < count( $this->attach )) && ( $propix < end( $ak )))
3190 if( !isset( $this->attach[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3191 return ( $inclParam ) ? $this->attach[$propix] : $this->attach[$propix]['value'];
3194 $ak = ( is_array( $this->attendee )) ? array_keys( $this->attendee ) : array();
3195 while( is_array( $this->attendee ) && !isset( $this->attendee[$propix] ) && ( 0 < count( $this->attendee )) && ( $propix < end( $ak )))
3197 if( !isset( $this->attendee[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3198 return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
3201 $ak = ( is_array( $this->categories )) ? array_keys( $this->categories ) : array();
3202 while( is_array( $this->categories ) && !isset( $this->categories[$propix] ) && ( 0 < count( $this->categories )) && ( $propix < end( $ak )))
3204 if( !isset( $this->categories[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3205 return ( $inclParam ) ? $this->categories[$propix] : $this->categories[$propix]['value'];
3208 if( !empty( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value'];
3211 $ak = ( is_array( $this->comment )) ? array_keys( $this->comment ) : array();
3212 while( is_array( $this->comment ) && !isset( $this->comment[$propix] ) && ( 0 < count( $this->comment )) && ( $propix < end( $ak )))
3214 if( !isset( $this->comment[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3215 return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value'];
3218 if( !empty( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value'];
3221 $ak = ( is_array( $this->contact )) ? array_keys( $this->contact ) : array();
3222 while( is_array( $this->contact ) && !isset( $this->contact[$propix] ) && ( 0 < count( $this->contact )) && ( $propix < end( $ak )))
3224 if( !isset( $this->contact[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3225 return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value'];
3228 if( !empty( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value'];
3231 $ak = ( is_array( $this->description )) ? array_keys( $this->description ) : array();
3232 while( is_array( $this->description ) && !isset( $this->description[$propix] ) && ( 0 < count( $this->description )) && ( $propix < end( $ak )))
3234 if( !isset( $this->description[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3235 return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value'];
3238 if( !empty( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value'];
3241 if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
3243 if( !isset( $this->dtstamp['value'] ))
3244 $this->_makeDtstamp();
3245 return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value'];
3248 if( !empty( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value'];
3251 if( !empty( $this->due['value'] )) return ( $inclParam ) ? $this->due : $this->due['value'];
3254 if( !isset( $this->duration['value'] )) return FALSE;
3255 $value = ( $specform && isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) ? iCal_UtilityFunctions::_duration2date( $this->dtstart['value'], $this->duration['value'] ) : $this->duration['value'];
3256 return ( $inclParam ) ? array( 'value' => $value, 'params' => $this->duration['params'] ) : $value;
3259 $ak = ( is_array( $this->exdate )) ? array_keys( $this->exdate ) : array();
3260 while( is_array( $this->exdate ) && !isset( $this->exdate[$propix] ) && ( 0 < count( $this->exdate )) && ( $propix < end( $ak )))
3262 if( !isset( $this->exdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3263 return ( $inclParam ) ? $this->exdate[$propix] : $this->exdate[$propix]['value'];
3266 $ak = ( is_array( $this->exrule )) ? array_keys( $this->exrule ) : array();
3267 while( is_array( $this->exrule ) && !isset( $this->exrule[$propix] ) && ( 0 < count( $this->exrule )) && ( $propix < end( $ak )))
3269 if( !isset( $this->exrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3270 return ( $inclParam ) ? $this->exrule[$propix] : $this->exrule[$propix]['value'];
3273 $ak = ( is_array( $this->freebusy )) ? array_keys( $this->freebusy ) : array();
3274 while( is_array( $this->freebusy ) && !isset( $this->freebusy[$propix] ) && ( 0 < count( $this->freebusy )) && ( $propix < end( $ak )))
3276 if( !isset( $this->freebusy[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3277 return ( $inclParam ) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value'];
3280 if( !empty( $this->geo['value'] )) return ( $inclParam ) ? $this->geo : $this->geo['value'];
3282 case 'LAST-MODIFIED':
3283 if( !empty( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value'];
3286 if( !empty( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value'];
3289 if( !empty( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value'];
3291 case 'PERCENT-COMPLETE':
3292 if( !empty( $this->percentcomplete['value'] ) || ( isset( $this->percentcomplete['value'] ) && ( '0' == $this->percentcomplete['value'] ))) return ( $inclParam ) ? $this->percentcomplete : $this->percentcomplete['value'];
3295 if( !empty( $this->priority['value'] ) || ( isset( $this->priority['value'] ) && ('0' == $this->priority['value'] ))) return ( $inclParam ) ? $this->priority : $this->priority['value'];
3298 $ak = ( is_array( $this->rdate )) ? array_keys( $this->rdate ) : array();
3299 while( is_array( $this->rdate ) && !isset( $this->rdate[$propix] ) && ( 0 < count( $this->rdate )) && ( $propix < end( $ak )))
3301 if( !isset( $this->rdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3302 return ( $inclParam ) ? $this->rdate[$propix] : $this->rdate[$propix]['value'];
3304 case 'RECURRENCE-ID':
3305 if( !empty( $this->recurrenceid['value'] )) return ( $inclParam ) ? $this->recurrenceid : $this->recurrenceid['value'];
3308 $ak = ( is_array( $this->relatedto )) ? array_keys( $this->relatedto ) : array();
3309 while( is_array( $this->relatedto ) && !isset( $this->relatedto[$propix] ) && ( 0 < count( $this->relatedto )) && ( $propix < end( $ak )))
3311 if( !isset( $this->relatedto[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3312 return ( $inclParam ) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value'];
3315 if( !empty( $this->repeat['value'] ) || ( isset( $this->repeat['value'] ) && ( '0' == $this->repeat['value'] ))) return ( $inclParam ) ? $this->repeat : $this->repeat['value'];
3317 case 'REQUEST-STATUS':
3318 $ak = ( is_array( $this->requeststatus )) ? array_keys( $this->requeststatus ) : array();
3319 while( is_array( $this->requeststatus ) && !isset( $this->requeststatus[$propix] ) && ( 0 < count( $this->requeststatus )) && ( $propix < end( $ak )))
3321 if( !isset( $this->requeststatus[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3322 return ( $inclParam ) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value'];
3325 $ak = ( is_array( $this->resources )) ? array_keys( $this->resources ) : array();
3326 while( is_array( $this->resources ) && !isset( $this->resources[$propix] ) && ( 0 < count( $this->resources )) && ( $propix < end( $ak )))
3328 if( !isset( $this->resources[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3329 return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value'];
3332 $ak = ( is_array( $this->rrule )) ? array_keys( $this->rrule ) : array();
3333 while( is_array( $this->rrule ) && !isset( $this->rrule[$propix] ) && ( 0 < count( $this->rrule )) && ( $propix < end( $ak )))
3335 if( !isset( $this->rrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3336 return ( $inclParam ) ? $this->rrule[$propix] : $this->rrule[$propix]['value'];
3340 isset( $this->sequence['value'] ) &&
3341 ( isset( $this->sequence['value'] ) && ( '0' <= $this->sequence['value'] ))
3343 return ( $inclParam ) ? $this->sequence : $this->sequence['value'];
3346 if( !empty( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value'];
3349 if( !empty( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value'];
3352 if( !empty( $this->transp['value'] )) return ( $inclParam ) ? $this->transp : $this->transp['value'];
3355 if( !empty( $this->trigger['value'] )) return ( $inclParam ) ? $this->trigger : $this->trigger['value'];
3358 if( !empty( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value'];
3361 $ak = ( is_array( $this->tzname )) ? array_keys( $this->tzname ) : array();
3362 while( is_array( $this->tzname ) && !isset( $this->tzname[$propix] ) && ( 0 < count( $this->tzname )) && ( $propix < end( $ak )))
3364 if( !isset( $this->tzname[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3365 return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
3367 case 'TZOFFSETFROM':
3368 if( !empty( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
3371 if( !empty( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value'];
3374 if( !empty( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value'];
3377 if( in_array( $this->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' )))
3379 if( empty( $this->uid['value'] ))
3381 return ( $inclParam ) ? $this->uid : $this->uid['value'];
3384 if( !empty( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value'];
3387 if( $propName != 'X-PROP' ) {
3388 if( !isset( $this->xprop[$propName] )) return FALSE;
3389 return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
3390 : array( $propName, $this->xprop[$propName]['value'] );
3393 if( empty( $this->xprop )) return FALSE;
3395 foreach( $this->xprop as $xpropkey => $xpropvalue ) {
3396 if( $propix == $xpropno )
3397 return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
3398 : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
3402 return FALSE; // not found ??
3408 * returns calendar property unique values for 'CATEGORIES', 'RESOURCES' or 'ATTENDEE' and each number of ocurrence
3410 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3411 * @since 2.8.8 - 2011-04-13
3412 * @param string $propName
3413 * @param array $output, incremented result array
3415 function _getProperties( $propName, & $output ) {
3416 if( !in_array( strtoupper( $propName ), array( 'ATTENDEE', 'CATEGORIES', 'RESOURCES' )))
3418 while( FALSE !== ( $content = $this->getProperty( $propName ))) {
3419 if( is_array( $content )) {
3420 foreach( $content as $part ) {
3421 if( FALSE !== strpos( $part, ',' )) {
3422 $part = explode( ',', $part );
3423 foreach( $part as $thePart ) {
3424 $thePart = trim( $thePart );
3425 if( !empty( $thePart )) {
3426 if( !isset( $output[$thePart] ))
3427 $output[$thePart] = 1;
3429 $output[$thePart] += 1;
3434 $part = trim( $part );
3435 if( !isset( $output[$part] ))
3438 $output[$part] += 1;
3442 elseif( FALSE !== strpos( $content, ',' )) {
3443 $content = explode( ',', $content );
3444 foreach( $content as $thePart ) {
3445 $thePart = trim( $thePart );
3446 if( !empty( $thePart )) {
3447 if( !isset( $output[$thePart] ))
3448 $output[$thePart] = 1;
3450 $output[$thePart] += 1;
3455 $content = trim( $content );
3456 if( !empty( $content )) {
3457 if( !isset( $output[$content] ))
3458 $output[$content] = 1;
3460 $output[$content] += 1;
3468 * general component property setting
3470 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3471 * @since 2.5.1 - 2008-11-05
3472 * @param mixed $args variable number of function arguments,
3473 * first argument is ALWAYS component name,
3474 * second ALWAYS component value!
3477 function setProperty() {
3478 $numargs = func_num_args();
3479 if( 1 > $numargs ) return FALSE;
3480 $arglist = func_get_args();
3481 if( $this->_notExistProp( $arglist[0] )) return FALSE;
3482 if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] )))
3484 $arglist[0] = strtoupper( $arglist[0] );
3485 for( $argix=$numargs; $argix < 12; $argix++ ) {
3486 if( !isset( $arglist[$argix] ))
3487 $arglist[$argix] = null;
3489 switch( $arglist[0] ) {
3491 return $this->setAction( $arglist[1], $arglist[2] );
3493 return $this->setAttach( $arglist[1], $arglist[2], $arglist[3] );
3495 return $this->setAttendee( $arglist[1], $arglist[2], $arglist[3] );
3497 return $this->setCategories( $arglist[1], $arglist[2], $arglist[3] );
3499 return $this->setClass( $arglist[1], $arglist[2] );
3501 return $this->setComment( $arglist[1], $arglist[2], $arglist[3] );
3503 return $this->setCompleted( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3505 return $this->setContact( $arglist[1], $arglist[2], $arglist[3] );
3507 return $this->setCreated( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3509 return $this->setDescription( $arglist[1], $arglist[2], $arglist[3] );
3511 return $this->setDtend( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
3513 return $this->setDtstamp( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3515 return $this->setDtstart( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
3517 return $this->setDue( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
3519 return $this->setDuration( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] );
3521 return $this->setExdate( $arglist[1], $arglist[2], $arglist[3] );
3523 return $this->setExrule( $arglist[1], $arglist[2], $arglist[3] );
3525 return $this->setFreebusy( $arglist[1], $arglist[2], $arglist[3], $arglist[4] );
3527 return $this->setGeo( $arglist[1], $arglist[2], $arglist[3] );
3528 case 'LAST-MODIFIED':
3529 return $this->setLastModified( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
3531 return $this->setLocation( $arglist[1], $arglist[2] );
3533 return $this->setOrganizer( $arglist[1], $arglist[2] );
3534 case 'PERCENT-COMPLETE':
3535 return $this->setPercentComplete( $arglist[1], $arglist[2] );
3537 return $this->setPriority( $arglist[1], $arglist[2] );
3539 return $this->setRdate( $arglist[1], $arglist[2], $arglist[3] );
3540 case 'RECURRENCE-ID':
3541 return $this->setRecurrenceid( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
3543 return $this->setRelatedTo( $arglist[1], $arglist[2], $arglist[3] );
3545 return $this->setRepeat( $arglist[1], $arglist[2] );
3546 case 'REQUEST-STATUS':
3547 return $this->setRequestStatus( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5] );
3549 return $this->setResources( $arglist[1], $arglist[2], $arglist[3] );
3551 return $this->setRrule( $arglist[1], $arglist[2], $arglist[3] );
3553 return $this->setSequence( $arglist[1], $arglist[2] );
3555 return $this->setStatus( $arglist[1], $arglist[2] );
3557 return $this->setSummary( $arglist[1], $arglist[2] );
3559 return $this->setTransp( $arglist[1], $arglist[2] );
3561 return $this->setTrigger( $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8], $arglist[9], $arglist[10], $arglist[11] );
3563 return $this->setTzid( $arglist[1], $arglist[2] );
3565 return $this->setTzname( $arglist[1], $arglist[2], $arglist[3] );
3566 case 'TZOFFSETFROM':
3567 return $this->setTzoffsetfrom( $arglist[1], $arglist[2] );
3569 return $this->setTzoffsetto( $arglist[1], $arglist[2] );
3571 return $this->setTzurl( $arglist[1], $arglist[2] );
3573 return $this->setUid( $arglist[1], $arglist[2] );
3575 return $this->setUrl( $arglist[1], $arglist[2] );
3577 return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] );
3581 /*********************************************************************************/
3583 * parse component unparsed data into properties
3585 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3586 * @since 2.10.2 - 2011-07-17
3587 * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of strings
3588 * @return bool FALSE if error occurs during parsing
3591 function parse( $unparsedtext=null ) {
3592 if( !empty( $unparsedtext )) {
3593 $nl = $this->getConfig( 'nl' );
3594 if( is_array( $unparsedtext ))
3595 $unparsedtext = implode( '\n'.$nl, $unparsedtext );
3596 /* fix line folding */
3597 $eolchars = array( "\r\n", "\n\r", "\n", "\r" ); // check all line endings
3599 foreach( $eolchars as $eolchar ) {
3600 if( !$EOLmark && ( FALSE !== strpos( $unparsedtext, $eolchar ))) {
3601 $unparsedtext = str_replace( $eolchar." ", '', $unparsedtext );
3602 $unparsedtext = str_replace( $eolchar."\t", '', $unparsedtext );
3603 if( $eolchar != $nl )
3604 $unparsedtext = str_replace( $eolchar, $nl, $unparsedtext );
3608 $tmp = explode( $nl, $unparsedtext );
3609 $unparsedtext = array();
3610 foreach( $tmp as $tmpr )
3611 if( !empty( $tmpr ))
3612 $unparsedtext[] = $tmpr;
3614 elseif( !isset( $this->unparsed ))
3615 $unparsedtext = array();
3617 $unparsedtext = $this->unparsed;
3618 $this->unparsed = array();
3620 $config = $this->getConfig();
3621 foreach ( $unparsedtext as $line ) {
3622 // echo $comp->objName.": $line<br />"; // test ###
3623 if( in_array( strtoupper( substr( $line, 0, 6 )), array( 'END:VA', 'END:DA' )))
3624 $this->components[] = $comp->copy();
3625 elseif( 'END:ST' == strtoupper( substr( $line, 0, 6 )))
3626 array_unshift( $this->components, $comp->copy());
3627 elseif( 'END:' == strtoupper( substr( $line, 0, 4 )))
3629 elseif( 'BEGIN:VALARM' == strtoupper( substr( $line, 0, 12 )))
3630 $comp = new valarm( $config);
3631 elseif( 'BEGIN:STANDARD' == strtoupper( substr( $line, 0, 14 )))
3632 $comp = new vtimezone( 'standard', $config );
3633 elseif( 'BEGIN:DAYLIGHT' == strtoupper( substr( $line, 0, 14 )))
3634 $comp = new vtimezone( 'daylight', $config );
3635 elseif( 'BEGIN:' == strtoupper( substr( $line, 0, 6 )))
3638 $comp->unparsed[] = $line;
3639 // echo $comp->objName.": $line<br />\n"; // test ###
3643 // echo $this->objName.'<br />'.var_export( $this->unparsed, TRUE )."<br />\n"; // test ###
3644 /* concatenate property values spread over several lines */
3646 $propnames = array( 'action', 'attach', 'attendee', 'categories', 'comment', 'completed'
3647 , 'contact', 'class', 'created', 'description', 'dtend', 'dtstart'
3648 , 'dtstamp', 'due', 'duration', 'exdate', 'exrule', 'freebusy', 'geo'
3649 , 'last-modified', 'location', 'organizer', 'percent-complete'
3650 , 'priority', 'rdate', 'recurrence-id', 'related-to', 'repeat'
3651 , 'request-status', 'resources', 'rrule', 'sequence', 'status'
3652 , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom'
3653 , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' );
3654 $proprows = array();
3655 foreach( $this->unparsed as $line ) {
3657 foreach ( $propnames as $propname ) {
3658 if( $propname == strtolower( substr( $line, 0, strlen( $propname )))) {
3665 $proprows[$lastix] = $proprows[$lastix];
3668 $proprows[$lastix] = $line;
3671 $proprows[$lastix] .= '!"#¤%&/()=?'.$line;
3673 /* parse each property 'line' */
3674 foreach( $proprows as $line ) {
3675 $line = str_replace( '!"#¤%&/()=? ', '', $line );
3676 $line = str_replace( '!"#¤%&/()=?', '', $line );
3677 if( '\n' == substr( $line, -2 ))
3678 $line = substr( $line, 0, strlen( $line ) - 2 );
3679 /* get propname, (problem with x-properties, otherwise in previous loop) */
3680 $cix = $propname = null;
3681 for( $cix=0, $clen = strlen( $line ); $cix < $clen; $cix++ ) {
3682 if( in_array( $line[$cix], array( ':', ';' )))
3685 $propname .= $line[$cix];
3688 if(( 'x-' == substr( $propname, 0, 2 )) || ( 'X-' == substr( $propname, 0, 2 ))) {
3689 $propname2 = $propname;
3692 /* rest of the line is opt.params and value */
3693 $line = substr( $line, $cix );
3694 /* separate attributes from value */
3697 $clen = strlen( $line );
3698 for( $cix=0; $cix < $clen; $cix++ ) {
3699 if(( ':' == $line[$cix] ) &&
3700 ( '://' != substr( $line, $cix, 3 )) &&
3701 ( !in_array( strtolower( substr( $line, $cix - 3, 4 )), array( 'fax:', 'cid:', 'sms:', 'tel:', 'urn:' ))) &&
3702 ( !in_array( strtolower( substr( $line, $cix - 4, 5 )), array( 'crid:', 'news:', 'pres:' ))) &&
3703 ( 'mailto:' != strtolower( substr( $line, $cix - 6, 7 )))) {
3705 if(( $cix < ( $clen - 4 )) &&
3706 ctype_digit( substr( $line, $cix+1, 4 ))) { // an URI with a (4pos) portnr??
3707 for( $c2ix = $cix; 3 < $c2ix; $c2ix-- ) {
3708 if( '://' == substr( $line, $c2ix - 2, 3 )) {
3710 break; // an URI with a portnr!!
3715 $line = substr( $line, $cix + 1 );
3719 if( ';' == $line[$cix] )
3720 $attr[++$attrix] = null;
3722 $attr[$attrix] .= $line[$cix];
3724 /* make attributes in array format */
3725 $propattr = array();
3726 foreach( $attr as $attribute ) {
3727 $attrsplit = explode( '=', $attribute, 2 );
3728 if( 1 < count( $attrsplit ))
3729 $propattr[$attrsplit[0]] = $attrsplit[1];
3731 $propattr[] = $attribute;
3733 /* call setProperty( $propname.. . */
3734 switch( strtoupper( $propname )) {
3736 foreach( $propattr as $pix => $attr ) {
3737 $attr2 = explode( ',', $attr );
3738 if( 1 < count( $attr2 ))
3739 $propattr[$pix] = $attr2;
3741 $this->setProperty( $propname, $line, $propattr );
3745 if( FALSE !== strpos( $line, ',' )) {
3746 $content = explode( ',', $line );
3747 $clen = count( $content );
3748 for( $cix = 0; $cix < $clen; $cix++ ) {
3749 if( "\\" == substr($content[$cix], -1)) {
3750 $content[$cix] .= ','.$content[$cix + 1];
3751 unset($content[$cix + 1]);
3755 if( 1 < count( $content )) {
3756 $content = array_values( $content );
3757 foreach( $content as $cix => $contentPart )
3758 $content[$cix] = calendarComponent::_strunrep( $contentPart );
3759 $this->setProperty( $propname, $content, $propattr );
3763 $line = reset( $content );
3766 $propname = ( isset( $propname2 )) ? $propname2 : $propname;
3774 $this->setProperty( $propname, calendarComponent::_strunrep( $line ), $propattr );
3775 unset( $propname2 );
3777 case 'REQUEST-STATUS':
3778 $values = explode( ';', $line, 3 );
3779 $values[1] = ( !isset( $values[1] )) ? null : calendarComponent::_strunrep( $values[1] );
3780 $values[2] = ( !isset( $values[2] )) ? null : calendarComponent::_strunrep( $values[2] );
3781 $this->setProperty( $propname
3782 , $values[0] // statcode
3783 , $values[1] // statdesc
3784 , $values[2] // extdata
3788 $fbtype = ( isset( $propattr['FBTYPE'] )) ? $propattr['FBTYPE'] : ''; // force setting default, if missing
3789 unset( $propattr['FBTYPE'] );
3790 $values = explode( ',', $line );
3791 foreach( $values as $vix => $value ) {
3792 $value2 = explode( '/', $value );
3793 if( 1 < count( $value2 ))
3794 $values[$vix] = $value2;
3796 $this->setProperty( $propname, $fbtype, $values, $propattr );
3799 $value = explode( ';', $line, 2 );
3800 if( 2 > count( $value ))
3802 $this->setProperty( $propname, $value[0], $value[1], $propattr );
3805 $values = ( !empty( $line )) ? explode( ',', $line ) : null;
3806 $this->setProperty( $propname, $values, $propattr );
3809 if( empty( $line )) {
3810 $this->setProperty( $propname, $line, $propattr );
3813 $values = explode( ',', $line );
3814 foreach( $values as $vix => $value ) {
3815 $value2 = explode( '/', $value );
3816 if( 1 < count( $value2 ))
3817 $values[$vix] = $value2;
3819 $this->setProperty( $propname, $values, $propattr );
3823 $values = explode( ';', $line );
3825 foreach( $values as $value2 ) {
3826 if( empty( $value2 ))
3827 continue; // ;-char in ending position ???
3828 $value3 = explode( '=', $value2, 2 );
3829 $rulelabel = strtoupper( $value3[0] );
3830 switch( $rulelabel ) {
3832 $value4 = explode( ',', $value3[1] );
3833 if( 1 < count( $value4 )) {
3834 foreach( $value4 as $v5ix => $value5 ) {
3836 $dayno = $dayname = null;
3837 $value5 = trim( (string) $value5 );
3838 if(( ctype_alpha( substr( $value5, -1 ))) &&
3839 ( ctype_alpha( substr( $value5, -2, 1 )))) {
3840 $dayname = substr( $value5, -2, 2 );
3841 if( 2 < strlen( $value5 ))
3842 $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
3847 $value6['DAY'] = $dayname;
3848 $value4[$v5ix] = $value6;
3853 $dayno = $dayname = null;
3854 $value5 = trim( (string) $value3[1] );
3855 if(( ctype_alpha( substr( $value5, -1 ))) &&
3856 ( ctype_alpha( substr( $value5, -2, 1 )))) {
3857 $dayname = substr( $value5, -2, 2 );
3858 if( 2 < strlen( $value5 ))
3859 $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
3864 $value4['DAY'] = $dayname;
3866 $recur[$rulelabel] = $value4;
3870 $value4 = explode( ',', $value3[1] );
3871 if( 1 < count( $value4 ))
3872 $value3[1] = $value4;
3873 $recur[$rulelabel] = $value3[1];
3876 } // end - switch $rulelabel
3877 } // end - foreach( $values.. .
3878 $this->setProperty( $propname, $recur, $propattr );
3881 case 'CLASSIFICATION':
3888 $line = calendarComponent::_strunrep( $line );
3890 $this->setProperty( $propname, $line, $propattr );
3892 } // end switch( $propname.. .
3893 } // end - foreach( $proprows.. .
3894 unset( $unparsedtext, $this->unparsed, $proprows );
3895 if( isset( $this->components ) && is_array( $this->components ) && ( 0 < count( $this->components ))) {
3896 $ckeys = array_keys( $this->components );
3897 foreach( $ckeys as $ckey ) {
3898 if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) {
3899 $this->components[$ckey]->parse();
3905 /*********************************************************************************/
3906 /*********************************************************************************/
3908 * return a copy of this component
3910 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3911 * @since 2.8.8 - 2011-03-15
3915 $serialized_contents = serialize( $this );
3916 $copy = unserialize( $serialized_contents );
3919 /*********************************************************************************/
3920 /*********************************************************************************/
3922 * delete calendar subcomponent from component container
3924 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3925 * @since 2.8.8 - 2011-03-15
3926 * @param mixed $arg1 ordno / component type / component uid
3927 * @param mixed $arg2 optional, ordno if arg1 = component type
3930 function deleteComponent( $arg1, $arg2=FALSE ) {
3931 if( !isset( $this->components )) return FALSE;
3932 $argType = $index = null;
3933 if ( ctype_digit( (string) $arg1 )) {
3935 $index = (int) $arg1 - 1;
3937 elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
3938 $argType = strtolower( $arg1 );
3939 $index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
3942 foreach ( $this->components as $cix => $component) {
3943 if( empty( $component )) continue;
3944 if(( 'INDEX' == $argType ) && ( $index == $cix )) {
3945 unset( $this->components[$cix] );
3948 elseif( $argType == $component->objName ) {
3949 if( $index == $cix2dC ) {
3950 unset( $this->components[$cix] );
3955 elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
3956 unset( $this->components[$cix] );
3963 * get calendar component subcomponent from component container
3965 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3966 * @since 2.8.8 - 2011-03-15
3967 * @param mixed $arg1 optional, ordno/component type/ component uid
3968 * @param mixed $arg2 optional, ordno if arg1 = component type
3971 function getComponent ( $arg1=FALSE, $arg2=FALSE ) {
3972 if( !isset( $this->components )) return FALSE;
3973 $index = $argType = null;
3976 $index = $this->compix['INDEX'] =
3977 ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
3979 elseif ( ctype_digit( (string) $arg1 )) {
3981 $index = (int) $arg1;
3982 unset( $this->compix );
3984 elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
3985 unset( $this->compix['INDEX'] );
3986 $argType = strtolower( $arg1 );
3988 $index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
3990 $index = (int) $arg2;
3993 $ckeys = array_keys( $this->components );
3994 if( !empty( $index) && ( $index > end( $ckeys )))
3997 foreach( $this->components as $cix => $component ) {
3998 if( empty( $component )) continue;
3999 if(( 'INDEX' == $argType ) && ( $index == $cix ))
4000 return $component->copy();
4001 elseif( $argType == $component->objName ) {
4002 if( $index == $cix2gC )
4003 return $component->copy();
4006 elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' )))
4007 return $component->copy();
4010 unset( $this->compix );
4014 * add calendar component as subcomponent to container for subcomponents
4016 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4017 * @since 1.x.x - 2007-04-24
4018 * @param object $component calendar component
4021 function addSubComponent ( $component ) {
4022 $this->setComponent( $component );
4025 * create new calendar component subcomponent, already included within component
4027 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4028 * @since 2.6.33 - 2011-01-03
4029 * @param string $compType subcomponent type
4030 * @return object (reference)
4032 function & newComponent( $compType ) {
4033 $config = $this->getConfig();
4034 $keys = array_keys( $this->components );
4035 $ix = end( $keys) + 1;
4036 switch( strtoupper( $compType )) {
4039 $this->components[$ix] = new valarm( $config );
4042 array_unshift( $this->components, new vtimezone( 'STANDARD', $config ));
4046 $this->components[$ix] = new vtimezone( 'DAYLIGHT', $config );
4051 return $this->components[$ix];
4054 * add calendar component as subcomponent to container for subcomponents
4056 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4057 * @since 2.8.8 - 2011-03-15
4058 * @param object $component calendar component
4059 * @param mixed $arg1 optional, ordno/component type/ component uid
4060 * @param mixed $arg2 optional, ordno if arg1 = component type
4063 function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) {
4064 if( !isset( $this->components )) return FALSE;
4065 $component->setConfig( $this->getConfig(), FALSE, TRUE );
4066 if( !in_array( $component->objName, array( 'valarm', 'vtimezone', 'standard', 'daylight' ))) {
4067 /* make sure dtstamp and uid is set */
4068 $dummy = $component->getProperty( 'dtstamp' );
4069 $dummy = $component->getProperty( 'uid' );
4071 if( !$arg1 ) { // plain insert, last in chain
4072 $this->components[] = $component->copy();
4075 $argType = $index = null;
4076 if ( ctype_digit( (string) $arg1 )) { // index insert/replace
4078 $index = (int) $arg1 - 1;
4080 elseif( in_array( strtolower( $arg1 ), array( 'vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone' ))) {
4081 $argType = strtolower( $arg1 );
4082 $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
4084 // else if arg1 is set, arg1 must be an UID
4086 foreach ( $this->components as $cix => $component2 ) {
4087 if( empty( $component2 )) continue;
4088 if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace
4089 $this->components[$cix] = $component->copy();
4092 elseif( $argType == $component2->objName ) { // component Type index insert/replace
4093 if( $index == $cix2sC ) {
4094 $this->components[$cix] = $component->copy();
4099 elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace
4100 $this->components[$cix] = $component->copy();
4104 /* arg1=index and not found.. . insert at index .. .*/
4105 if( 'INDEX' == $argType ) {
4106 $this->components[$index] = $component->copy();
4107 ksort( $this->components, SORT_NUMERIC );
4109 else /* not found.. . insert last in chain anyway .. .*/
4110 $this->components[] = $component->copy();
4114 * creates formatted output for subcomponents
4116 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4117 * @since 2.6.27 - 2010-12-12
4120 function createSubComponent() {
4122 foreach( $this->components as $component ) {
4123 if( empty( $component )) continue;
4124 $component->setConfig( $this->getConfig(), FALSE, TRUE );
4125 $output .= $component->createComponent( $this->xcaldecl );
4129 /********************************************************************************/
4131 * break lines at pos 75
4133 * Lines of text SHOULD NOT be longer than 75 octets, excluding the line
4134 * break. Long content lines SHOULD be split into a multiple line
4135 * representations using a line "folding" technique. That is, a long
4136 * line can be split between any two characters by inserting a CRLF
4137 * immediately followed by a single linear white space character (i.e.,
4138 * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
4139 * of CRLF followed immediately by a single linear white space character
4140 * is ignored (i.e., removed) when processing the content type.
4142 * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where
4143 * the reserved expression "\n" in the arg $string could be broken up by the
4144 * folding of lines, causing ambiguity in the return string.
4145 * Fix uses var $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be.
4147 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4148 * @since 2.10.11 - 2011-09-01
4149 * @param string $value
4152 function _size75( $string ) {
4155 $eolcharlen = strlen( '\n' );
4156 /* if PHP is config with mb_string and conf overload.. . */
4157 if( defined( 'MB_OVERLOAD_STRING' ) && ( 1 < ini_get( 'mbstring.func_overload' ))) {
4158 $strlen = mb_strlen( $tmp );
4159 while( $strlen > 75 ) {
4160 if( '\n' == mb_substr( $tmp, 75, $eolcharlen ))
4164 $string .= mb_substr( $tmp, 0, $breakAtChar );
4165 if( $this->nl != mb_substr( $string, ( 0 - mb_strlen( $this->nl ))))
4166 $string .= $this->nl;
4167 $tmp = mb_substr( $tmp, $breakAtChar );
4170 $strlen = mb_strlen( $tmp );
4173 $string .= $tmp; // the rest
4174 if( $this->nl != mb_substr( $string, ( 0 - mb_strlen( $this->nl ))))
4175 $string .= $this->nl;
4179 /* if PHP is not config with mb_string.. . */
4181 $bytecnt = strlen( $tmp );
4183 for( $ix = 0; $ix < $bytecnt; $ix++ ) {
4184 if(( 73 < $charCnt ) && ( '\n' == substr( $tmp, $ix, $eolcharlen )))
4185 break; // break before '\n'
4186 elseif( 74 < $charCnt ) {
4187 if( '\n' == substr( $tmp, $ix, $eolcharlen ))
4188 $ix -= 1; // don't break inside '\n'
4189 break; // always break while-loop here
4192 $byte = ord( $tmp[$ix] );
4193 if ($byte <= 127) { // add a one byte character
4194 $string .= substr( $tmp, $ix, 1 );
4197 else if ($byte >= 194 && $byte <= 223) { // start byte in two byte character
4198 $string .= substr( $tmp, $ix, 2 ); // add a two bytes character
4201 else if ($byte >= 224 && $byte <= 239) { // start byte in three bytes character
4202 $string .= substr( $tmp, $ix, 3 ); // add a three bytes character
4205 else if ($byte >= 240 && $byte <= 244) { // start byte in four bytes character
4206 $string .= substr( $tmp, $ix, 4 ); // add a four bytes character
4211 if( $this->nl != substr( $string, ( 0 - strlen( $this->nl ))))
4212 $string .= $this->nl;
4213 $tmp = substr( $tmp, $ix );
4215 break; // while-loop breakes here
4222 * special characters management output
4224 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4225 * @since 2.6.15 - 2010-09-24
4226 * @param string $string
4229 function _strrep( $string ) {
4230 switch( $this->format ) {
4232 $string = str_replace( '\n', $this->nl, $string);
4233 $string = htmlspecialchars( strip_tags( stripslashes( urldecode ( $string ))));
4237 $specChars = array( 'n', 'N', 'r', ',', ';' );
4238 while( $pos <= strlen( $string )) {
4239 $pos = strpos( $string, "\\", $pos );
4240 if( FALSE === $pos )
4242 if( !in_array( substr( $string, $pos, 1 ), $specChars )) {
4243 $string = substr( $string, 0, $pos )."\\".substr( $string, ( $pos + 1 ));
4248 if( FALSE !== strpos( $string, '"' ))
4249 $string = str_replace('"', "'", $string);
4250 if( FALSE !== strpos( $string, ',' ))
4251 $string = str_replace(',', '\,', $string);
4252 if( FALSE !== strpos( $string, ';' ))
4253 $string = str_replace(';', '\;', $string);
4255 if( FALSE !== strpos( $string, "\r\n" ))
4256 $string = str_replace( "\r\n", '\n', $string);
4257 elseif( FALSE !== strpos( $string, "\r" ))
4258 $string = str_replace( "\r", '\n', $string);
4260 elseif( FALSE !== strpos( $string, "\n" ))
4261 $string = str_replace( "\n", '\n', $string);
4263 if( FALSE !== strpos( $string, '\N' ))
4264 $string = str_replace( '\N', '\n', $string);
4265 // if( FALSE !== strpos( $string, $this->nl ))
4266 $string = str_replace( $this->nl, '\n', $string);
4272 * special characters management input (from iCal file)
4274 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4275 * @since 2.6.22 - 2010-10-17
4276 * @param string $string
4279 static function _strunrep( $string ) {
4280 $string = str_replace( '\\\\', '\\', $string);
4281 $string = str_replace( '\,', ',', $string);
4282 $string = str_replace( '\;', ';', $string);
4283 // $string = str_replace( '\n', $this->nl, $string); // ??