Projet

Général

Profil

Paste
Télécharger (187 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / libraries / iCalcreator-2.22.1 / lib / calendarComponent.class.php @ 9525582e

1
<?php
2
/*********************************************************************************/
3
/**
4
 *
5
 * iCalcreator, a PHP rfc2445/rfc5545 solution.
6
 *
7
 * @copyright Copyright (c) 2007-2015 Kjell-Inge Gustafsson, kigkonsult, All rights reserved
8
 * @link      http://kigkonsult.se/iCalcreator/index.php
9
 * @license   http://kigkonsult.se/downloads/dl.php?f=LGPL
10
 * @package   iCalcreator
11
 * @version   2.22
12
 */
13
/**
14
 * This library is free software; you can redistribute it and/or
15
 * modify it under the terms of the GNU Lesser General Public
16
 * License as published by the Free Software Foundation; either
17
 * version 2.1 of the License, or (at your option) any later version.
18
 *
19
 * This library is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22
 * Lesser General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU Lesser General Public
25
 * License along with this library; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28
/*********************************************************************************/
29
/**
30
 *  abstract class for calendar components
31
 *
32
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
33
 * @since 2.2.11 - 2015-03-31
34
 */
35
class calendarComponent  extends iCalBase {
36
/** @var array component property UID value */
37
  protected $uid;
38
/** @var array component property DTSTAMP value */
39
  protected $dtstamp;
40
/** @var string component type */
41
  public $objName;
42
/**
43
 * constructor for calendar component object
44
 *
45
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
46
 * @since 2.9.6 - 2011-05-17
47
 * @uses calendarComponent::$objName
48
 * @uses calendarComponent::$timezonetype
49
 * @uses calendarComponent::$uid
50
 * @uses calendarComponent::$dtstamp
51
 * @uses calendarComponent::$language
52
 * @uses calendarComponent::$nl
53
 * @uses calendarComponent::$unique_id
54
 * @uses calendarComponent::$format
55
 * @uses calendarComponent::$dtzid
56
 * @uses calendarComponent::$allowEmpty
57
 * @uses calendarComponent::$xcaldecl
58
 * @uses calendarComponent::_createFormat()
59
 * @uses calendarComponent::_makeDtstamp()
60
 */
61
  function calendarComponent() {
62
    $this->objName         = ( isset( $this->timezonetype )) ?
63
                          strtolower( $this->timezonetype )  :  get_class ( $this );
64
    $this->uid             = array();
65
    $this->dtstamp         = array();
66

    
67
    $this->language        = null;
68
    $this->nl              = null;
69
    $this->unique_id       = null;
70
    $this->format          = null;
71
    $this->dtzid           = null;
72
    $this->allowEmpty      = TRUE;
73
    $this->xcaldecl        = array();
74

    
75
    $this->_createFormat();
76
    $this->_makeDtstamp();
77
  }
78
/*********************************************************************************/
79
/**
80
 * Property Name: ACTION
81
 */
82
/**
83
 * creates formatted output for calendar component property action
84
 *
85
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
86
 * @since 2.4.8 - 2008-10-22
87
 * @uses calendarComponent::$action
88
 * @uses calendarComponent::getConfig()
89
 * @uses calendarComponent::_createElement()
90
 * @uses calendarComponent::_createParams()
91
 * @uses calendarComponent::_createElement()
92
 * @return string
93
 */
94
  function createAction() {
95
    if( empty( $this->action )) return FALSE;
96
    if( empty( $this->action['value'] ))
97
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ACTION' ) : FALSE;
98
    $attributes = $this->_createParams( $this->action['params'] );
99
    return $this->_createElement( 'ACTION', $attributes, $this->action['value'] );
100
  }
101
/**
102
 * set calendar component property action
103
 *
104
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
105
 * @since 2.16.21 - 2013-06-23
106
 * @param string $value  "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
107
 * @param mixed $params
108
 * @uses calendarComponent::getConfig()
109
 * @uses calendarComponent::$action
110
 * @uses calendarComponent::$action
111
 * @uses iCalUtilityFunctions::_setParams()
112
 * @return bool
113
 */
114
  function setAction( $value, $params=FALSE ) {
115
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
116
    $this->action = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
117
    return TRUE;
118
  }
119
/*********************************************************************************/
120
/**
121
 * Property Name: ATTACH
122
 */
123
/**
124
 * creates formatted output for calendar component property attach
125
 *
126
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
127
 * @since 2.11.16 - 2012-02-04
128
 * @uses calendarComponent::$attach
129
 * @uses calendarComponent::_createParams()
130
 * @uses calendarComponent::$format
131
 * @uses calendarComponent::$intAttrDelimiter
132
 * @uses calendarComponent::$attributeDelimiter
133
 * @uses calendarComponent::$valueInit
134
 * @uses calendarComponent::$nl
135
 * @uses calendarComponent::_createElement()
136
 * @return string
137
 */
138
  function createAttach() {
139
    if( empty( $this->attach )) return FALSE;
140
    $output       = null;
141
    foreach( $this->attach as $attachPart ) {
142
      if( !empty( $attachPart['value'] )) {
143
        $attributes = $this->_createParams( $attachPart['params'] );
144
        if(( 'xcal' != $this->format ) && isset( $attachPart['params']['VALUE'] ) && ( 'BINARY' == $attachPart['params']['VALUE'] )) {
145
          $attributes = str_replace( $this->intAttrDelimiter, $this->attributeDelimiter, $attributes );
146
          $str        = 'ATTACH'.$attributes.$this->valueInit.$attachPart['value'];
147
          $output     = substr( $str, 0, 75 ).$this->nl;
148
          $str        = substr( $str, 75 );
149
          $output    .= ' '.chunk_split( $str, 74, $this->nl.' ' );
150
          if( ' ' == substr( $output, -1 ))
151
            $output   = rtrim( $output );
152
          if( $this->nl != substr( $output, ( 0 - strlen( $this->nl ))))
153
            $output  .= $this->nl;
154
          return $output;
155
        }
156
        $output    .= $this->_createElement( 'ATTACH', $attributes, $attachPart['value'] );
157
      }
158
      elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'ATTACH' );
159
    }
160
    return $output;
161
  }
162
/**
163
 * set calendar component property attach
164
 *
165
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
166
 * @since 2.16.21 - 2013-06-23
167
 * @param string  $value
168
 * @param array   $params
169
 * @param integer $index
170
 * @uses calendarComponent::$attach
171
 * @uses calendarComponent::getConfig()
172
 * @uses iCalUtilityFunctions::_setMval()
173
 * @return bool
174
 */
175
  function setAttach( $value, $params=FALSE, $index=FALSE ) {
176
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
177
    iCalUtilityFunctions::_setMval( $this->attach, $value, $params, FALSE, $index );
178
    return TRUE;
179
  }
180
/*********************************************************************************/
181
/**
182
 * Property Name: ATTENDEE
183
 */
184
/**
185
 * creates formatted output for calendar component property attendee
186
 *
187
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
188
 * @since 2.11.12 - 2012-01-31
189
 * @uses calendarComponent::$attendee
190
 * @uses calendarComponent::getConfig()
191
 * @uses calendarComponent::_createElement()
192
 * @uses calendarComponent::$intAttrDelimiter
193
 * @return string
194
 */
195
  function createAttendee() {
196
    if( empty( $this->attendee )) return FALSE;
197
    $output = null;
198
    foreach( $this->attendee as $attendeePart ) {                      // start foreach 1
199
      if( empty( $attendeePart['value'] )) {
200
        if( $this->getConfig( 'allowEmpty' ))
201
          $output .= $this->_createElement( 'ATTENDEE' );
202
        continue;
203
      }
204
      $attendee1 = $attendee2 = null;
205
      foreach( $attendeePart as $paramlabel => $paramvalue ) {         // start foreach 2
206
        if( 'value' == $paramlabel )
207
          $attendee2     .= $paramvalue;
208
        elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue ))) { // start elseif
209
          $mParams = array( 'MEMBER', 'DELEGATED-TO', 'DELEGATED-FROM' );
210
          foreach( $paramvalue as $pKey => $pValue ) {                 // fix (opt) quotes
211
            if( is_array( $pValue ) || in_array( $pKey, $mParams ))
212
              continue;
213
            if(( FALSE !== strpos( $pValue, ':' )) ||
214
               ( FALSE !== strpos( $pValue, ';' )) ||
215
               ( FALSE !== strpos( $pValue, ',' )))
216
              $paramvalue[$pKey] = '"'.$pValue.'"';
217
          }
218
        // set attenddee parameters in rfc2445 order
219
          if( isset( $paramvalue['CUTYPE'] ))
220
            $attendee1   .= $this->intAttrDelimiter.'CUTYPE='.$paramvalue['CUTYPE'];
221
          if( isset( $paramvalue['MEMBER'] )) {
222
            $attendee1   .= $this->intAttrDelimiter.'MEMBER=';
223
            foreach( $paramvalue['MEMBER'] as $cix => $opv )
224
              $attendee1 .= ( $cix ) ? ',"'.$opv.'"' : '"'.$opv.'"' ;
225
          }
226
          if( isset( $paramvalue['ROLE'] ))
227
            $attendee1   .= $this->intAttrDelimiter.'ROLE='.$paramvalue['ROLE'];
228
          if( isset( $paramvalue['PARTSTAT'] ))
229
            $attendee1   .= $this->intAttrDelimiter.'PARTSTAT='.$paramvalue['PARTSTAT'];
230
          if( isset( $paramvalue['RSVP'] ))
231
            $attendee1   .= $this->intAttrDelimiter.'RSVP='.$paramvalue['RSVP'];
232
          if( isset( $paramvalue['DELEGATED-TO'] )) {
233
            $attendee1   .= $this->intAttrDelimiter.'DELEGATED-TO=';
234
            foreach( $paramvalue['DELEGATED-TO'] as $cix => $opv )
235
              $attendee1 .= ( $cix ) ? ',"'.$opv.'"' : '"'.$opv.'"' ;
236
          }
237
          if( isset( $paramvalue['DELEGATED-FROM'] )) {
238
            $attendee1   .= $this->intAttrDelimiter.'DELEGATED-FROM=';
239
            foreach( $paramvalue['DELEGATED-FROM'] as $cix => $opv )
240
              $attendee1 .= ( $cix ) ? ',"'.$opv.'"' : '"'.$opv.'"' ;
241
          }
242
          if( isset( $paramvalue['SENT-BY'] ))
243
            $attendee1   .= $this->intAttrDelimiter.'SENT-BY='.$paramvalue['SENT-BY'];
244
          if( isset( $paramvalue['CN'] ))
245
            $attendee1   .= $this->intAttrDelimiter.'CN='.$paramvalue['CN'];
246
          if( isset( $paramvalue['DIR'] )) {
247
            $delim = ( FALSE === strpos( $paramvalue['DIR'], '"' )) ? '"' : '';
248
            $attendee1   .= $this->intAttrDelimiter.'DIR='.$delim.$paramvalue['DIR'].$delim;
249
          }
250
          if( isset( $paramvalue['LANGUAGE'] ))
251
            $attendee1   .= $this->intAttrDelimiter.'LANGUAGE='.$paramvalue['LANGUAGE'];
252
          $xparams = array();
253
          foreach( $paramvalue as $optparamlabel => $optparamvalue ) { // start foreach 3
254
            if( ctype_digit( (string) $optparamlabel )) {
255
              $xparams[]  = $optparamvalue;
256
              continue;
257
            }
258
            if( !in_array( $optparamlabel, array( 'CUTYPE', 'MEMBER', 'ROLE', 'PARTSTAT', 'RSVP', 'DELEGATED-TO', 'DELEGATED-FROM', 'SENT-BY', 'CN', 'DIR', 'LANGUAGE' )))
259
              $xparams[$optparamlabel] = $optparamvalue;
260
          } // end foreach 3
261
          ksort( $xparams, SORT_STRING );
262
          foreach( $xparams as $paramKey => $paramValue ) {
263
            if( ctype_digit( (string) $paramKey ))
264
              $attendee1 .= $this->intAttrDelimiter.$paramValue;
265
            else
266
              $attendee1 .= $this->intAttrDelimiter."$paramKey=$paramValue";
267
          }      // end foreach 3
268
        }        // end elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue )))
269
      }          // end foreach 2
270
      $output .= $this->_createElement( 'ATTENDEE', $attendee1, $attendee2 );
271
    }              // end foreach 1
272
    return $output;
273
  }
274
/**
275
 * set calendar component property attach
276
 *
277
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
278
 * @since 2.18.13 - 2013-09-22
279
 * @param string  $value
280
 * @param array   $params
281
 * @param integer $index
282
 * @uses calendarComponent::getConfig()
283
 * @uses calendarComponent::$objName
284
 * @uses iCalUtilityFunctions::_existRem()
285
 * @uses iCalUtilityFunctions::_setMval()
286
 * @return bool
287
 */
288
  function setAttendee( $value, $params=FALSE, $index=FALSE ) {
289
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
290
          // ftp://, http://, mailto:, file://, gopher://, news:, nntp://, telnet://, wais://, prospero://  may exist.. . also in params
291
    if( !empty( $value )) {
292
      if( FALSE === ( $pos = strpos( substr( $value, 0, 9 ), ':' )))
293
        $value = 'MAILTO:'.$value;
294
      elseif( !empty( $value ))
295
        $value = strtolower( substr( $value, 0, $pos )).substr( $value, $pos );
296
      $value = str_replace( 'mailto:', 'MAILTO:', $value );
297
    }
298
    $params2 = array();
299
    if( is_array($params )) {
300
      $optarrays = array();
301
      $params = array_change_key_case( $params, CASE_UPPER );
302
      foreach( $params as $optparamlabel => $optparamvalue ) {
303
        if(( 'X-' != substr( $optparamlabel, 0, 2 )) && (( 'vfreebusy' == $this->objName ) || ( 'valarm' == $this->objName )))
304
          continue;
305
        switch( $optparamlabel ) {
306
          case 'MEMBER':
307
          case 'DELEGATED-TO':
308
          case 'DELEGATED-FROM':
309
            if( !is_array( $optparamvalue ))
310
              $optparamvalue = array( $optparamvalue );
311
            foreach( $optparamvalue as $part ) {
312
              $part = trim( $part );
313
              if(( '"' == substr( $part, 0, 1 )) &&
314
                 ( '"' == substr( $part, -1 )))
315
                $part = substr( $part, 1, ( strlen( $part ) - 2 ));
316
              if( 'mailto:' != strtolower( substr( $part, 0, 7 )))
317
                $part = "MAILTO:$part";
318
              else
319
                $part = 'MAILTO:'.substr( $part, 7 );
320
              $optarrays[$optparamlabel][] = $part;
321
            }
322
            break;
323
          default:
324
            if(( '"' == substr( $optparamvalue, 0, 1 )) &&
325
               ( '"' == substr( $optparamvalue, -1 )))
326
              $optparamvalue = substr( $optparamvalue, 1, ( strlen( $optparamvalue ) - 2 ));
327
            if( 'SENT-BY' ==  $optparamlabel ) {
328
              if( 'mailto:' != strtolower( substr( $optparamvalue, 0, 7 )))
329
                $optparamvalue = "MAILTO:$optparamvalue";
330
              else
331
                $optparamvalue = 'MAILTO:'.substr( $optparamvalue, 7 );
332
            }
333
            $params2[$optparamlabel] = $optparamvalue;
334
            break;
335
        } // end switch( $optparamlabel.. .
336
      } // end foreach( $optparam.. .
337
      foreach( $optarrays as $optparamlabel => $optparams )
338
        $params2[$optparamlabel] = $optparams;
339
    }
340
        // remove defaults
341
    iCalUtilityFunctions::_existRem( $params2, 'CUTYPE',   'INDIVIDUAL' );
342
    iCalUtilityFunctions::_existRem( $params2, 'PARTSTAT', 'NEEDS-ACTION' );
343
    iCalUtilityFunctions::_existRem( $params2, 'ROLE',     'REQ-PARTICIPANT' );
344
    iCalUtilityFunctions::_existRem( $params2, 'RSVP',     'FALSE' );
345
        // check language setting
346
    if( isset( $params2['CN' ] )) {
347
      $lang = $this->getConfig( 'language' );
348
      if( !isset( $params2['LANGUAGE' ] ) && !empty( $lang ))
349
        $params2['LANGUAGE' ] = $lang;
350
    }
351
    iCalUtilityFunctions::_setMval( $this->attendee, $value, $params2, FALSE, $index );
352
    return TRUE;
353
  }
354
/*********************************************************************************/
355
/**
356
 * Property Name: CATEGORIES
357
 */
358
/**
359
 * creates formatted output for calendar component property categories
360
 *
361
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
362
 * @since 2.16.2 - 2012-12-18
363
 * @uses calendarComponent::$categories
364
 * @uses calendarComponent::_createElement()
365
 * @uses calendarComponent::_createParams()
366
 * @uses iCalUtilityFunctions::_strrep()
367
 * @uses calendarComponent::$format
368
 * @uses calendarComponent::$nl
369
 * @return string
370
 */
371
  function createCategories() {
372
    if( empty( $this->categories )) return FALSE;
373
    $output = null;
374
    foreach( $this->categories as $category ) {
375
      if( empty( $category['value'] )) {
376
        if ( $this->getConfig( 'allowEmpty' ))
377
          $output .= $this->_createElement( 'CATEGORIES' );
378
        continue;
379
      }
380
      $attributes = $this->_createParams( $category['params'], array( 'LANGUAGE' ));
381
      if( is_array( $category['value'] )) {
382
        foreach( $category['value'] as $cix => $categoryPart )
383
          $category['value'][$cix] = iCalUtilityFunctions::_strrep( $categoryPart, $this->format, $this->nl );
384
        $content  = implode( ',', $category['value'] );
385
      }
386
      else
387
        $content  = iCalUtilityFunctions::_strrep( $category['value'], $this->format, $this->nl );
388
      $output    .= $this->_createElement( 'CATEGORIES', $attributes, $content );
389
    }
390
    return $output;
391
  }
392
/**
393
 * set calendar component property categories
394
 *
395
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
396
 * @since 2.16.21 - 2013-06-23
397
 * @param mixed   $value
398
 * @param array   $params
399
 * @param integer $index
400
 * @uses calendarComponent::getConfig()
401
 * @uses calendarComponent::$categories
402
 * @uses iCalUtilityFunctions::_setMval()
403
 * @return bool
404
 */
405
  function setCategories( $value, $params=FALSE, $index=FALSE ) {
406
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
407
    iCalUtilityFunctions::_setMval( $this->categories, $value, $params, FALSE, $index );
408
    return TRUE;
409
 }
410
/*********************************************************************************/
411
/**
412
 * Property Name: CLASS
413
 */
414
/**
415
 * creates formatted output for calendar component property class
416
 *
417
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
418
 * @since 0.9.7 - 2006-11-20
419
 * @uses calendarComponent::$class
420
 * @uses calendarComponent::getConfig()
421
 * @uses calendarComponent::_createElement()
422
 * @uses calendarComponent::_createParams()
423
 * @return string
424
 */
425
  function createClass() {
426
    if( empty( $this->class )) return FALSE;
427
    if( empty( $this->class['value'] ))
428
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'CLASS' ) : FALSE;
429
    $attributes = $this->_createParams( $this->class['params'] );
430
    return $this->_createElement( 'CLASS', $attributes, $this->class['value'] );
431
  }
432
/**
433
 * set calendar component property class
434
 *
435
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
436
 * @since 2.16.21 - 2013-06-23
437
 * @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name
438
 * @param array  $params optional
439
 * @uses calendarComponent::getConfig()
440
 * @uses calendarComponent::$class
441
 * @uses iCalUtilityFunctions::_setParams()
442
 * @return bool
443
 */
444
  function setClass( $value, $params=FALSE ) {
445
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
446
    $this->class = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
447
    return TRUE;
448
  }
449
/*********************************************************************************/
450
/**
451
 * Property Name: COMMENT
452
 */
453
/**
454
 * creates formatted output for calendar component property comment
455
 *
456
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
457
 * @since 2.16.2 - 2012-12-18
458
 * @uses calendarComponent::$comment
459
 * @uses calendarComponent::getConfig()
460
 * @uses calendarComponent::_createElement()
461
 * @uses calendarComponent::_createParams()
462
 * @uses iCalUtilityFunctions::_strrep()
463
 * @uses calendarComponent::$format
464
 * @uses calendarComponent::$nl
465
 * @return string
466
 */
467
  function createComment() {
468
    if( empty( $this->comment )) return FALSE;
469
    $output = null;
470
    foreach( $this->comment as $commentPart ) {
471
      if( empty( $commentPart['value'] )) {
472
        if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'COMMENT' );
473
        continue;
474
      }
475
      $attributes = $this->_createParams( $commentPart['params'], array( 'ALTREP', 'LANGUAGE' ));
476
      $content    = iCalUtilityFunctions::_strrep( $commentPart['value'], $this->format, $this->nl );
477
      $output    .= $this->_createElement( 'COMMENT', $attributes, $content );
478
    }
479
    return $output;
480
  }
481
/**
482
 * set calendar component property comment
483
 *
484
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
485
 * @since 2.16.21 - 2013-06-23
486
 * @param string  $value
487
 * @param array   $params
488
 * @param integer $index
489
 * @uses calendarComponent::getConfig()
490
 * @uses iCalUtilityFunctions::_setMval()
491
 * @uses calendarComponent::$comment
492
 * @return bool
493
 */
494
  function setComment( $value, $params=FALSE, $index=FALSE ) {
495
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
496
    iCalUtilityFunctions::_setMval( $this->comment, $value, $params, FALSE, $index );
497
    return TRUE;
498
  }
499
/*********************************************************************************/
500
/**
501
 * Property Name: COMPLETED
502
 */
503
/**
504
 * creates formatted output for calendar component property completed
505
 *
506
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
507
 * @since 2.4.8 - 2008-10-22
508
 * @return string
509
 * @uses calendarComponent::$completed
510
 * @uses calendarComponent::getConfig()
511
 * @uses calendarComponent::_createElement()
512
 * @uses iCalUtilityFunctions::_date2strdate();
513
 * @uses calendarComponent::_createParams()
514
 */
515
  function createCompleted( ) {
516
    if( empty( $this->completed )) return FALSE;
517
    if( !isset( $this->completed['value']['year'] )  &&
518
        !isset( $this->completed['value']['month'] ) &&
519
        !isset( $this->completed['value']['day'] )   &&
520
        !isset( $this->completed['value']['hour'] )  &&
521
        !isset( $this->completed['value']['min'] )   &&
522
        !isset( $this->completed['value']['sec'] ))
523
      if( $this->getConfig( 'allowEmpty' ))
524
        return $this->_createElement( 'COMPLETED' );
525
      else return FALSE;
526
    $formatted  = iCalUtilityFunctions::_date2strdate( $this->completed['value'], 7 );
527
    $attributes = $this->_createParams( $this->completed['params'] );
528
    return $this->_createElement( 'COMPLETED', $attributes, $formatted );
529
  }
530
/**
531
 * set calendar component property completed
532
 *
533
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
534
 * @since 2.16.21 - 2013-06-23
535
 * @param mixed $year
536
 * @param mixed $month
537
 * @param int   $day
538
 * @param int   $hour
539
 * @param int   $min
540
 * @param int   $sec
541
 * @param array $params
542
 * @uses calendarComponent::getConfig()
543
 * @uses iCalUtilityFunctions::_setParams()
544
 * @uses calendarComponent::$completed
545
 * @uses iCalUtilityFunctions::_setDate2()
546
 * @return bool
547
 */
548
  function setCompleted( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
549
    if( empty( $year )) {
550
      if( $this->getConfig( 'allowEmpty' )) {
551
        $this->completed = array( 'value' => '', 'params' => iCalUtilityFunctions::_setParams( $params ));
552
        return TRUE;
553
      }
554
      else
555
        return FALSE;
556
    }
557
    $this->completed = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
558
    return TRUE;
559
  }
560
/*********************************************************************************/
561
/**
562
 * Property Name: CONTACT
563
 */
564
/**
565
 * creates formatted output for calendar component property contact
566
 *
567
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
568
 * @since 2.16.2 - 2012-12-18
569
 * @uses calendarComponent::$contact
570
 * @uses calendarComponent::_createParams()
571
 * @uses iCalUtilityFunctions::_strrep()
572
 * @uses calendarComponent::getConfig()
573
 * @uses calendarComponent::_createElement()
574
 * @return string
575
 */
576
  function createContact() {
577
    if( empty( $this->contact )) return FALSE;
578
    $output = null;
579
    foreach( $this->contact as $contact ) {
580
      if( !empty( $contact['value'] )) {
581
        $attributes = $this->_createParams( $contact['params'], array( 'ALTREP', 'LANGUAGE' ));
582
        $content    = iCalUtilityFunctions::_strrep( $contact['value'], $this->format, $this->nl );
583
        $output    .= $this->_createElement( 'CONTACT', $attributes, $content );
584
      }
585
      elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'CONTACT' );
586
    }
587
    return $output;
588
  }
589
/**
590
 * set calendar component property contact
591
 *
592
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
593
 * @since 2.16.21 - 2013-06-23
594
 * @param string  $value
595
 * @param array   $params
596
 * @param integer $index
597
 * @uses calendarComponent::getConfig()
598
 * @uses iCalUtilityFunctions::_setMval()
599
 * @uses calendarComponent::$contact
600
 * @return bool
601
 */
602
  function setContact( $value, $params=FALSE, $index=FALSE ) {
603
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
604
    iCalUtilityFunctions::_setMval( $this->contact, $value, $params, FALSE, $index );
605
    return TRUE;
606
  }
607
/*********************************************************************************/
608
/**
609
 * Property Name: CREATED
610
 */
611
/**
612
 * creates formatted output for calendar component property created
613
 *
614
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
615
 * @since 2.4.8 - 2008-10-21
616
 * @uses calendarComponent::$created
617
 * @uses iCalUtilityFunctions::_date2strdate()
618
 * @uses calendarComponent::_createParams()
619
 * @uses calendarComponent::_createElement()
620
 * @return string
621
 */
622
  function createCreated() {
623
    if( empty( $this->created )) return FALSE;
624
    $formatted  = iCalUtilityFunctions::_date2strdate( $this->created['value'], 7 );
625
    $attributes = $this->_createParams( $this->created['params'] );
626
    return $this->_createElement( 'CREATED', $attributes, $formatted );
627
  }
628
/**
629
 * set calendar component property created
630
 *
631
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
632
 * @since 2.19.5 - 2014-03-29
633
 * @param mixed $year
634
 * @param mixed $month
635
 * @param int   $day
636
 * @param int   $hour
637
 * @param int   $min
638
 * @param int   $sec
639
 * @param mixed $params
640
 * @uses calendarComponent::$created
641
 * @uses iCalUtilityFunctions::_setDate2()
642
 * @return bool
643
 */
644
  function setCreated( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
645
    if( !isset( $year ))
646
      $year = gmdate( 'Ymd\THis' );
647
    $this->created = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
648
    return TRUE;
649
  }
650
/*********************************************************************************/
651
/**
652
 * Property Name: DESCRIPTION
653
 */
654
/**
655
 * creates formatted output for calendar component property description
656
 *
657
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
658
 * @since 2.16.2 - 2012-12-18
659
 * @uses calendarComponent::$description
660
 * @uses calendarComponent::_createParams()
661
 * @uses iCalUtilityFunctions::_strrep()
662
 * @uses calendarComponent::_createElement()
663
 * @uses calendarComponent::getConfig()
664
 * @return string
665
 */
666
  function createDescription() {
667
    if( empty( $this->description )) return FALSE;
668
    $output       = null;
669
    foreach( $this->description as $description ) {
670
      if( !empty( $description['value'] )) {
671
        $attributes = $this->_createParams( $description['params'], array( 'ALTREP', 'LANGUAGE' ));
672
        $content    = iCalUtilityFunctions::_strrep( $description['value'], $this->format, $this->nl );
673
        $output    .= $this->_createElement( 'DESCRIPTION', $attributes, $content );
674
      }
675
      elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'DESCRIPTION' );
676
    }
677
    return $output;
678
  }
679
/**
680
 * set calendar component property description
681
 *
682
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
683
 * @since 2.16.21 - 2013-06-23
684
 * @param string  $value
685
 * @param array   $params
686
 * @param integer $index
687
 * @uses calendarComponent::getConfig()
688
 * @uses calendarComponent::$objName
689
 * @uses iCalUtilityFunctions::_setMval()
690
 * @uses calendarComponent::$description
691
 * @return bool
692
 */
693
  function setDescription( $value, $params=FALSE, $index=FALSE ) {
694
    if( empty( $value )) { if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE; }
695
    if( 'vjournal' != $this->objName )
696
      $index = 1;
697
    iCalUtilityFunctions::_setMval( $this->description, $value, $params, FALSE, $index );
698
    return TRUE;
699
  }
700
/*********************************************************************************/
701
/**
702
 * Property Name: DTEND
703
 */
704
/**
705
 * creates formatted output for calendar component property dtend
706
 *
707
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
708
 * @since 2.14.4 - 2012-09-26
709
 * @uses calendarComponent::$dtend
710
 * @uses calendarComponent::getConfig()
711
 * @uses iCalUtilityFunctions::_date2strdate()
712
 * @uses calendarComponent::_createParams()
713
 * @uses calendarComponent::_createElement()
714
 * @return string
715
 */
716
  function createDtend() {
717
    if( empty( $this->dtend )) return FALSE;
718
    if( !isset( $this->dtend['value']['year'] )  &&
719
        !isset( $this->dtend['value']['month'] ) &&
720
        !isset( $this->dtend['value']['day'] )   &&
721
        !isset( $this->dtend['value']['hour'] )  &&
722
        !isset( $this->dtend['value']['min'] )   &&
723
        !isset( $this->dtend['value']['sec'] ))
724
      if( $this->getConfig( 'allowEmpty' ))
725
        return $this->_createElement( 'DTEND' );
726
      else return FALSE;
727
    $parno      = ( isset( $this->dtend['params']['VALUE'] ) && ( 'DATE' == $this->dtend['params']['VALUE'] )) ? 3 : null;
728
    $formatted  = iCalUtilityFunctions::_date2strdate( $this->dtend['value'], $parno );
729
    $attributes = $this->_createParams( $this->dtend['params'] );
730
    return $this->_createElement( 'DTEND', $attributes, $formatted );
731
  }
732
/**
733
 * set calendar component property dtend
734
 *
735
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
736
 * @since 2.16.21 - 2013-06-23
737
 * @param mixed  $year
738
 * @param mixed  $month
739
 * @param int    $day
740
 * @param int    $hour
741
 * @param int    $min
742
 * @param int    $sec
743
 * @param string $tz
744
 * @param array  $params
745
 * @uses calendarComponent::getConfig()
746
 * @uses calendarComponent::$dtend
747
 * @uses iCalUtilityFunctions::_setParams()
748
 * @uses iCalUtilityFunctions::_setDate()
749
 * @return bool
750
 */
751
  function setDtend( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
752
    if( empty( $year )) {
753
      if( $this->getConfig( 'allowEmpty' )) {
754
        $this->dtend = array( 'value' => '', 'params' => iCalUtilityFunctions::_setParams( $params ));
755
        return TRUE;
756
      }
757
      else
758
        return FALSE;
759
    }
760
    $this->dtend = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
761
    return TRUE;
762
  }
763
/*********************************************************************************/
764
/**
765
 * Property Name: DTSTAMP
766
 */
767
/**
768
 * creates formatted output for calendar component property dtstamp
769
 *
770
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
771
 * @since 2.4.4 - 2008-03-07
772
 * @uses calendarComponent::$dtstamp
773
 * @uses calendarComponent::_makeDtstamp()
774
 * @uses iCalUtilityFunctions::_date2strdate()
775
 * @uses calendarComponent::_createParams()
776
 * @uses calendarComponent::_createElement()
777
 * @return string
778
 */
779
  function createDtstamp() {
780
    if( !isset( $this->dtstamp['value']['year'] )  &&
781
        !isset( $this->dtstamp['value']['month'] ) &&
782
        !isset( $this->dtstamp['value']['day'] )   &&
783
        !isset( $this->dtstamp['value']['hour'] )  &&
784
        !isset( $this->dtstamp['value']['min'] )   &&
785
        !isset( $this->dtstamp['value']['sec'] ))
786
      $this->_makeDtstamp();
787
    $formatted  = iCalUtilityFunctions::_date2strdate( $this->dtstamp['value'], 7 );
788
    $attributes = $this->_createParams( $this->dtstamp['params'] );
789
    return $this->_createElement( 'DTSTAMP', $attributes, $formatted );
790
  }
791
/**
792
 * computes datestamp for calendar component object instance dtstamp
793
 *
794
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
795
 * @since 2.21.11 - 2015-03-21
796
 * @uses iCalUtilityFunctions::$fmt
797
 * @uses calendarComponent::$dtstamp
798
 * @return void
799
 */
800
  function _makeDtstamp() {
801
    $d    = gmdate( iCalUtilityFunctions::$fmt['YmdHis3'], time());
802
    $date = explode( '-', $d );
803
    $this->dtstamp['value'] = array( 'year' => $date[0], 'month' => $date[1], 'day' => $date[2], 'hour' => $date[3], 'min' => $date[4], 'sec' => $date[5], 'tz' => 'Z' );
804
    $this->dtstamp['params'] = null;
805
  }
806
/**
807
 * set calendar component property dtstamp
808
 *
809
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
810
 * @since 2.4.8 - 2008-10-23
811
 * @param mixed $year
812
 * @param mixed $month
813
 * @param int   $day
814
 * @param int   $hour
815
 * @param int   $min
816
 * @param int   $sec
817
 * @param array $params
818
 * @uses calendarComponent::_makeDtstamp()
819
 * @uses calendarComponent::$dtstamp
820
 * @uses iCalUtilityFunctions::_setDate2()
821
 * @return TRUE
822
 */
823
  function setDtstamp( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
824
    if( empty( $year ))
825
      $this->_makeDtstamp();
826
    else
827
      $this->dtstamp = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
828
    return TRUE;
829
  }
830
/*********************************************************************************/
831
/**
832
 * Property Name: DTSTART
833
 */
834
/**
835
 * creates formatted output for calendar component property dtstart
836
 *
837
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
838
 * @since 2.14.4 - 2012-09-26
839
 * @uses calendarComponent::$dtstart
840
 * @uses calendarComponent::getConfig()
841
 * @uses calendarComponent::_createElement()
842
 * @uses iCalUtilityFunctions::_date2strdate()
843
 * @uses calendarComponent::_createParams()
844
 * @return string
845
 */
846
  function createDtstart() {
847
    if( empty( $this->dtstart )) return FALSE;
848
    if( !isset( $this->dtstart['value']['year'] )  &&
849
        !isset( $this->dtstart['value']['month'] ) &&
850
        !isset( $this->dtstart['value']['day'] )   &&
851
        !isset( $this->dtstart['value']['hour'] )  &&
852
        !isset( $this->dtstart['value']['min'] )   &&
853
        !isset( $this->dtstart['value']['sec'] )) {
854
      if( $this->getConfig( 'allowEmpty' ))
855
        return $this->_createElement( 'DTSTART' );
856
      else return FALSE;
857
    }
858
    if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' )))
859
       unset( $this->dtstart['value']['tz'], $this->dtstart['params']['TZID'] );
860
    $parno      = ( isset( $this->dtstart['params']['VALUE'] ) && ( 'DATE' == $this->dtstart['params']['VALUE'] )) ? 3 : null;
861
    $formatted  = iCalUtilityFunctions::_date2strdate( $this->dtstart['value'], $parno );
862
    $attributes = $this->_createParams( $this->dtstart['params'] );
863
    return $this->_createElement( 'DTSTART', $attributes, $formatted );
864
  }
865
/**
866
 * set calendar component property dtstart
867
 *
868
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
869
 * @since 2.16.21 - 2013-06-23
870
 * @param mixed  $year
871
 * @param mixed  $month
872
 * @param int    $day
873
 * @param int    $hour
874
 * @param int    $min
875
 * @param int    $sec
876
 * @param string $tz
877
 * @param array  $params
878
 * @uses calendarComponent::getConfig()
879
 * @uses iCalUtilityFunctions::_setParams()
880
 * @uses calendarComponent::$dtstart
881
 * @uses iCalUtilityFunctions::_setDate()
882
 * @return bool
883
 */
884
  function setDtstart( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
885
    if( empty( $year )) {
886
      if( $this->getConfig( 'allowEmpty' )) {
887
        $this->dtstart = array( 'value' => '', 'params' => iCalUtilityFunctions::_setParams( $params ));
888
        return TRUE;
889
      }
890
      else
891
        return FALSE;
892
    }
893
    $this->dtstart = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart', $this->objName, $this->getConfig( 'TZID' ));
894
    return TRUE;
895
  }
896
/*********************************************************************************/
897
/**
898
 * Property Name: DUE
899
 */
900
/**
901
 * creates formatted output for calendar component property due
902
 *
903
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
904
 * @since 2.14.4 - 2012-09-26
905
 * @uses calendarComponent::$due
906
 * @uses calendarComponent::getConfig()
907
 * @uses calendarComponent::_createElement()
908
 * @uses iCalUtilityFunctions::_date2strdate()
909
 * @uses calendarComponent::_createParams()
910
 * @return string
911
 */
912
  function createDue() {
913
    if( empty( $this->due )) return FALSE;
914
    if( !isset( $this->due['value']['year'] )  &&
915
        !isset( $this->due['value']['month'] ) &&
916
        !isset( $this->due['value']['day'] )   &&
917
        !isset( $this->due['value']['hour'] )  &&
918
        !isset( $this->due['value']['min'] )   &&
919
        !isset( $this->due['value']['sec'] )) {
920
      if( $this->getConfig( 'allowEmpty' ))
921
        return $this->_createElement( 'DUE' );
922
      else
923
       return FALSE;
924
    }
925
    $parno      = ( isset( $this->due['params']['VALUE'] ) && ( 'DATE' == $this->due['params']['VALUE'] )) ? 3 : null;
926
    $formatted  = iCalUtilityFunctions::_date2strdate( $this->due['value'], $parno );
927
    $attributes = $this->_createParams( $this->due['params'] );
928
    return $this->_createElement( 'DUE', $attributes, $formatted );
929
  }
930
/**
931
 * set calendar component property due
932
 *
933
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
934
 * @since 2.16.21 - 2013-06-23
935
 * @param mixed  $year
936
 * @param mixed  $month
937
 * @param int    $day
938
 * @param int    $hour
939
 * @param int    $min
940
 * @param int    $sec
941
 * @param string $tz
942
 * @param array  $params
943
 * @uses calendarComponent::getConfig()
944
 * @uses calendarComponent::$due
945
 * @uses iCalUtilityFunctions::_setParams()
946
 * @uses iCalUtilityFunctions::_setDate()
947
 * @return bool
948
 */
949
  function setDue( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
950
    if( empty( $year )) {
951
      if( $this->getConfig( 'allowEmpty' )) {
952
        $this->due = array( 'value' => '', 'params' => iCalUtilityFunctions::_setParams( $params ));
953
        return TRUE;
954
      }
955
      else
956
        return FALSE;
957
    }
958
    $this->due = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
959
    return TRUE;
960
  }
961
/*********************************************************************************/
962
/**
963
 * Property Name: DURATION
964
 */
965
/**
966
 * creates formatted output for calendar component property duration
967
 *
968
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
969
 * @since 2.16.21 - 2013-05-25
970
 * @uses calendarComponent::$duration
971
 * @uses calendarComponent::getConfig()
972
 * @uses calendarComponent::_createElement()
973
 * @uses calendarComponent::_createParams()
974
 * @uses iCalUtilityFunctions::_duration2str()
975
 * @return string
976
 */
977
  function createDuration() {
978
    if( empty( $this->duration )) return FALSE;
979
    if( !isset( $this->duration['value']['week'] ) &&
980
        !isset( $this->duration['value']['day'] )  &&
981
        !isset( $this->duration['value']['hour'] ) &&
982
        !isset( $this->duration['value']['min'] )  &&
983
        !isset( $this->duration['value']['sec'] ))
984
      if( $this->getConfig( 'allowEmpty' ))
985
        return $this->_createElement( 'DURATION' );
986
      else return FALSE;
987
    $attributes = $this->_createParams( $this->duration['params'] );
988
    return $this->_createElement( 'DURATION', $attributes, iCalUtilityFunctions::_duration2str( $this->duration['value'] ));
989
  }
990
/**
991
 * set calendar component property duration
992
 *
993
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
994
 * @since 2.16.21 - 2013-05-25
995
 * @param mixed $week
996
 * @param mixed $day
997
 * @param int   $hour
998
 * @param int   $min
999
 * @param int   $sec
1000
 * @param array $params
1001
 * @uses calendarComponent::getConfig()
1002
 * @uses calendarComponent::$duration
1003
 * @uses iCalUtilityFunctions::_duration2arr()
1004
 * @uses iCalUtilityFunctions::_durationStr2arr()
1005
 * @uses iCalUtilityFunctions::_setParams()
1006
 * @uses iCalUtilityFunctions::_duration2arr()
1007
 * @return bool
1008
 */
1009
  function setDuration( $week, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1010
    if( empty( $week ) && empty( $day ) && empty( $hour ) && empty( $min ) && empty( $sec )) {
1011
      if( $this->getConfig( 'allowEmpty' ))
1012
        $week = $day = null;
1013
      else
1014
        return FALSE;
1015
    }
1016
    if( is_array( $week ) && ( 1 <= count( $week )))
1017
      $this->duration = array( 'value' => iCalUtilityFunctions::_duration2arr( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
1018
    elseif( is_string( $week ) && ( 3 <= strlen( trim( $week )))) {
1019
      $week = trim( $week );
1020
      if( in_array( substr( $week, 0, 1 ), array( '+', '-' )))
1021
        $week = substr( $week, 1 );
1022
      $this->duration = array( 'value' => iCalUtilityFunctions::_durationStr2arr( $week ), 'params' => iCalUtilityFunctions::_setParams( $day ));
1023
    }
1024
    else
1025
      $this->duration = array( 'value' => iCalUtilityFunctions::_duration2arr( array( 'week' => $week, 'day' => $day, 'hour' => $hour, 'min' => $min, 'sec' => $sec ))
1026
                             , 'params' => iCalUtilityFunctions::_setParams( $params ));
1027
    return TRUE;
1028
  }
1029
/*********************************************************************************/
1030
/**
1031
 * Property Name: EXDATE
1032
 */
1033
/**
1034
 * creates formatted output for calendar component property exdate
1035
 *
1036
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1037
 * @since 2.16.5 - 2012-12-28
1038
 * @uses calendarComponent::$exdate
1039
 * @uses calendarComponent::getConfig()
1040
 * @uses calendarComponent::_createElement()
1041
 * @uses iCalUtilityFunctions::_sortExdate1()
1042
 * @uses iCalUtilityFunctions::_sortExdate2()
1043
 * @uses iCalUtilityFunctions::_date2strdate()
1044
 * @uses calendarComponent::_createParams()
1045
 * @return string
1046
 */
1047
  function createExdate() {
1048
    if( empty( $this->exdate )) return FALSE;
1049
    $output  = null;
1050
    $exdates = array();
1051
    foreach( $this->exdate as $theExdate ) {
1052
      if( empty( $theExdate['value'] )) {
1053
        if( $this->getConfig( 'allowEmpty' ))
1054
          $output .= $this->_createElement( 'EXDATE' );
1055
        continue;
1056
      }
1057
      if( 1 < count( $theExdate['value'] ))
1058
        usort( $theExdate['value'], array( 'iCalUtilityFunctions', '_sortExdate1' ));
1059
      $exdates[] = $theExdate;
1060
    }
1061
    if( 1 < count( $exdates ))
1062
      usort( $exdates, array( 'iCalUtilityFunctions', '_sortExdate2' ));
1063
    foreach( $exdates as $theExdate ) {
1064
      $content = $attributes = null;
1065
      foreach( $theExdate['value'] as $eix => $exdatePart ) {
1066
        $parno = count( $exdatePart );
1067
        $formatted = iCalUtilityFunctions::_date2strdate( $exdatePart, $parno );
1068
        if( isset( $theExdate['params']['TZID'] ))
1069
          $formatted = str_replace( 'Z', '', $formatted);
1070
        if( 0 < $eix ) {
1071
          if( isset( $theExdate['value'][0]['tz'] )) {
1072
            if( ctype_digit( substr( $theExdate['value'][0]['tz'], -4 )) ||
1073
               ( 'Z' == $theExdate['value'][0]['tz'] )) {
1074
              if( 'Z' != substr( $formatted, -1 ))
1075
                $formatted .= 'Z';
1076
            }
1077
            else
1078
              $formatted = str_replace( 'Z', '', $formatted );
1079
          }
1080
          else
1081
            $formatted = str_replace( 'Z', '', $formatted );
1082
        } // end if( 0 < $eix )
1083
        $content .= ( 0 < $eix ) ? ','.$formatted : $formatted;
1084
      } // end foreach( $theExdate['value'] as $eix => $exdatePart )
1085
      $attributes .= $this->_createParams( $theExdate['params'] );
1086
      $output .= $this->_createElement( 'EXDATE', $attributes, $content );
1087
    } // end foreach( $exdates as $theExdate )
1088
    return $output;
1089
  }
1090
/**
1091
 * set calendar component property exdate
1092
 *
1093
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1094
 * @since 2.21.11 - 2015-03-10
1095
 * @param array   $exdates
1096
 * @param array   $params
1097
 * @param integer $index
1098
 * @uses calendarComponent::getConfig()
1099
 * @uses iCalUtilityFunctions::_setMval()
1100
 * @uses calendarComponent::$exdate
1101
 * @uses iCalUtilityFunctions::_setParams()
1102
 * @uses iCalUtilityFunctions::_chkdatecfg()
1103
 * @uses iCalUtilityFunctions::_existRem()
1104
 * @uses iCalUtilityFunctions::_strDate2arr()
1105
 * @uses iCalUtilityFunctions::_isArrayTimestampDate()
1106
 * @uses iCalUtilityFunctions::_isOffset()
1107
 * @uses iCalUtilityFunctions::_timestamp2date()
1108
 * @uses iCalUtilityFunctions::_chkDateArr()
1109
 * @uses iCalUtilityFunctions::$fmt
1110
 * @uses iCalUtilityFunctions::_strdate2date()
1111
 * @return bool
1112
 */
1113
  function setExdate( $exdates, $params=FALSE, $index=FALSE ) {
1114
    if( empty( $exdates )) {
1115
      if( $this->getConfig( 'allowEmpty' )) {
1116
        iCalUtilityFunctions::_setMval( $this->exdate, '', $params, FALSE, $index );
1117
        return TRUE;
1118
      }
1119
      else
1120
        return FALSE;
1121
    }
1122
    $input  = array( 'params' => iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
1123
    $toZ = ( isset( $input['params']['TZID'] ) && in_array( strtoupper( $input['params']['TZID'] ), array( 'GMT', 'UTC', 'Z' ))) ? TRUE : FALSE;
1124
            /* ev. check 1:st date and save ev. timezone **/
1125
    iCalUtilityFunctions::_chkdatecfg( reset( $exdates ), $parno, $input['params'] );
1126
    iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default parameter
1127
    foreach( $exdates as $eix => $theExdate ) {
1128
      iCalUtilityFunctions::_strDate2arr( $theExdate );
1129
      if( iCalUtilityFunctions::_isArrayTimestampDate( $theExdate )) {
1130
        if( isset( $theExdate['tz'] ) && !iCalUtilityFunctions::_isOffset( $theExdate['tz'] )) {
1131
          if( isset( $input['params']['TZID'] ))
1132
            $theExdate['tz'] = $input['params']['TZID'];
1133
          else
1134
            $input['params']['TZID'] = $theExdate['tz'];
1135
        }
1136
        $exdatea = iCalUtilityFunctions::_timestamp2date( $theExdate, $parno );
1137
      }
1138
      elseif(  is_array( $theExdate )) {
1139
        $d = iCalUtilityFunctions::_chkDateArr( $theExdate, $parno );
1140
        if( isset( $d['tz'] ) && ( 'Z' != $d['tz'] ) && iCalUtilityFunctions::_isOffset( $d['tz'] )) {
1141
          $strdate = sprintf( iCalUtilityFunctions::$fmt['YmdHise'], (int) $d['year'], (int) $d['month'], (int) $d['day'], (int) $d['hour'], (int) $d['min'], (int) $d['sec'], $d['tz'] );
1142
          $exdatea = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
1143
          unset( $exdatea['unparsedtext'] );
1144
        }
1145
        else
1146
          $exdatea = $d;
1147
      }
1148
      elseif( 8 <= strlen( trim( $theExdate ))) { // ex. 2006-08-03 10:12:18
1149
        $exdatea = iCalUtilityFunctions::_strdate2date( $theExdate, $parno );
1150
        unset( $exdatea['unparsedtext'] );
1151
      }
1152
      if( 3 == $parno )
1153
        unset( $exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz'] );
1154
      elseif( isset( $exdatea['tz'] ))
1155
        $exdatea['tz'] = (string) $exdatea['tz'];
1156
      if(  isset( $input['params']['TZID'] ) ||
1157
         ( isset( $exdatea['tz'] ) && !iCalUtilityFunctions::_isOffset( $exdatea['tz'] )) ||
1158
         ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))) ||
1159
         ( isset( $input['value'][0]['tz'] ) && !iCalUtilityFunctions::_isOffset( $input['value'][0]['tz'] )))
1160
        unset( $exdatea['tz'] );
1161
      if( $toZ ) // time zone Z
1162
        $exdatea['tz'] = 'Z';
1163
      $input['value'][] = $exdatea;
1164
    }
1165
    if( 0 >= count( $input['value'] ))
1166
      return FALSE;
1167
    if( 3 == $parno ) {
1168
      $input['params']['VALUE'] = 'DATE';
1169
      unset( $input['params']['TZID'] );
1170
    }
1171
    if( $toZ ) // time zone Z
1172
      unset( $input['params']['TZID'] );
1173
    iCalUtilityFunctions::_setMval( $this->exdate, $input['value'], $input['params'], FALSE, $index );
1174
    return TRUE;
1175
  }
1176
/*********************************************************************************/
1177
/**
1178
 * Property Name: EXRULE
1179
 */
1180
/**
1181
 * creates formatted output for calendar component property exrule
1182
 *
1183
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1184
 * @since 2.4.8 - 2008-10-22
1185
 * @uses calendarComponent::$exrule
1186
 * @uses calendarComponent::_format_recur()
1187
 * @return string
1188
 */
1189
  function createExrule() {
1190
    if( empty( $this->exrule )) return FALSE;
1191
    return $this->_format_recur( 'EXRULE', $this->exrule );
1192
  }
1193
/**
1194
 * set calendar component property exdate
1195
 *
1196
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1197
 * @since 2.16.21 - 2013-06-23
1198
 * @param array   $exruleset
1199
 * @param array   $params
1200
 * @param integer $index
1201
 * @uses calendarComponent::getConfig()
1202
 * @uses iCalUtilityFunctions::_setMval()
1203
 * @uses calendarComponent::$exrule
1204
 * @uses iCalUtilityFunctions::_setRexrule()
1205
 * @return bool
1206
 */
1207
  function setExrule( $exruleset, $params=FALSE, $index=FALSE ) {
1208
    if( empty( $exruleset )) if( $this->getConfig( 'allowEmpty' )) $exruleset = ''; else return FALSE;
1209
    iCalUtilityFunctions::_setMval( $this->exrule, iCalUtilityFunctions::_setRexrule( $exruleset ), $params, FALSE, $index );
1210
    return TRUE;
1211
  }
1212
/*********************************************************************************/
1213
/**
1214
 * Property Name: FREEBUSY
1215
 */
1216
/**
1217
 * creates formatted output for calendar component property freebusy
1218
 *
1219
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1220
 * @since 2.16.27 - 2013-07-05
1221
 * @uses calendarComponent::$freebusy
1222
 * @uses calendarComponent::getConfig()
1223
 * @uses calendarComponent::_createElement()
1224
 * @uses calendarComponent::$intAttrDelimiter
1225
 * @uses calendarComponent::_createParams()
1226
 * @uses iCalUtilityFunctions::_sortRdate1()
1227
 * @uses iCalUtilityFunctions::_date2strdate()
1228
 * @uses iCalUtilityFunctions::_duration2str()
1229
 * @return string
1230
 */
1231
  function createFreebusy() {
1232
    if( empty( $this->freebusy )) return FALSE;
1233
    $output = null;
1234
    foreach( $this->freebusy as $freebusyPart ) {
1235
      if( empty( $freebusyPart['value'] ) || (( 1 == count( $freebusyPart['value'] )) && isset( $freebusyPart['value']['fbtype'] ))) {
1236
        if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'FREEBUSY' );
1237
        continue;
1238
      }
1239
      $attributes = $content = null;
1240
      if( isset( $freebusyPart['value']['fbtype'] )) {
1241
          $attributes .= $this->intAttrDelimiter.'FBTYPE='.$freebusyPart['value']['fbtype'];
1242
        unset( $freebusyPart['value']['fbtype'] );
1243
        $freebusyPart['value'] = array_values( $freebusyPart['value'] );
1244
      }
1245
      else
1246
        $attributes .= $this->intAttrDelimiter.'FBTYPE=BUSY';
1247
      $attributes .= $this->_createParams( $freebusyPart['params'] );
1248
      $fno = 1;
1249
      $cnt = count( $freebusyPart['value']);
1250
      if( 1 < $cnt )
1251
        usort( $freebusyPart['value'], array( 'iCalUtilityFunctions', '_sortRdate1' ));
1252
      foreach( $freebusyPart['value'] as $periodix => $freebusyPeriod ) {
1253
        $formatted   = iCalUtilityFunctions::_date2strdate( $freebusyPeriod[0] );
1254
        $content .= $formatted;
1255
        $content .= '/';
1256
        $cnt2 = count( $freebusyPeriod[1]);
1257
        if( array_key_exists( 'year', $freebusyPeriod[1] ))      // date-time
1258
          $cnt2 = 7;
1259
        elseif( array_key_exists( 'week', $freebusyPeriod[1] ))  // duration
1260
          $cnt2 = 5;
1261
        if(( 7 == $cnt2 )   &&    // period=  -> date-time
1262
            isset( $freebusyPeriod[1]['year'] )  &&
1263
            isset( $freebusyPeriod[1]['month'] ) &&
1264
            isset( $freebusyPeriod[1]['day'] )) {
1265
          $content .= iCalUtilityFunctions::_date2strdate( $freebusyPeriod[1] );
1266
        }
1267
        else {                                  // period=  -> dur-time
1268
          $content .= iCalUtilityFunctions::_duration2str( $freebusyPeriod[1] );
1269
        }
1270
        if( $fno < $cnt )
1271
          $content .= ',';
1272
        $fno++;
1273
      }
1274
      $output .= $this->_createElement( 'FREEBUSY', $attributes, $content );
1275
    }
1276
    return $output;
1277
  }
1278
/**
1279
 * set calendar component property freebusy
1280
 *
1281
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1282
 * @since 2.16.21 - 2013-06-23
1283
 * @param string  $fbType
1284
 * @param array   $fbValues
1285
 * @param array   $params
1286
 * @param integer $index
1287
 * @uses calendarComponent::getConfig()
1288
 * @uses calendarComponent::$freebusy
1289
 * @uses iCalUtilityFunctions::_isArrayDate()
1290
 * @uses iCalUtilityFunctions::_setMval()
1291
 * @uses iCalUtilityFunctions::_chkDateArr()
1292
 * @uses iCalUtilityFunctions::_isArrayTimestampDate()
1293
 * @uses iCalUtilityFunctions::_timestamp2date()
1294
 * @uses iCalUtilityFunctions::_duration2arr()
1295
 * @uses iCalUtilityFunctions::_durationStr2arr()
1296
 * @uses iCalUtilityFunctions::_strdate2date()
1297
 * @return bool
1298
 */
1299
  function setFreebusy( $fbType, $fbValues, $params=FALSE, $index=FALSE ) {
1300
    if( empty( $fbValues )) {
1301
      if( $this->getConfig( 'allowEmpty' )) {
1302
        iCalUtilityFunctions::_setMval( $this->freebusy, '', $params, FALSE, $index );
1303
        return TRUE;
1304
      }
1305
      else
1306
        return FALSE;
1307
    }
1308
    $fbType = strtoupper( $fbType );
1309
    if(( !in_array( $fbType, array( 'FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE' ))) &&
1310
       ( 'X-' != substr( $fbType, 0, 2 )))
1311
      $fbType = 'BUSY';
1312
    $input = array( 'fbtype' => $fbType );
1313
    foreach( $fbValues as $fbPeriod ) {   // periods => period
1314
      if( empty( $fbPeriod ))
1315
        continue;
1316
      $freebusyPeriod = array();
1317
      foreach( $fbPeriod as $fbMember ) { // pairs => singlepart
1318
        $freebusyPairMember = array();
1319
        if( is_array( $fbMember )) {
1320
          if( iCalUtilityFunctions::_isArrayDate( $fbMember )) { // date-time value
1321
            $freebusyPairMember       = iCalUtilityFunctions::_chkDateArr( $fbMember, 7 );
1322
            $freebusyPairMember['tz'] = 'Z';
1323
          }
1324
          elseif( iCalUtilityFunctions::_isArrayTimestampDate( $fbMember )) { // timestamp value
1325
            $freebusyPairMember       = iCalUtilityFunctions::_timestamp2date( $fbMember['timestamp'], 7 );
1326
            $freebusyPairMember['tz'] = 'Z';
1327
          }
1328
          else {                                         // array format duration
1329
            $freebusyPairMember = iCalUtilityFunctions::_duration2arr( $fbMember );
1330
          }
1331
        }
1332
        elseif(( 3 <= strlen( trim( $fbMember ))) &&    // string format duration
1333
               ( in_array( $fbMember{0}, array( 'P', '+', '-' )))) {
1334
          if( 'P' != $fbMember{0} )
1335
            $fbmember = substr( $fbMember, 1 );
1336
          $freebusyPairMember = iCalUtilityFunctions::_durationStr2arr( $fbMember );
1337
        }
1338
        elseif( 8 <= strlen( trim( $fbMember ))) { // text date ex. 2006-08-03 10:12:18
1339
          $freebusyPairMember       = iCalUtilityFunctions::_strdate2date( $fbMember, 7 );
1340
          unset( $freebusyPairMember['unparsedtext'] );
1341
          $freebusyPairMember['tz'] = 'Z';
1342
        }
1343
        $freebusyPeriod[]   = $freebusyPairMember;
1344
      }
1345
      $input[]              = $freebusyPeriod;
1346
    }
1347
    iCalUtilityFunctions::_setMval( $this->freebusy, $input, $params, FALSE, $index );
1348
    return TRUE;
1349
  }
1350
/*********************************************************************************/
1351
/**
1352
 * Property Name: GEO
1353
 */
1354
/**
1355
 * creates formatted output for calendar component property geo
1356
 *
1357
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1358
 * @since 2.18.10 - 2013-09-03
1359
 * @uses calendarComponent::$geo
1360
 * @uses calendarComponent::getConfig()
1361
 * @uses calendarComponent::_createElement()
1362
 * @uses calendarComponent::_createParams()
1363
 * @uses iCalUtilityFunctions::_geo2str2()
1364
 * @uses iCalUtilityFunctions::$geoLongFmt
1365
 * @uses iCalUtilityFunctions::$geoLatFmt
1366
 * @return string
1367
 */
1368
  function createGeo() {
1369
    if( empty( $this->geo )) return FALSE;
1370
    if( empty( $this->geo['value'] ))
1371
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'GEO' ) : FALSE;
1372
    return $this->_createElement( 'GEO', $this->_createParams( $this->geo['params'] ),
1373
                                  iCalUtilityFunctions::_geo2str2( $this->geo['value']['latitude'],  iCalUtilityFunctions::$geoLatFmt ).
1374
                              ';'.iCalUtilityFunctions::_geo2str2( $this->geo['value']['longitude'], iCalUtilityFunctions::$geoLongFmt ));
1375
  }
1376
/**
1377
 * set calendar component property geo
1378
 *
1379
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1380
 * @since 2.18.10 - 2013-09-03
1381
 * @param mixed $latitude
1382
 * @param mixed $longitude
1383
 * @param array $params
1384
 * @uses calendarComponent::$geo
1385
 * @uses iCalUtilityFunctions::_setParams()
1386
 * @uses calendarComponent::getConfig()
1387
 * @return bool
1388
 */
1389
  function setGeo( $latitude, $longitude, $params=FALSE ) {
1390
    if( isset( $latitude ) && isset( $longitude )) {
1391
      if( !is_array( $this->geo )) $this->geo = array();
1392
      $this->geo['value']['latitude']  = floatval( $latitude );
1393
      $this->geo['value']['longitude'] = floatval( $longitude );
1394
      $this->geo['params'] = iCalUtilityFunctions::_setParams( $params );
1395
    }
1396
    elseif( $this->getConfig( 'allowEmpty' ))
1397
      $this->geo = array( 'value' => '', 'params' => iCalUtilityFunctions::_setParams( $params ) );
1398
    else
1399
      return FALSE;
1400
    return TRUE;
1401
  }
1402
/*********************************************************************************/
1403
/**
1404
 * Property Name: LAST-MODIFIED
1405
 */
1406
/**
1407
 * creates formatted output for calendar component property last-modified
1408
 *
1409
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1410
 * @since 2.4.8 - 2008-10-21
1411
 * @uses calendarComponent::$lastmodified
1412
 * @uses calendarComponent::_createParams()
1413
 * @uses iCalUtilityFunctions::_date2strdate()
1414
 * @uses calendarComponent::_createElement()
1415
 * @return string
1416
 */
1417
  function createLastModified() {
1418
    if( empty( $this->lastmodified )) return FALSE;
1419
    $attributes = $this->_createParams( $this->lastmodified['params'] );
1420
    $formatted  = iCalUtilityFunctions::_date2strdate( $this->lastmodified['value'], 7 );
1421
    return $this->_createElement( 'LAST-MODIFIED', $attributes, $formatted );
1422
  }
1423
/**
1424
 * set calendar component property completed
1425
 *
1426
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1427
 * @since 2.19.5 - 2014-03-29
1428
 * @param mixed $year optional
1429
 * @param mixed $month optional
1430
 * @param int $day optional
1431
 * @param int $hour optional
1432
 * @param int $min optional
1433
 * @param int $sec optional
1434
 * @param array $params optional
1435
 * @uses calendarComponent::$lastmodified
1436
 * @uses iCalUtilityFunctions::_setDate2()
1437
 * @return boll
1438
 */
1439
  function setLastModified( $year=FALSE, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $params=FALSE ) {
1440
    if( empty( $year ))
1441
      $year = gmdate( 'Ymd\THis' );
1442
    $this->lastmodified = iCalUtilityFunctions::_setDate2( $year, $month, $day, $hour, $min, $sec, $params );
1443
    return TRUE;
1444
  }
1445
/*********************************************************************************/
1446
/**
1447
 * Property Name: LOCATION
1448
 */
1449
/**
1450
 * creates formatted output for calendar component property location
1451
 *
1452
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1453
 * @since 2.16.2 - 2012-12-18
1454
 * @uses calendarComponent::$location
1455
 * @uses calendarComponent::getConfig()
1456
 * @uses calendarComponent::_createElement()
1457
 * @uses calendarComponent::_createParams()
1458
 * @uses iCalUtilityFunctions::_strrep()
1459
 * @return string
1460
 */
1461
  function createLocation() {
1462
    if( empty( $this->location )) return FALSE;
1463
    if( empty( $this->location['value'] ))
1464
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'LOCATION' ) : FALSE;
1465
    $attributes = $this->_createParams( $this->location['params'], array( 'ALTREP', 'LANGUAGE' ));
1466
    $content    = iCalUtilityFunctions::_strrep( $this->location['value'], $this->format, $this->nl );
1467
    return $this->_createElement( 'LOCATION', $attributes, $content );
1468
  }
1469
/**
1470
 * set calendar component property location
1471
 '
1472
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1473
 * @since 2.16.21 - 2013-06-23
1474
 * @param string  $value
1475
 * @param array   $params
1476
 * @uses calendarComponent::$location
1477
 * @uses calendarComponent::getConfig()
1478
 * @uses iCalUtilityFunctions::_setParams()
1479
 * @return bool
1480
 */
1481
  function setLocation( $value, $params=FALSE ) {
1482
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
1483
    $this->location = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
1484
    return TRUE;
1485
  }
1486
/*********************************************************************************/
1487
/**
1488
 * Property Name: ORGANIZER
1489
 */
1490
/**
1491
 * creates formatted output for calendar component property organizer
1492
 *
1493
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1494
 * @since 2.6.33 - 2010-12-17
1495
 * @uses calendarComponent::$organizer
1496
 * @uses calendarComponent::getConfig()
1497
 * @uses calendarComponent::_createElement()
1498
 * @uses calendarComponent::_createParams()
1499
 * @return string
1500
 */
1501
  function createOrganizer() {
1502
    if( empty( $this->organizer )) return FALSE;
1503
    if( empty( $this->organizer['value'] ))
1504
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'ORGANIZER' ) : FALSE;
1505
    $attributes = $this->_createParams( $this->organizer['params']
1506
                                      , array( 'CN', 'DIR', 'SENT-BY', 'LANGUAGE' ));
1507
    return $this->_createElement( 'ORGANIZER', $attributes, $this->organizer['value'] );
1508
  }
1509
/**
1510
 * set calendar component property organizer
1511
 *
1512
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1513
 * @since 2.16.21 - 2013-06-23
1514
 * @param string  $value
1515
 * @param array   $params
1516
 * @uses calendarComponent::getConfig()
1517
 * @uses calendarComponent::$organizer
1518
 * @uses iCalUtilityFunctions::_setParams()
1519
 * @return bool
1520
 */
1521
  function setOrganizer( $value, $params=FALSE ) {
1522
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
1523
    if( !empty( $value )) {
1524
      if( FALSE === ( $pos = strpos( substr( $value, 0, 9 ), ':' )))
1525
        $value = 'MAILTO:'.$value;
1526
      elseif( !empty( $value ))
1527
        $value = strtolower( substr( $value, 0, $pos )).substr( $value, $pos );
1528
      $value = str_replace( 'mailto:', 'MAILTO:', $value );
1529
    }
1530
    $this->organizer = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
1531
    if( isset( $this->organizer['params']['SENT-BY'] )){
1532
      if( 'mailto:' !== strtolower( substr( $this->organizer['params']['SENT-BY'], 0, 7 )))
1533
        $this->organizer['params']['SENT-BY'] = 'MAILTO:'.$this->organizer['params']['SENT-BY'];
1534
      else
1535
        $this->organizer['params']['SENT-BY'] = 'MAILTO:'.substr( $this->organizer['params']['SENT-BY'], 7 );
1536
    }
1537
    return TRUE;
1538
  }
1539
/*********************************************************************************/
1540
/**
1541
 * Property Name: PERCENT-COMPLETE
1542
 */
1543
/**
1544
 * creates formatted output for calendar component property percent-complete
1545
 *
1546
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1547
 * @since 2.9.3 - 2011-05-14
1548
 * @uses calendarComponent::$percentcomplete
1549
 * @uses calendarComponent::getConfig()
1550
 * @uses calendarComponent::_createElement()
1551
 * @uses calendarComponent::_createParams()
1552
 * @return string
1553
 */
1554
  function createPercentComplete() {
1555
    if( !isset($this->percentcomplete) || ( empty( $this->percentcomplete ) && !is_numeric( $this->percentcomplete ))) return FALSE;
1556
    if( !isset( $this->percentcomplete['value'] ) || ( empty( $this->percentcomplete['value'] ) && !is_numeric( $this->percentcomplete['value'] )))
1557
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PERCENT-COMPLETE' ) : FALSE;
1558
    $attributes = $this->_createParams( $this->percentcomplete['params'] );
1559
    return $this->_createElement( 'PERCENT-COMPLETE', $attributes, $this->percentcomplete['value'] );
1560
  }
1561
/**
1562
 * set calendar component property percent-complete
1563
 *
1564
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1565
 * @since 2.16.21 - 2013-06-23
1566
 * @param int    $value
1567
 * @param array  $params
1568
 * @uses calendarComponent::$percentcomplete
1569
 * @uses calendarComponent::getConfig()
1570
 * @uses iCalUtilityFunctions::_setParams()
1571
 * @return bool
1572
 */
1573
  function setPercentComplete( $value, $params=FALSE ) {
1574
    if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
1575
    $this->percentcomplete = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
1576
    return TRUE;
1577
  }
1578
/*********************************************************************************/
1579
/**
1580
 * Property Name: PRIORITY
1581
 */
1582
/**
1583
 * creates formatted output for calendar component property priority
1584
 *
1585
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1586
 * @since 2.9.3 - 2011-05-14
1587
 * @uses calendarComponent::$priority
1588
 * @uses calendarComponent::getConfig()
1589
 * @uses calendarComponent::_createElement()
1590
 * @uses calendarComponent::_createParams()
1591
 * @return string
1592
 */
1593
  function createPriority() {
1594
    if( !isset($this->priority) || ( empty( $this->priority ) && !is_numeric( $this->priority ))) return FALSE;
1595
    if( !isset( $this->priority['value'] ) || ( empty( $this->priority['value'] ) && !is_numeric( $this->priority['value'] )))
1596
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'PRIORITY' ) : FALSE;
1597
    $attributes = $this->_createParams( $this->priority['params'] );
1598
    return $this->_createElement( 'PRIORITY', $attributes, $this->priority['value'] );
1599
  }
1600
/**
1601
 * set calendar component property priority
1602
 *
1603
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1604
 * @since 2.16.21 - 2013-06-23
1605
 * @param int    $value
1606
 * @param array  $params
1607
 * @uses calendarComponent::getConfig()
1608
 * @uses calendarComponent::$priority
1609
 * @uses iCalUtilityFunctions::_setParams()
1610
 * @return bool
1611
 */
1612
  function setPriority( $value, $params=FALSE  ) {
1613
    if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
1614
    $this->priority = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
1615
    return TRUE;
1616
  }
1617
/*********************************************************************************/
1618
/**
1619
 * Property Name: RDATE
1620
 */
1621
/**
1622
 * creates formatted output for calendar component property rdate
1623
 *
1624
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1625
 * @since 2.16.9 - 2013-01-09
1626
 * @uses calendarComponent::$rdate
1627
 * @uses calendarComponent::$objName
1628
 * @uses calendarComponent::getConfig()
1629
 * @uses calendarComponent::_createElement()
1630
 * @uses iCalUtilityFunctions::_sortRdate1()
1631
 * @uses iCalUtilityFunctions::_sortRdate2()
1632
 * @uses calendarComponent::_createParams()
1633
 * @uses iCalUtilityFunctions::_date2strdate()
1634
 * @return string
1635
 */
1636
  function createRdate() {
1637
    if( empty( $this->rdate )) return FALSE;
1638
    $utctime = ( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) ? TRUE : FALSE;
1639
    $output = null;
1640
    $rdates = array();
1641
    foreach( $this->rdate as $rpix => $theRdate ) {
1642
      if( empty( $theRdate['value'] )) {
1643
        if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RDATE' );
1644
        continue;
1645
      }
1646
      if( $utctime  )
1647
        unset( $theRdate['params']['TZID'] );
1648
      if( 1 < count( $theRdate['value'] ))
1649
        usort( $theRdate['value'], array( 'iCalUtilityFunctions', '_sortRdate1' ));
1650
      $rdates[] = $theRdate;
1651
    }
1652
    if( 1 < count( $rdates ))
1653
      usort( $rdates, array( 'iCalUtilityFunctions', '_sortRdate2' ));
1654
    foreach( $rdates as $rpix => $theRdate ) {
1655
      $attributes = $this->_createParams( $theRdate['params'] );
1656
      $cnt = count( $theRdate['value'] );
1657
      $content = null;
1658
      $rno = 1;
1659
      foreach( $theRdate['value'] as $rix => $rdatePart ) {
1660
        $contentPart = null;
1661
        if( is_array( $rdatePart ) &&
1662
            isset( $theRdate['params']['VALUE'] ) && ( 'PERIOD' == $theRdate['params']['VALUE'] )) { // PERIOD
1663
          if( $utctime )
1664
            unset( $rdatePart[0]['tz'] );
1665
          $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart[0] ); // PERIOD part 1
1666
          if( $utctime || !empty( $theRdate['params']['TZID'] ))
1667
            $formatted = str_replace( 'Z', '', $formatted);
1668
          $contentPart .= $formatted;
1669
          $contentPart .= '/';
1670
          $cnt2 = count( $rdatePart[1]);
1671
          if( array_key_exists( 'year', $rdatePart[1] )) {
1672
            if( array_key_exists( 'hour', $rdatePart[1] ))
1673
              $cnt2 = 7;                                      // date-time
1674
            else
1675
              $cnt2 = 3;                                      // date
1676
          }
1677
          elseif( array_key_exists( 'week', $rdatePart[1] ))  // duration
1678
            $cnt2 = 5;
1679
          if(( 7 == $cnt2 )   &&    // period=  -> date-time
1680
              isset( $rdatePart[1]['year'] )  &&
1681
              isset( $rdatePart[1]['month'] ) &&
1682
              isset( $rdatePart[1]['day'] )) {
1683
            if( $utctime )
1684
              unset( $rdatePart[1]['tz'] );
1685
            $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart[1] ); // PERIOD part 2
1686
            if( $utctime || !empty( $theRdate['params']['TZID'] ))
1687
              $formatted = str_replace( 'Z', '', $formatted );
1688
           $contentPart .= $formatted;
1689
          }
1690
          else {                                  // period=  -> dur-time
1691
            $contentPart .= iCalUtilityFunctions::_duration2str( $rdatePart[1] );
1692
          }
1693
        } // PERIOD end
1694
        else { // SINGLE date start
1695
          if( $utctime )
1696
            unset( $rdatePart['tz'] );
1697
          $parno = ( isset( $theRdate['params']['VALUE'] ) && ( 'DATE' == isset( $theRdate['params']['VALUE'] ))) ? 3 : null;
1698
          $formatted = iCalUtilityFunctions::_date2strdate( $rdatePart, $parno );
1699
          if( $utctime || !empty( $theRdate['params']['TZID'] ))
1700
            $formatted = str_replace( 'Z', '', $formatted);
1701
          $contentPart .= $formatted;
1702
        }
1703
        $content .= $contentPart;
1704
        if( $rno < $cnt )
1705
          $content .= ',';
1706
        $rno++;
1707
      }
1708
      $output    .= $this->_createElement( 'RDATE', $attributes, $content );
1709
    }
1710
    return $output;
1711
  }
1712
/**
1713
 * set calendar component property rdate
1714
 *
1715
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1716
 * @since 2.21.11 - 2015-03-10
1717
 * @param array   $rdates
1718
 * @param array   $params
1719
 * @param integer $index
1720
 * @uses calendarComponent::getConfig()
1721
 * @uses iCalUtilityFunctions::_setMval()
1722
 * @uses calendarComponent::$rdate
1723
 * @uses iCalUtilityFunctions::_setParams()
1724
 * @uses calendarComponent::$objName
1725
 * @uses iCalUtilityFunctions::_isArrayDate()
1726
 * @uses iCalUtilityFunctions::_chkdatecfg()
1727
 * @uses iCalUtilityFunctions::_existRem()
1728
 * @uses iCalUtilityFunctions::_strDate2arr()
1729
 * @uses iCalUtilityFunctions::_isArrayTimestampDate()
1730
 * @uses iCalUtilityFunctions::_isOffset()
1731
 * @uses iCalUtilityFunctions::_timestamp2date()
1732
 * @uses iCalUtilityFunctions::_chkDateArr()
1733
 * @uses iCalUtilityFunctions::$fmt
1734
 * @uses iCalUtilityFunctions::_strdate2date()
1735
 * @uses iCalUtilityFunctions::_duration2arr()
1736
 * @uses iCalUtilityFunctions::_durationStr2arr()
1737
 * @return bool
1738
 */
1739
  function setRdate( $rdates, $params=FALSE, $index=FALSE ) {
1740
    if( empty( $rdates )) {
1741
      if( $this->getConfig( 'allowEmpty' )) {
1742
        iCalUtilityFunctions::_setMval( $this->rdate, '', $params, FALSE, $index );
1743
        return TRUE;
1744
      }
1745
      else
1746
        return FALSE;
1747
    }
1748
    $input = array( 'params' => iCalUtilityFunctions::_setParams( $params, array( 'VALUE' => 'DATE-TIME' )));
1749
    if( in_array( $this->objName, array( 'vtimezone', 'standard', 'daylight' ))) {
1750
      unset( $input['params']['TZID'] );
1751
      $input['params']['VALUE'] = 'DATE-TIME';
1752
    }
1753
    $zArr = array( 'GMT', 'UTC', 'Z' );
1754
    $toZ = ( isset( $params['TZID'] ) && in_array( strtoupper( $params['TZID'] ), $zArr )) ? TRUE : FALSE;
1755
            /*  check if PERIOD, if not set */
1756
    if((!isset( $input['params']['VALUE'] ) || !in_array( $input['params']['VALUE'], array( 'DATE', 'PERIOD' ))) &&
1757
          isset( $rdates[0] )    && is_array( $rdates[0] ) && ( 2 == count( $rdates[0] )) &&
1758
          isset( $rdates[0][0] ) &&    isset( $rdates[0][1] ) && !isset( $rdates[0]['timestamp'] ) &&
1759
    (( is_array( $rdates[0][0] ) && ( isset( $rdates[0][0]['timestamp'] ) ||
1760
                                      iCalUtilityFunctions::_isArrayDate( $rdates[0][0] ))) ||
1761
                                    ( is_string( $rdates[0][0] ) && ( 8 <= strlen( trim( $rdates[0][0] )))))  &&
1762
     ( is_array( $rdates[0][1] ) || ( is_string( $rdates[0][1] ) && ( 3 <= strlen( trim( $rdates[0][1] ))))))
1763
      $input['params']['VALUE'] = 'PERIOD';
1764
            /* check 1:st date, upd. $parno (opt) and save ev. timezone **/
1765
    $date  = reset( $rdates );
1766
    if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) // PERIOD
1767
      $date  = reset( $date );
1768
    iCalUtilityFunctions::_chkdatecfg( $date, $parno, $input['params'] );
1769
    iCalUtilityFunctions::_existRem( $input['params'], 'VALUE', 'DATE-TIME' ); // remove default
1770
    foreach( $rdates as $rpix => $theRdate ) {
1771
      $inputa = null;
1772
      iCalUtilityFunctions::_strDate2arr( $theRdate );
1773
      if( is_array( $theRdate )) {
1774
        if( isset( $input['params']['VALUE'] ) && ( 'PERIOD' == $input['params']['VALUE'] )) { // PERIOD
1775
          foreach( $theRdate as $rix => $rPeriod ) {
1776
            iCalUtilityFunctions::_strDate2arr( $theRdate );
1777
            if( is_array( $rPeriod )) {
1778
              if( iCalUtilityFunctions::_isArrayTimestampDate( $rPeriod )) {    // timestamp
1779
                if( isset( $rPeriod['tz'] ) && !iCalUtilityFunctions::_isOffset( $rPeriod['tz'] )) {
1780
                  if( isset( $input['params']['TZID'] ))
1781
                    $rPeriod['tz'] = $input['params']['TZID'];
1782
                  else
1783
                    $input['params']['TZID'] = $rPeriod['tz'];
1784
                }
1785
                $inputab = iCalUtilityFunctions::_timestamp2date( $rPeriod, $parno );
1786
              }
1787
              elseif( iCalUtilityFunctions::_isArrayDate( $rPeriod )) {
1788
                $d = ( 3 < count ( $rPeriod )) ? iCalUtilityFunctions::_chkDateArr( $rPeriod, $parno ) : iCalUtilityFunctions::_chkDateArr( $rPeriod, 6 );
1789
                if( isset( $d['tz'] ) && ( 'Z' != $d['tz'] ) && iCalUtilityFunctions::_isOffset( $d['tz'] )) {
1790
                  $strdate = sprintf( iCalUtilityFunctions::$fmt['YmdHise'], (int) $d['year'], (int) $d['month'], (int) $d['day'], (int) $d['hour'], (int) $d['min'], (int) $d['sec'], $d['tz'] );
1791
                  $inputab = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
1792
                  unset( $inputab['unparsedtext'] );
1793
                }
1794
                else
1795
                  $inputab = $d;
1796
              }
1797
              elseif (( 1 == count( $rPeriod )) && ( 8 <= strlen( reset( $rPeriod )))) { // text-date
1798
                $inputab   = iCalUtilityFunctions::_strdate2date( reset( $rPeriod ), $parno );
1799
                unset( $inputab['unparsedtext'] );
1800
              }
1801
              else                                               // array format duration
1802
                $inputab   = iCalUtilityFunctions::_duration2arr( $rPeriod );
1803
            }
1804
            elseif(( 3 <= strlen( trim( $rPeriod ))) &&          // string format duration
1805
                   ( in_array( $rPeriod[0], array( 'P', '+', '-' )))) {
1806
              if( 'P' != $rPeriod[0] )
1807
                $rPeriod   = substr( $rPeriod, 1 );
1808
              $inputab     = iCalUtilityFunctions::_durationStr2arr( $rPeriod );
1809
            }
1810
            elseif( 8 <= strlen( trim( $rPeriod ))) {            // text date ex. 2006-08-03 10:12:18
1811
              $inputab     = iCalUtilityFunctions::_strdate2date( $rPeriod, $parno );
1812
              unset( $inputab['unparsedtext'] );
1813
            }
1814
            if(( 0 == $rpix ) && ( 0 == $rix )) {
1815
              if( isset( $inputab['tz'] ) && in_array( strtoupper( $inputab['tz'] ), $zArr )) {
1816
                $inputab['tz'] = 'Z';
1817
                $toZ = TRUE;
1818
              }
1819
            }
1820
            else {
1821
              if( isset( $inputa[0]['tz'] ) && ( 'Z' == $inputa[0]['tz'] ) && isset( $inputab['year'] ))
1822
                $inputab['tz'] = 'Z';
1823
              else
1824
                unset( $inputab['tz'] );
1825
            }
1826
            if( $toZ && isset( $inputab['year'] ) )
1827
              $inputab['tz'] = 'Z';
1828
            $inputa[]      = $inputab;
1829
          }
1830
        } // PERIOD end
1831
        elseif ( iCalUtilityFunctions::_isArrayTimestampDate( $theRdate )) {    // timestamp
1832
          if( isset( $theRdate['tz'] ) && !iCalUtilityFunctions::_isOffset( $theRdate['tz'] )) {
1833
            if( isset( $input['params']['TZID'] ))
1834
              $theRdate['tz'] = $input['params']['TZID'];
1835
            else
1836
              $input['params']['TZID'] = $theRdate['tz'];
1837
          }
1838
          $inputa = iCalUtilityFunctions::_timestamp2date( $theRdate, $parno );
1839
        }
1840
        else {                                                                  // date[-time]
1841
          $inputa = iCalUtilityFunctions::_chkDateArr( $theRdate, $parno );
1842
          if( isset( $inputa['tz'] ) && ( 'Z' != $inputa['tz'] ) && iCalUtilityFunctions::_isOffset( $inputa['tz'] )) {
1843
            $strdate = sprintf( iCalUtilityFunctions::$fmt['YmdHise'], (int) $inputa['year'], (int) $inputa['month'], (int) $inputa['day'], (int) $inputa['hour'], (int) $inputa['min'], (int) $inputa['sec'], $inputa['tz'] );
1844
            $inputa  = iCalUtilityFunctions::_strdate2date( $strdate, 7 );
1845
            unset( $inputa['unparsedtext'] );
1846
          }
1847
        }
1848
      }
1849
      elseif( 8 <= strlen( trim( $theRdate ))) {                 // text date ex. 2006-08-03 10:12:18
1850
        $inputa       = iCalUtilityFunctions::_strdate2date( $theRdate, $parno );
1851
        unset( $inputa['unparsedtext'] );
1852
        if( $toZ )
1853
          $inputa['tz'] = 'Z';
1854
      }
1855
      if( !isset( $input['params']['VALUE'] ) || ( 'PERIOD' != $input['params']['VALUE'] )) { // no PERIOD
1856
        if(( 0 == $rpix ) && !$toZ )
1857
          $toZ = ( isset( $inputa['tz'] ) && in_array( strtoupper( $inputa['tz'] ), $zArr )) ? TRUE : FALSE;
1858
        if( $toZ )
1859
          $inputa['tz']    = 'Z';
1860
        if( 3 == $parno )
1861
          unset( $inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz'] );
1862
        elseif( isset( $inputa['tz'] ))
1863
          $inputa['tz']    = (string) $inputa['tz'];
1864
        if( isset( $input['params']['TZID'] ) || ( isset( $input['value'][0] ) && ( !isset( $input['value'][0]['tz'] ))))
1865
          if( !$toZ )
1866
            unset( $inputa['tz'] );
1867
      }
1868
      $input['value'][]    = $inputa;
1869
    }
1870
    if( 3 == $parno ) {
1871
      $input['params']['VALUE'] = 'DATE';
1872
      unset( $input['params']['TZID'] );
1873
    }
1874
    if( $toZ )
1875
      unset( $input['params']['TZID'] );
1876
    iCalUtilityFunctions::_setMval( $this->rdate, $input['value'], $input['params'], FALSE, $index );
1877
    return TRUE;
1878
  }
1879
/*********************************************************************************/
1880
/**
1881
 * Property Name: RECURRENCE-ID
1882
 */
1883
/**
1884
 * creates formatted output for calendar component property recurrence-id
1885
 *
1886
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1887
 * @since 2.14.4 - 2012-09-26
1888
 * @uses calendarComponent::$recurrenceid
1889
 * @uses calendarComponent::getConfig()
1890
 * @uses calendarComponent::_createElement()
1891
 * @uses iCalUtilityFunctions::_date2strdate()
1892
 * @uses calendarComponent::_createParams()
1893
 * @return string
1894
 */
1895
  function createRecurrenceid() {
1896
    if( empty( $this->recurrenceid )) return FALSE;
1897
    if( empty( $this->recurrenceid['value'] ))
1898
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'RECURRENCE-ID' ) : FALSE;
1899
    $parno      = ( isset( $this->recurrenceid['params']['VALUE'] ) && ( 'DATE' == $this->recurrenceid['params']['VALUE'] )) ? 3 : null;
1900
    $formatted  = iCalUtilityFunctions::_date2strdate( $this->recurrenceid['value'], $parno );
1901
    $attributes = $this->_createParams( $this->recurrenceid['params'] );
1902
    return $this->_createElement( 'RECURRENCE-ID', $attributes, $formatted );
1903
  }
1904
/**
1905
 * set calendar component property recurrence-id
1906
 *
1907
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1908
 * @since 2.16.21 - 2013-06-23
1909
 * @param mixed   $year
1910
 * @param mixed   $month
1911
 * @param int     $day
1912
 * @param int     $hour
1913
 * @param int     $min
1914
 * @param int     $sec
1915
 * @param string  $tz
1916
 * @param array   $params
1917
 * @uses calendarComponent::getConfig()
1918
 * @uses calendarComponent::$recurrenceid
1919
 * @uses iCalUtilityFunctions::_setDate()
1920
 * @return bool
1921
 */
1922
  function setRecurrenceid( $year, $month=FALSE, $day=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $tz=FALSE, $params=FALSE ) {
1923
    if( empty( $year )) {
1924
      if( $this->getConfig( 'allowEmpty' )) {
1925
        $this->recurrenceid = array( 'value' => '', 'params' => null );
1926
        return TRUE;
1927
      }
1928
      else
1929
        return FALSE;
1930
    }
1931
    $this->recurrenceid = iCalUtilityFunctions::_setDate( $year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig( 'TZID' ));
1932
    return TRUE;
1933
  }
1934
/*********************************************************************************/
1935
/**
1936
 * Property Name: RELATED-TO
1937
 */
1938
/**
1939
 * creates formatted output for calendar component property related-to
1940
 *
1941
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1942
 * @since 2.16.21 - 2013-05-25
1943
 * @uses calendarComponent::$relatedto
1944
 * @uses calendarComponent::_createElement()
1945
 * @uses calendarComponent::_createParams()
1946
 * @uses iCalUtilityFunctions::_strrep()
1947
 * @uses calendarComponent::getConfig()
1948
 * @return string
1949
 */
1950
  function createRelatedTo() {
1951
    if( empty( $this->relatedto )) return FALSE;
1952
    $output = null;
1953
    foreach( $this->relatedto as $relation ) {
1954
      if( !empty( $relation['value'] ))
1955
        $output .= $this->_createElement( 'RELATED-TO', $this->_createParams( $relation['params'] ), iCalUtilityFunctions::_strrep( $relation['value'], $this->format, $this->nl ));
1956
      elseif( $this->getConfig( 'allowEmpty' ))
1957
        $output .= $this->_createElement( 'RELATED-TO' );
1958
    }
1959
    return $output;
1960
  }
1961
/**
1962
 * set calendar component property related-to
1963
 *
1964
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1965
 * @since 2.16.21 - 2013-06-23
1966
 * @param string  $value
1967
 * @param array   $params
1968
 * @param int     $index
1969
 * @uses calendarComponent::getConfig()
1970
 * @uses iCalUtilityFunctions::_existRem()
1971
 * @uses iCalUtilityFunctions::_setMval()
1972
 * @return bool
1973
 */
1974
  function setRelatedTo( $value, $params=FALSE, $index=FALSE ) {
1975
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
1976
    iCalUtilityFunctions::_existRem( $params, 'RELTYPE', 'PARENT', TRUE ); // remove default
1977
    iCalUtilityFunctions::_setMval( $this->relatedto, $value, $params, FALSE, $index );
1978
    return TRUE;
1979
  }
1980
/*********************************************************************************/
1981
/**
1982
 * Property Name: REPEAT
1983
 */
1984
/**
1985
 * creates formatted output for calendar component property repeat
1986
 *
1987
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
1988
 * @since 2.9.3 - 2011-05-14
1989
 * @uses calendarComponent::$repeat
1990
 * @uses calendarComponent::getConfig()
1991
 * @uses calendarComponent::_createElement()
1992
 * @uses calendarComponent::_createParams()
1993
 * @return string
1994
 */
1995
  function createRepeat() {
1996
    if( !isset( $this->repeat ) || ( empty( $this->repeat ) && !is_numeric( $this->repeat ))) return FALSE;
1997
    if( !isset( $this->repeat['value']) || ( empty( $this->repeat['value'] ) && !is_numeric( $this->repeat['value'] )))
1998
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'REPEAT' ) : FALSE;
1999
    $attributes = $this->_createParams( $this->repeat['params'] );
2000
    return $this->_createElement( 'REPEAT', $attributes, $this->repeat['value'] );
2001
  }
2002
/**
2003
 * set calendar component property repeat
2004
 *
2005
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2006
 * @since 2.16.21 - 2013-06-23
2007
 * @param string  $value
2008
 * @param array   $params
2009
 * @uses calendarComponent::getConfig()
2010
 * @uses calendarComponent::$repeat
2011
 * @uses iCalUtilityFunctions::_setParams()
2012
 * @return void
2013
 */
2014
  function setRepeat( $value, $params=FALSE ) {
2015
    if( empty( $value ) && !is_numeric( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2016
    $this->repeat = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2017
    return TRUE;
2018
  }
2019
/*********************************************************************************/
2020
/**
2021
 * Property Name: REQUEST-STATUS
2022
 */
2023
/**
2024
 * creates formatted output for calendar component property request-status
2025
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2026
 * @since 2.16.2 - 2012-12-18
2027
 * @uses calendarComponent::$requeststatus
2028
 * @uses calendarComponent::getConfig()
2029
 * @uses calendarComponent::_createElement()
2030
 * @uses calendarComponent::_createParams()
2031
 * @uses iCalUtilityFunctions::_strrep()
2032
 * @return string
2033
 */
2034
  function createRequestStatus() {
2035
    if( empty( $this->requeststatus )) return FALSE;
2036
    $output = null;
2037
    foreach( $this->requeststatus as $rstat ) {
2038
      if( empty( $rstat['value']['statcode'] )) {
2039
        if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'REQUEST-STATUS' );
2040
        continue;
2041
      }
2042
      $attributes  = $this->_createParams( $rstat['params'], array( 'LANGUAGE' ));
2043
      $content     = number_format( (float) $rstat['value']['statcode'], 2, '.', '');
2044
      $content    .= ';'.iCalUtilityFunctions::_strrep( $rstat['value']['text'], $this->format, $this->nl );
2045
      if( isset( $rstat['value']['extdata'] ))
2046
        $content  .= ';'.iCalUtilityFunctions::_strrep( $rstat['value']['extdata'], $this->format, $this->nl );
2047
      $output     .= $this->_createElement( 'REQUEST-STATUS', $attributes, $content );
2048
    }
2049
    return $output;
2050
  }
2051
/**
2052
 * set calendar component property request-status
2053
 *
2054
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2055
 * @since 2.16.21 - 2013-06-23
2056
 * @param float    $statcode
2057
 * @param string   $text
2058
 * @param string   $extdata
2059
 * @param array    $params
2060
 * @param integer  $index
2061
 * @uses calendarComponent::getConfig()
2062
 * @uses calendarComponent::$requeststatus
2063
 * @uses iCalUtilityFunctions::_setMval()
2064
 * @return bool
2065
 */
2066
  function setRequestStatus( $statcode, $text, $extdata=FALSE, $params=FALSE, $index=FALSE ) {
2067
    if( empty( $statcode ) || empty( $text )) if( $this->getConfig( 'allowEmpty' )) $statcode = $text = ''; else return FALSE;
2068
    $input              = array( 'statcode' => $statcode, 'text' => $text );
2069
    if( $extdata )
2070
      $input['extdata'] = $extdata;
2071
    iCalUtilityFunctions::_setMval( $this->requeststatus, $input, $params, FALSE, $index );
2072
    return TRUE;
2073
  }
2074
/*********************************************************************************/
2075
/**
2076
 * Property Name: RESOURCES
2077
 */
2078
/**
2079
 * creates formatted output for calendar component property resources
2080
 *
2081
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2082
 * @since 2.16.2 - 2012-12-18
2083
 * @uses calendarComponent::$resources
2084
 * @uses calendarComponent::getConfig()
2085
 * @uses calendarComponent::_createElement()
2086
 * @uses calendarComponent::_createParams()
2087
 * @uses iCalUtilityFunctions::_strrep()
2088
 * @return string
2089
 */
2090
  function createResources() {
2091
    if( empty( $this->resources )) return FALSE;
2092
    $output = null;
2093
    foreach( $this->resources as $resource ) {
2094
      if( empty( $resource['value'] )) {
2095
        if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'RESOURCES' );
2096
        continue;
2097
      }
2098
      $attributes  = $this->_createParams( $resource['params'], array( 'ALTREP', 'LANGUAGE' ));
2099
      if( is_array( $resource['value'] )) {
2100
        foreach( $resource['value'] as $rix => $resourcePart )
2101
          $resource['value'][$rix] = iCalUtilityFunctions::_strrep( $resourcePart, $this->format, $this->nl );
2102
        $content   = implode( ',', $resource['value'] );
2103
      }
2104
      else
2105
        $content   = iCalUtilityFunctions::_strrep( $resource['value'], $this->format, $this->nl );
2106
      $output     .= $this->_createElement( 'RESOURCES', $attributes, $content );
2107
    }
2108
    return $output;
2109
  }
2110
/**
2111
 * set calendar component property recources
2112
 *
2113
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2114
 * @since 2.16.21 - 2013-06-23
2115
 * @param mixed    $value
2116
 * @param array    $params
2117
 * @param integer  $index
2118
 * @uses calendarComponent::getConfig()
2119
 * @uses iCalUtilityFunctions::_setMval()
2120
 * @uses calendarComponent::$resources
2121
 * @return bool
2122
 */
2123
  function setResources( $value, $params=FALSE, $index=FALSE ) {
2124
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2125
    iCalUtilityFunctions::_setMval( $this->resources, $value, $params, FALSE, $index );
2126
    return TRUE;
2127
  }
2128
/*********************************************************************************/
2129
/**
2130
 * Property Name: RRULE
2131
 */
2132
/**
2133
 * creates formatted output for calendar component property rrule
2134
 *
2135
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2136
 * @since 2.4.8 - 2008-10-21
2137
 * @uses calendarComponent::$rrule
2138
 * @uses calendarComponent::_format_recur()
2139
 * @return string
2140
 */
2141
  function createRrule() {
2142
    if( empty( $this->rrule )) return FALSE;
2143
    return $this->_format_recur( 'RRULE', $this->rrule );
2144
  }
2145
/**
2146
 * set calendar component property rrule
2147
 *
2148
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2149
 * @since 2.16.21 - 2013-06-23
2150
 * @param array    $rruleset
2151
 * @param array    $params
2152
 * @param integer  $index
2153
 * @uses calendarComponent::getConfig()
2154
 * @uses iCalUtilityFunctions::_setMval()
2155
 * @uses iCalUtilityFunctions::_setRexrule()
2156
 * @return void
2157
 */
2158
  function setRrule( $rruleset, $params=FALSE, $index=FALSE ) {
2159
    if( empty( $rruleset )) if( $this->getConfig( 'allowEmpty' )) $rruleset = ''; else return FALSE;
2160
    iCalUtilityFunctions::_setMval( $this->rrule, iCalUtilityFunctions::_setRexrule( $rruleset ), $params, FALSE, $index );
2161
    return TRUE;
2162
  }
2163
/*********************************************************************************/
2164
/**
2165
 * Property Name: SEQUENCE
2166
 */
2167
/**
2168
 * creates formatted output for calendar component property sequence
2169
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2170
 * @since 2.9.3 - 2011-05-14
2171
 * @uses calendarComponent::$sequence
2172
 * @uses calendarComponent::getConfig()
2173
 * @uses calendarComponent::_createElement()
2174
 * @uses calendarComponent::_createParams()
2175
 * @return string
2176
 */
2177
  function createSequence() {
2178
    if( !isset( $this->sequence ) || ( empty( $this->sequence ) && !is_numeric( $this->sequence ))) return FALSE;
2179
    if(( !isset($this->sequence['value'] ) || ( empty( $this->sequence['value'] ) && !is_numeric( $this->sequence['value'] ))) &&
2180
       ( '0' != $this->sequence['value'] ))
2181
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SEQUENCE' ) : FALSE;
2182
    $attributes = $this->_createParams( $this->sequence['params'] );
2183
    return $this->_createElement( 'SEQUENCE', $attributes, $this->sequence['value'] );
2184
  }
2185
/**
2186
 * set calendar component property sequence
2187
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2188
 * @since 2.10.8 - 2011-09-19
2189
 * @param int    $value
2190
 * @param array  $params
2191
 * @uses calendarComponent::$sequence
2192
 * @uses iCalUtilityFunctions::_setParams();
2193
 * @return bool
2194
 */
2195
  function setSequence( $value=FALSE, $params=FALSE ) {
2196
    if(( empty( $value ) && !is_numeric( $value )) && ( '0' != $value ))
2197
      $value = ( isset( $this->sequence['value'] ) && ( -1 < $this->sequence['value'] )) ? $this->sequence['value'] + 1 : '0';
2198
    $this->sequence = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2199
    return TRUE;
2200
  }
2201
/*********************************************************************************/
2202
/**
2203
 * Property Name: STATUS
2204
 */
2205
/**
2206
 * creates formatted output for calendar component property status
2207
 *
2208
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2209
 * @since 2.4.8 - 2008-10-21
2210
 * @uses calendarComponent::$status
2211
 * @uses calendarComponent::getConfig()
2212
 * @uses calendarComponent::_createElement()
2213
 * @uses calendarComponent::_createParams()
2214
 * @return string
2215
 */
2216
  function createStatus() {
2217
    if( empty( $this->status )) return FALSE;
2218
    if( empty( $this->status['value'] ))
2219
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'STATUS' ) : FALSE;
2220
    $attributes = $this->_createParams( $this->status['params'] );
2221
    return $this->_createElement( 'STATUS', $attributes, $this->status['value'] );
2222
  }
2223
/**
2224
 * set calendar component property status
2225
 *
2226
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2227
 * @since 2.16.21 - 2013-06-23
2228
 * @param string  $value
2229
 * @param array   $params
2230
 * @uses calendarComponent::getConfig()
2231
 * @uses calendarComponent::$status
2232
 * @uses iCalUtilityFunctions::_setParams()
2233
 * @return bool
2234
 */
2235
  function setStatus( $value, $params=FALSE ) {
2236
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2237
    $this->status = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2238
    return TRUE;
2239
  }
2240
/*********************************************************************************/
2241
/**
2242
 * Property Name: SUMMARY
2243
 */
2244
/**
2245
 * creates formatted output for calendar component property summary
2246
 *
2247
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2248
 * @since 2.16.2 - 2012-12-18
2249
 * @uses calendarComponent::$summary
2250
 * @uses calendarComponent::getConfig()
2251
 * @uses calendarComponent::_createElement()
2252
 * @uses calendarComponent::_createParams()
2253
 * @uses iCalUtilityFunctions::_strrep()
2254
 * @return string
2255
 */
2256
  function createSummary() {
2257
    if( empty( $this->summary )) return FALSE;
2258
    if( empty( $this->summary['value'] ))
2259
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'SUMMARY' ) : FALSE;
2260
    $attributes = $this->_createParams( $this->summary['params'], array( 'ALTREP', 'LANGUAGE' ));
2261
    $content    = iCalUtilityFunctions::_strrep( $this->summary['value'], $this->format, $this->nl );
2262
    return $this->_createElement( 'SUMMARY', $attributes, $content );
2263
  }
2264
/**
2265
 * set calendar component property summary
2266
 *
2267
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2268
 * @since 2.16.21 - 2013-06-23
2269
 * @param string  $value
2270
 * @param string  $params
2271
 * @uses calendarComponent::getConfig()
2272
 * @uses iCalUtilityFunctions::_setParams()
2273
 * @return bool
2274
 */
2275
  function setSummary( $value, $params=FALSE ) {
2276
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2277
    $this->summary = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2278
    return TRUE;
2279
  }
2280
/*********************************************************************************/
2281
/**
2282
 * Property Name: TRANSP
2283
 */
2284
/**
2285
 * creates formatted output for calendar component property transp
2286
 *
2287
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2288
 * @since 2.4.8 - 2008-10-21
2289
 * @uses calendarComponent::$transp
2290
 * @uses calendarComponent::getConfig()
2291
 * @uses calendarComponent::_createElement()
2292
 * @uses calendarComponent::_createParams()
2293
 * @return string
2294
 */
2295
  function createTransp() {
2296
    if( empty( $this->transp )) return FALSE;
2297
    if( empty( $this->transp['value'] ))
2298
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRANSP' ) : FALSE;
2299
    $attributes = $this->_createParams( $this->transp['params'] );
2300
    return $this->_createElement( 'TRANSP', $attributes, $this->transp['value'] );
2301
  }
2302
/**
2303
 * set calendar component property transp
2304
 *
2305
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2306
 * @since 2.16.21 - 2013-06-23
2307
 * @param string  $value
2308
 * @param string  $params
2309
 * @uses calendarComponent::getConfig()
2310
 * @uses calendarComponent::$transp
2311
 * @uses iCalUtilityFunctions::_setParams()
2312
 * @return bool
2313
 */
2314
  function setTransp( $value, $params=FALSE ) {
2315
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2316
    $this->transp = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2317
    return TRUE;
2318
  }
2319
/*********************************************************************************/
2320
/**
2321
 * Property Name: TRIGGER
2322
 */
2323
/**
2324
 * creates formatted output for calendar component property trigger
2325
 *
2326
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2327
 * @since 2.4.16 - 2008-10-21
2328
 * @uses calendarComponent::$trigger
2329
 * @uses calendarComponent::getConfig()
2330
 * @uses calendarComponent::_createElement()
2331
 * @uses iCalUtilityFunctions::_date2strdate()
2332
 * @uses calendarComponent::$intAttrDelimiter
2333
 * @uses iCalUtilityFunctions::_duration2str()
2334
 * @uses calendarComponent::_createParams()
2335
 * @return string
2336
 */
2337
  function createTrigger() {
2338
    if( empty( $this->trigger )) return FALSE;
2339
    if( empty( $this->trigger['value'] ))
2340
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TRIGGER' ) : FALSE;
2341
    $content = $attributes = null;
2342
    if( isset( $this->trigger['value']['year'] )   &&
2343
        isset( $this->trigger['value']['month'] )  &&
2344
        isset( $this->trigger['value']['day'] ))
2345
      $content      .= iCalUtilityFunctions::_date2strdate( $this->trigger['value'] );
2346
    else {
2347
      if( TRUE !== $this->trigger['value']['relatedStart'] )
2348
        $attributes .= $this->intAttrDelimiter.'RELATED=END';
2349
      if( $this->trigger['value']['before'] )
2350
        $content    .= '-';
2351
      $content      .= iCalUtilityFunctions::_duration2str( $this->trigger['value'] );
2352
    }
2353
    $attributes     .= $this->_createParams( $this->trigger['params'] );
2354
    return $this->_createElement( 'TRIGGER', $attributes, $content );
2355
  }
2356
/**
2357
 * set calendar component property trigger
2358
 *
2359
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2360
 * @since 2.16.21 - 2013-06-23
2361
 * @param mixed  $year
2362
 * @param mixed  $month
2363
 * @param int    $day
2364
 * @param int    $week
2365
 * @param int    $hour
2366
 * @param int    $min
2367
 * @param int    $sec
2368
 * @param bool   $relatedStart
2369
 * @param bool   $before
2370
 * @param array  $params
2371
 * @uses calendarComponent::getConfig()
2372
 * @uses calendarComponent::$trigger
2373
 * @uses iCalUtilityFunctions::_setParams()
2374
 * @uses iCalUtilityFunctions::_isArrayTimestampDate()
2375
 * @uses iCalUtilityFunctions::_timestamp2date()
2376
 * @uses iCalUtilityFunctions::_strdate2date()
2377
 * @uses iCalUtilityFunctions::_duration2arr()
2378
 * @return bool
2379
 */
2380
  function setTrigger( $year, $month=null, $day=null, $week=FALSE, $hour=FALSE, $min=FALSE, $sec=FALSE, $relatedStart=TRUE, $before=TRUE, $params=FALSE ) {
2381
    if( empty( $year ) && ( empty( $month ) || is_array( $month )) && empty( $day ) && empty( $week ) && empty( $hour ) && empty( $min ) && empty( $sec ))
2382
      if( $this->getConfig( 'allowEmpty' )) {
2383
        $this->trigger = array( 'value' => '', 'params' => iCalUtilityFunctions::_setParams( $month ) );
2384
        return TRUE;
2385
      }
2386
      else
2387
        return FALSE;
2388
    if( iCalUtilityFunctions::_isArrayTimestampDate( $year )) { // timestamp UTC
2389
      $params = iCalUtilityFunctions::_setParams( $month );
2390
      $date   = iCalUtilityFunctions::_timestamp2date( $year, 7 );
2391
      foreach( $date as $k => $v )
2392
        $$k = $v;
2393
    }
2394
    elseif( is_array( $year ) && ( is_array( $month ) || empty( $month ))) {
2395
      $params = iCalUtilityFunctions::_setParams( $month );
2396
      if(!(array_key_exists( 'year',  $year ) &&   // exclude date-time
2397
           array_key_exists( 'month', $year ) &&
2398
           array_key_exists( 'day',   $year ))) {  // when this must be a duration
2399
        if( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] )))
2400
          $relatedStart = FALSE;
2401
        else
2402
          $relatedStart = ( array_key_exists( 'relatedStart', $year ) && ( TRUE !== $year['relatedStart'] )) ? FALSE : TRUE;
2403
        $before         = ( array_key_exists( 'before', $year )       && ( TRUE !== $year['before'] ))       ? FALSE : TRUE;
2404
      }
2405
      $SSYY  = ( array_key_exists( 'year',  $year )) ? $year['year']  : null;
2406
      $month = ( array_key_exists( 'month', $year )) ? $year['month'] : null;
2407
      $day   = ( array_key_exists( 'day',   $year )) ? $year['day']   : null;
2408
      $week  = ( array_key_exists( 'week',  $year )) ? $year['week']  : null;
2409
      $hour  = ( array_key_exists( 'hour',  $year )) ? $year['hour']  : 0; //null;
2410
      $min   = ( array_key_exists( 'min',   $year )) ? $year['min']   : 0; //null;
2411
      $sec   = ( array_key_exists( 'sec',   $year )) ? $year['sec']   : 0; //null;
2412
      $year  = $SSYY;
2413
    }
2414
    elseif(is_string( $year ) && ( is_array( $month ) || empty( $month ))) {  // duration or date in a string
2415
      $params = iCalUtilityFunctions::_setParams( $month );
2416
      if( in_array( $year{0}, array( 'P', '+', '-' ))) { // duration
2417
        $relatedStart = ( isset( $params['RELATED'] ) && ( 'END' == strtoupper( $params['RELATED'] ))) ? FALSE : TRUE;
2418
        $before       = ( '-'  == $year[0] ) ? TRUE : FALSE;
2419
        if(     'P'  != $year[0] )
2420
          $year       = substr( $year, 1 );
2421
        $date         = iCalUtilityFunctions::_durationStr2arr( $year);
2422
      }
2423
      else   // date
2424
        $date    = iCalUtilityFunctions::_strdate2date( $year, 7 );
2425
      unset( $year, $month, $day, $date['unparsedtext'] );
2426
      if( empty( $date ))
2427
        $sec = 0;
2428
      else
2429
        foreach( $date as $k => $v )
2430
          $$k = $v;
2431
    }
2432
    else // single values in function input parameters
2433
      $params = iCalUtilityFunctions::_setParams( $params );
2434
    if( !empty( $year ) && !empty( $month ) && !empty( $day )) { // date
2435
      $params['VALUE'] = 'DATE-TIME';
2436
      $hour = ( $hour ) ? $hour : 0;
2437
      $min  = ( $min  ) ? $min  : 0;
2438
      $sec  = ( $sec  ) ? $sec  : 0;
2439
      $this->trigger = array( 'params' => $params );
2440
      $this->trigger['value'] = array( 'year'  => $year
2441
                                     , 'month' => $month
2442
                                     , 'day'   => $day
2443
                                     , 'hour'  => $hour
2444
                                     , 'min'   => $min
2445
                                     , 'sec'   => $sec
2446
                                     , 'tz'    => 'Z' );
2447
      return TRUE;
2448
    }
2449
    elseif(( empty( $year ) && empty( $month )) &&    // duration
2450
           (( !empty( $week ) || ( 0 == $week )) ||
2451
            ( !empty( $day )  || ( 0 == $day  )) ||
2452
            ( !empty( $hour ) || ( 0 == $hour )) ||
2453
            ( !empty( $min )  || ( 0 == $min  )) ||
2454
            ( !empty( $sec )  || ( 0 == $sec  )))) {
2455
      unset( $params['RELATED'] ); // set at output creation (END only)
2456
      unset( $params['VALUE'] );   // 'DURATION' default
2457
      $this->trigger = array( 'params' => $params );
2458
      $this->trigger['value']  = array();
2459
      if( !empty( $week )) $this->trigger['value']['week'] = $week;
2460
      if( !empty( $day  )) $this->trigger['value']['day']  = $day;
2461
      if( !empty( $hour )) $this->trigger['value']['hour'] = $hour;
2462
      if( !empty( $min  )) $this->trigger['value']['min']  = $min;
2463
      if( !empty( $sec  )) $this->trigger['value']['sec']  = $sec;
2464
      if( empty( $this->trigger['value'] )) {
2465
        $this->trigger['value']['sec'] = 0;
2466
        $before                        = FALSE;
2467
      }
2468
      else
2469
        $this->trigger['value'] = iCalUtilityFunctions::_duration2arr( $this->trigger['value'] );
2470
      $relatedStart = ( FALSE !== $relatedStart ) ? TRUE : FALSE;
2471
      $before       = ( FALSE !== $before )       ? TRUE : FALSE;
2472
      $this->trigger['value']['relatedStart'] = $relatedStart;
2473
      $this->trigger['value']['before']       = $before;
2474
      return TRUE;
2475
    }
2476
    return FALSE;
2477
  }
2478
/*********************************************************************************/
2479
/**
2480
 * Property Name: TZID
2481
 */
2482
/**
2483
 * creates formatted output for calendar component property tzid
2484
 *
2485
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2486
 * @since 2.16.2 - 2012-12-18
2487
 * @uses calendarComponent::$tzid
2488
 * @uses calendarComponent::getConfig()
2489
 * @uses calendarComponent::_createElement()
2490
 * @uses calendarComponent::_createParams()
2491
 * @uses iCalUtilityFunctions::_strrep()
2492
 * @uses calendarComponent::$format
2493
 * @uses calendarComponent::$nl
2494
 * @return string
2495
 */
2496
  function createTzid() {
2497
    if( empty( $this->tzid )) return FALSE;
2498
    if( empty( $this->tzid['value'] ))
2499
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZID' ) : FALSE;
2500
    $attributes = $this->_createParams( $this->tzid['params'] );
2501
    return $this->_createElement( 'TZID', $attributes, iCalUtilityFunctions::_strrep( $this->tzid['value'], $this->format, $this->nl ));
2502
  }
2503
/**
2504
 * set calendar component property tzid
2505
 *
2506
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2507
 * @since 2.16.21 - 2013-06-23
2508
 * @param string  $value
2509
 * @param array   $params
2510
 * @uses calendarComponent::getConfig()
2511
 * @uses calendarComponent::$tzid
2512
 * @uses iCalUtilityFunctions::_setParams()
2513
 * @return bool
2514
 */
2515
  function setTzid( $value, $params=FALSE ) {
2516
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2517
    $this->tzid = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2518
    return TRUE;
2519
  }
2520
/*********************************************************************************/
2521
/**
2522
 * .. .
2523
 * Property Name: TZNAME
2524
 */
2525
/**
2526
 * creates formatted output for calendar component property tzname
2527
 *
2528
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2529
 * @since 2.16.2 - 2012-12-18
2530
 * @uses calendarComponent::$tzname
2531
 * @uses calendarComponent::_createParams()
2532
 * @uses calendarComponent::_createElement()
2533
 * @uses iCalUtilityFunctions::_strrep(
2534
 * @uses calendarComponent::$format
2535
 * @uses calendarComponent::$nl
2536
 * @uses calendarComponent::getConfig()
2537
 * @return string
2538
 */
2539
  function createTzname() {
2540
    if( empty( $this->tzname )) return FALSE;
2541
    $output = null;
2542
    foreach( $this->tzname as $theName ) {
2543
      if( !empty( $theName['value'] )) {
2544
        $attributes = $this->_createParams( $theName['params'], array( 'LANGUAGE' ));
2545
        $output    .= $this->_createElement( 'TZNAME', $attributes, iCalUtilityFunctions::_strrep( $theName['value'], $this->format, $this->nl ));
2546
      }
2547
      elseif( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( 'TZNAME' );
2548
    }
2549
    return $output;
2550
  }
2551
/**
2552
 * set calendar component property tzname
2553
 *
2554
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2555
 * @since 2.16.21 - 2013-06-23
2556
 * @param string   $value
2557
 * @param array    $params
2558
 * @param integer  $index
2559
 * @uses calendarComponent::_createParams()
2560
 * @uses calendarComponent::$tzname
2561
 * @uses iCalUtilityFunctions::_setMval()
2562
 * @return bool
2563
 */
2564
  function setTzname( $value, $params=FALSE, $index=FALSE ) {
2565
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2566
    iCalUtilityFunctions::_setMval( $this->tzname, $value, $params, FALSE, $index );
2567
    return TRUE;
2568
  }
2569
/*********************************************************************************/
2570
/**
2571
 * Property Name: TZOFFSETFROM
2572
 */
2573
/**
2574
 * creates formatted output for calendar component property tzoffsetfrom
2575
 *
2576
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2577
 * @since 2.4.8 - 2008-10-21
2578
 * @uses calendarComponent::$tzoffsetfrom
2579
 * @uses calendarComponent::getConfig()
2580
 * @uses calendarComponent::_createElement()
2581
 * @uses calendarComponent::_createParams()
2582
 * @return string
2583
 */
2584
  function createTzoffsetfrom() {
2585
    if( empty( $this->tzoffsetfrom )) return FALSE;
2586
    if( empty( $this->tzoffsetfrom['value'] ))
2587
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETFROM' ) : FALSE;
2588
    $attributes = $this->_createParams( $this->tzoffsetfrom['params'] );
2589
    return $this->_createElement( 'TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value'] );
2590
  }
2591
/**
2592
 * set calendar component property tzoffsetfrom
2593
 *
2594
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2595
 * @since 2.16.21 - 2013-06-23
2596
 * @param string  $value
2597
 * @param array   $params
2598
 * @uses calendarComponent::getConfig()
2599
 * @uses calendarComponent::$tzoffsetfrom
2600
 * @uses iCalUtilityFunctions::_setParams()
2601
 * @return bool
2602
 */
2603
  function setTzoffsetfrom( $value, $params=FALSE ) {
2604
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2605
    $this->tzoffsetfrom = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2606
    return TRUE;
2607
  }
2608
/*********************************************************************************/
2609
/**
2610
 * Property Name: TZOFFSETTO
2611
 */
2612
/**
2613
 * creates formatted output for calendar component property tzoffsetto
2614
 *
2615
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2616
 * @since 2.4.8 - 2008-10-21
2617
 * @uses calendarComponent::$tzoffsetto
2618
 * @uses calendarComponent::getConfig()
2619
 * @uses calendarComponent::_createElement()
2620
 * @uses calendarComponent::_createParams()
2621
 * @return string
2622
 */
2623
  function createTzoffsetto() {
2624
    if( empty( $this->tzoffsetto )) return FALSE;
2625
    if( empty( $this->tzoffsetto['value'] ))
2626
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZOFFSETTO' ) : FALSE;
2627
    $attributes = $this->_createParams( $this->tzoffsetto['params'] );
2628
    return $this->_createElement( 'TZOFFSETTO', $attributes, $this->tzoffsetto['value'] );
2629
  }
2630
/**
2631
 * set calendar component property tzoffsetto
2632
 *
2633
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2634
 * @since 2.16.21 - 2013-06-23
2635
 * @param string  $value
2636
 * @param array   $params
2637
 * @uses calendarComponent::getConfig()
2638
 * @uses calendarComponent::$tzoffsetto
2639
 * @uses iCalUtilityFunctions::_setParams()
2640
 * @return bool
2641
 */
2642
  function setTzoffsetto( $value, $params=FALSE ) {
2643
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2644
    $this->tzoffsetto = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2645
    return TRUE;
2646
  }
2647
/*********************************************************************************/
2648
/**
2649
 * Property Name: TZURL
2650
 */
2651
/**
2652
 * creates formatted output for calendar component property tzurl
2653
 *
2654
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2655
 * @since 2.4.8 - 2008-10-21
2656
 * @uses calendarComponent::$tzurl
2657
 * @uses calendarComponent::getConfig()
2658
 * @uses calendarComponent::_createElement()
2659
 * @uses calendarComponent::_createParams()
2660
 * @return string
2661
 */
2662
  function createTzurl() {
2663
    if( empty( $this->tzurl )) return FALSE;
2664
    if( empty( $this->tzurl['value'] ))
2665
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'TZURL' ) : FALSE;
2666
    $attributes = $this->_createParams( $this->tzurl['params'] );
2667
    return $this->_createElement( 'TZURL', $attributes, $this->tzurl['value'] );
2668
  }
2669
/**
2670
 * set calendar component property tzurl
2671
 *
2672
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2673
 * @since 2.16.21 - 2013-06-23
2674
 * @param string  $value
2675
 * @param array   $params
2676
 * @uses calendarComponent::$tzurl
2677
 * @uses calendarComponent::getConfig()
2678
 * @uses calendarComponent::$tzurl
2679
 * @uses iCalUtilityFunctions::_setParams()
2680
 * @return boll
2681
 */
2682
  function setTzurl( $value, $params=FALSE ) {
2683
    if( empty( $value )) if( $this->getConfig( 'allowEmpty' )) $value = ''; else return FALSE;
2684
    $this->tzurl = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2685
    return TRUE;
2686
  }
2687
/*********************************************************************************/
2688
/**
2689
 * Property Name: UID
2690
 */
2691
/**
2692
 * creates formatted output for calendar component property uid
2693
 *
2694
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2695
 * @since 2.19.1 - 2014-02-21
2696
 * @uses calendarComponent::$uid
2697
 * @uses calendarComponent::_makeuid();
2698
 * @uses calendarComponent::_createParams()
2699
 * @uses calendarComponent::_createElement()
2700
 * @return string
2701
 */
2702
  function createUid() {
2703
    if( empty( $this->uid ))
2704
      $this->_makeuid();
2705
    $attributes = $this->_createParams( $this->uid['params'] );
2706
    return $this->_createElement( 'UID', $attributes, $this->uid['value'] );
2707
  }
2708
/**
2709
 * create an unique id for this calendar component object instance
2710
 *
2711
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2712
 * @since 2.2.7 - 2007-09-04
2713
 * @uses calendarComponent::$uid
2714
 * @uses calendarComponent::getConfig()
2715
 * @return void
2716
 */
2717
  function _makeUid() {
2718
    $date   = date('Ymd\THisT');
2719
    $unique = substr(microtime(), 2, 4);
2720
    $base   = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890';
2721
    $start  = 0;
2722
    $end    = strlen( $base ) - 1;
2723
    $length = 6;
2724
    $str    = null;
2725
    for( $p = 0; $p < $length; $p++ )
2726
      $unique .= $base{mt_rand( $start, $end )};
2727
    $this->uid = array( 'params' => null );
2728
    $this->uid['value']  = $date.'-'.$unique.'@'.$this->getConfig( 'unique_id' );
2729
  }
2730
/**
2731
 * set calendar component property uid
2732
 *
2733
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2734
 * @since 2.19.1 - 2014-02-21
2735
 * @param string  $value
2736
 * @param array   $params
2737
 * @uses calendarComponent::$uid
2738
 * @uses calendarComponent::_setParams()
2739
 * @return bool
2740
 */
2741
  function setUid( $value, $params=FALSE ) {
2742
    if( empty( $value ) && ( '0' != $value )) return FALSE; // no allowEmpty check here !!!!
2743
    $this->uid = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2744
    return TRUE;
2745
  }
2746
/*********************************************************************************/
2747
/**
2748
 * Property Name: URL
2749
 */
2750
/**
2751
 * creates formatted output for calendar component property url
2752
 *
2753
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2754
 * @since 2.4.8 - 2008-10-21
2755
 * @uses calendarComponent::$url
2756
 * @uses calendarComponent::getConfig()
2757
 * @uses calendarComponent::_createElement()
2758
 * @uses calendarComponent::_createParams()
2759
 * @return string
2760
 */
2761
  function createUrl() {
2762
    if( empty( $this->url )) return FALSE;
2763
    if( empty( $this->url['value'] ))
2764
      return ( $this->getConfig( 'allowEmpty' )) ? $this->_createElement( 'URL' ) : FALSE;
2765
    $attributes = $this->_createParams( $this->url['params'] );
2766
    return $this->_createElement( 'URL', $attributes, $this->url['value'] );
2767
  }
2768
/**
2769
 * set calendar component property url
2770
 *
2771
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2772
 * @since 2.16.21 - 2013-06-23
2773
 * @param string  $value
2774
 * @param array   $params
2775
 * @uses calendarComponent::getConfig()
2776
 * @uses calendarComponent::$url
2777
 * @uses calendarComponent::_setParams()
2778
 * @return bool
2779
 */
2780
  function setUrl( $value, $params=FALSE ) {
2781
    if( !empty( $value )) {
2782
      if( !filter_var( $value, FILTER_VALIDATE_URL ) && ( 'urn' != strtolower( substr( $value, 0, 3 ))))
2783
        return FALSE;
2784
    }
2785
    elseif( $this->getConfig( 'allowEmpty' ))
2786
      $value = '';
2787
    else
2788
      return FALSE;
2789
    $this->url = array( 'value' => $value, 'params' => iCalUtilityFunctions::_setParams( $params ));
2790
    return TRUE;
2791
  }
2792
/*********************************************************************************/
2793
/*********************************************************************************/
2794
/**
2795
 * create element format parts
2796
 *
2797
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2798
 * @since 2.0.6 - 2006-06-20
2799
 * @uses iCalBase::_createFormat()
2800
 * @uses calendarComponent::$timezonetype
2801
 * @return string
2802
 */
2803
  function _createFormat() {
2804
    parent::_createFormat();
2805
    $objectname     = null;
2806
    switch( $this->format ) {
2807
      case 'xcal':
2808
        return ( isset( $this->timezonetype )) ? strtolower( $this->timezonetype ) : strtolower( $this->objName );
2809
        break;
2810
      default:
2811
        return ( isset( $this->timezonetype )) ? strtoupper( $this->timezonetype ) : strtoupper( $this->objName );
2812
        break;
2813
    }
2814
  }
2815
/**
2816
 * creates formatted output for calendar component property data value type recur
2817
 *
2818
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2819
 * @since 2.16.25 - 2013-06-30
2820
 * @param array $recurlabel
2821
 * @param array $recurdata
2822
 * @uses calendarComponent::getConfig()
2823
 * @uses calendarComponent::_createElement()
2824
 * @uses calendarComponent::_createParams()
2825
 * @uses iCalUtilityFunctions::_date2strdate()
2826
 * @uses iCalUtilityFunctions::_recurBydaySort()
2827
 * @return string
2828
 */
2829
  function _format_recur( $recurlabel, $recurdata ) {
2830
    $output = null;
2831
    foreach( $recurdata as $therule ) {
2832
      if( empty( $therule['value'] )) {
2833
        if( $this->getConfig( 'allowEmpty' )) $output .= $this->_createElement( $recurlabel );
2834
        continue;
2835
      }
2836
      $attributes = ( isset( $therule['params'] )) ? $this->_createParams( $therule['params'] ) : null;
2837
      $content1  = $content2  = null;
2838
      foreach( $therule['value'] as $rulelabel => $rulevalue ) {
2839
        switch( strtoupper( $rulelabel )) {
2840
          case 'FREQ': {
2841
            $content1 .= "FREQ=$rulevalue";
2842
            break;
2843
          }
2844
          case 'UNTIL': {
2845
            $parno     = ( isset( $rulevalue['hour'] )) ? 7 : 3;
2846
            $content2 .= ';UNTIL='.iCalUtilityFunctions::_date2strdate( $rulevalue, $parno );
2847
            break;
2848
          }
2849
          case 'COUNT':
2850
          case 'INTERVAL':
2851
          case 'WKST': {
2852
            $content2 .= ";$rulelabel=$rulevalue";
2853
            break;
2854
          }
2855
          case 'BYSECOND':
2856
          case 'BYMINUTE':
2857
          case 'BYHOUR':
2858
          case 'BYMONTHDAY':
2859
          case 'BYYEARDAY':
2860
          case 'BYWEEKNO':
2861
          case 'BYMONTH':
2862
          case 'BYSETPOS': {
2863
            $content2 .= ";$rulelabel=";
2864
            if( is_array( $rulevalue )) {
2865
              foreach( $rulevalue as $vix => $valuePart ) {
2866
                $content2 .= ( $vix ) ? ',' : null;
2867
                $content2 .= $valuePart;
2868
              }
2869
            }
2870
            else
2871
             $content2 .= $rulevalue;
2872
            break;
2873
          }
2874
          case 'BYDAY': {
2875
            $byday          = array( '' );
2876
            $bx             = 0;
2877
            foreach( $rulevalue as $bix => $bydayPart ) {
2878
              if( ! empty( $byday[$bx] ) && ! ctype_digit( substr( $byday[$bx], -1 ))) // new day
2879
                $byday[++$bx] = '';
2880
              if( ! is_array( $bydayPart ))   // day without order number
2881
                $byday[$bx] .= (string) $bydayPart;
2882
              else {                          // day with order number
2883
                foreach( $bydayPart as $bix2 => $bydayPart2 )
2884
                  $byday[$bx] .= (string) $bydayPart2;
2885
              }
2886
            } // end foreach( $rulevalue as $bix => $bydayPart )
2887
            if( 1 < count( $byday ))
2888
              usort( $byday, array( 'iCalUtilityFunctions', '_recurBydaySort' ));
2889
            $content2      .= ';BYDAY='.implode( ',', $byday );
2890
            break;
2891
          }
2892
          default: {
2893
            $content2 .= ";$rulelabel=$rulevalue";
2894
            break;
2895
          }
2896
        }
2897
      }
2898
      $output .= $this->_createElement( $recurlabel, $attributes, $content1.$content2 );
2899
    }
2900
    return $output;
2901
  }
2902
/**
2903
 * check if property not exists within component
2904
 *
2905
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2906
 * @since 2.5.1 - 2008-10-15
2907
 * @param string $propName
2908
 * @uses calendarComponent::$lastmodified
2909
 * @uses calendarComponent::$percentcomplete
2910
 * @uses calendarComponent::$recurrenceid
2911
 * @uses calendarComponent::$relatedto
2912
 * @uses calendarComponent::$requeststatus
2913
 * @uses calendarComponent::getConfig()
2914
 * @uses calendarComponent::{$propname}
2915
 * @return bool
2916
 */
2917
  function _notExistProp( $propName ) {
2918
    if( empty( $propName )) return FALSE; // when deleting x-prop, an empty propName may be used=allowed
2919
    $propName = strtolower( $propName );
2920
    if(     'last-modified'    == $propName )  { if( !isset( $this->lastmodified ))    return TRUE; }
2921
    elseif( 'percent-complete' == $propName )  { if( !isset( $this->percentcomplete )) return TRUE; }
2922
    elseif( 'recurrence-id'    == $propName )  { if( !isset( $this->recurrenceid ))    return TRUE; }
2923
    elseif( 'related-to'       == $propName )  { if( !isset( $this->relatedto ))       return TRUE; }
2924
    elseif( 'request-status'   == $propName )  { if( !isset( $this->requeststatus ))   return TRUE; }
2925
    elseif((       'x-' != substr($propName,0,2)) && !isset( $this->$propName ))       return TRUE;
2926
    return FALSE;
2927
  }
2928
/*********************************************************************************/
2929
/*********************************************************************************/
2930
/**
2931
 * get general component config variables or info about subcomponents
2932
 *
2933
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
2934
 * @since 2.21.11 - 2015-03-21
2935
 * @param mixed $config
2936
 * @uses calendarComponent::getConfig()
2937
 * @uses calendarComponent::$allowEmpty
2938
 * @uses calendarComponent::$compix
2939
 * @uses calendarComponent::$components
2940
 * @uses calendarComponent::$objName
2941
 * @uses calendarComponent::getProperty()
2942
 * @uses calendarComponent::$format
2943
 * @uses calendarComponent::$language
2944
 * @uses calendarComponent::$nl
2945
 * @uses iCalUtilityFunctions::$miscComps
2946
 * @uses calendarComponent::$uid
2947
 * @uses calendarComponent::_makeuid()
2948
 * @uses calendarComponent::dtstamp
2949
 * @uses calendarComponent::_makeDtstamp()
2950
 * @uses calendarComponent::$summary
2951
 * @uses calendarComponent::$description
2952
 * @uses calendarComponent::$dtstart
2953
 * @uses calendarComponent::$dtend
2954
 * @uses calendarComponent::$due
2955
 * @uses calendarComponent::$duration
2956
 * @uses calendarComponent::$rrule
2957
 * @uses calendarComponent::$rdate
2958
 * @uses calendarComponent::$exdate
2959
 * @uses calendarComponent::$exrule
2960
 * @uses calendarComponent::$action
2961
 * @uses calendarComponent::$attach
2962
 * @uses calendarComponent::$attendee
2963
 * @uses calendarComponent::$categories
2964
 * @uses calendarComponent::$class
2965
 * @uses calendarComponent::$comment
2966
 * @uses calendarComponent::$completed
2967
 * @uses calendarComponent::$contact
2968
 * @uses calendarComponent::$created
2969
 * @uses calendarComponent::$freebusy
2970
 * @uses calendarComponent::$geo
2971
 * @uses calendarComponent::$lastmodified
2972
 * @uses calendarComponent::$location
2973
 * @uses calendarComponent::$organizer
2974
 * @uses calendarComponent::$percentcomplete
2975
 * @uses calendarComponent::$priority
2976
 * @uses calendarComponent::$recurrenceid
2977
 * @uses calendarComponent::$relatedto
2978
 * @uses calendarComponent::$repeat
2979
 * @uses calendarComponent::$requeststatus
2980
 * @uses calendarComponent::$resources
2981
 * @uses calendarComponent::$sequence
2982
 * @uses calendarComponent::$sequence
2983
 * @uses calendarComponent::$status
2984
 * @uses calendarComponent::$transp
2985
 * @uses calendarComponent::$trigger
2986
 * @uses calendarComponent::$tzid
2987
 * @uses calendarComponent::$tzname
2988
 * @uses calendarComponent::$tzoffsetfrom
2989
 * @uses calendarComponent::$tzoffsetto
2990
 * @uses calendarComponent::$tzurl
2991
 * @uses calendarComponent::$url
2992
 * @uses calendarComponent::$xprop
2993
 * @uses calendarComponent::$dtzid
2994
 * @uses calendarComponent::$unique_id
2995
 * @return value
2996
 */
2997
  function getConfig( $config = FALSE) {
2998
    if( !$config ) {
2999
      $return = array();
3000
      $return['ALLOWEMPTY']  = $this->getConfig( 'ALLOWEMPTY' );
3001
      $return['FORMAT']      = $this->getConfig( 'FORMAT' );
3002
      if( FALSE !== ( $lang  = $this->getConfig( 'LANGUAGE' )))
3003
        $return['LANGUAGE']  = $lang;
3004
      $return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' );
3005
      $return['TZTD']        = $this->getConfig( 'TZID' );
3006
      $return['UNIQUE_ID']   = $this->getConfig( 'UNIQUE_ID' );
3007
      return $return;
3008
    }
3009
    switch( strtoupper( $config )) {
3010
      case 'ALLOWEMPTY':
3011
        return $this->allowEmpty;
3012
        break;
3013
      case 'COMPSINFO':
3014
        unset( $this->compix );
3015
        $info = array();
3016
        if( isset( $this->components )) {
3017
          foreach( $this->components as $cix => $component ) {
3018
            if( empty( $component )) continue;
3019
            $info[$cix]['ordno'] = $cix + 1;
3020
            $info[$cix]['type']  = $component->objName;
3021
            $info[$cix]['uid']   = $component->getProperty( 'uid' );
3022
            $info[$cix]['props'] = $component->getConfig( 'propinfo' );
3023
            $info[$cix]['sub']   = $component->getConfig( 'compsinfo' );
3024
          }
3025
        }
3026
        return $info;
3027
        break;
3028
      case 'FORMAT':
3029
        return $this->format;
3030
        break;
3031
      case 'LANGUAGE':
3032
         // get language for calendar component as defined in [RFC 1766]
3033
        return $this->language;
3034
        break;
3035
      case 'NL':
3036
      case 'NEWLINECHAR':
3037
        return $this->nl;
3038
        break;
3039
      case 'PROPINFO':
3040
        $output = array();
3041
        if( ! in_array( $this->objName, iCalUtilityFunctions::$miscComps )) {
3042
          if( empty( $this->uid ))            $this->_makeuid();
3043
                                              $output['UID']              = 1;
3044
          if( empty( $this->dtstamp ))        $this->_makeDtstamp();
3045
                                              $output['DTSTAMP']          = 1;
3046
        }
3047
        if( !empty( $this->summary ))         $output['SUMMARY']          = 1;
3048
        if( !empty( $this->description ))     $output['DESCRIPTION']      = count( $this->description );
3049
        if( !empty( $this->dtstart ))         $output['DTSTART']          = 1;
3050
        if( !empty( $this->dtend ))           $output['DTEND']            = 1;
3051
        if( !empty( $this->due ))             $output['DUE']              = 1;
3052
        if( !empty( $this->duration ))        $output['DURATION']         = 1;
3053
        if( !empty( $this->rrule ))           $output['RRULE']            = count( $this->rrule );
3054
        if( !empty( $this->rdate ))           $output['RDATE']            = count( $this->rdate );
3055
        if( !empty( $this->exdate ))          $output['EXDATE']           = count( $this->exdate );
3056
        if( !empty( $this->exrule ))          $output['EXRULE']           = count( $this->exrule );
3057
        if( !empty( $this->action ))          $output['ACTION']           = 1;
3058
        if( !empty( $this->attach ))          $output['ATTACH']           = count( $this->attach );
3059
        if( !empty( $this->attendee ))        $output['ATTENDEE']         = count( $this->attendee );
3060
        if( !empty( $this->categories ))      $output['CATEGORIES']       = count( $this->categories );
3061
        if( !empty( $this->class ))           $output['CLASS']            = 1;
3062
        if( !empty( $this->comment ))         $output['COMMENT']          = count( $this->comment );
3063
        if( !empty( $this->completed ))       $output['COMPLETED']        = 1;
3064
        if( !empty( $this->contact ))         $output['CONTACT']          = count( $this->contact );
3065
        if( !empty( $this->created ))         $output['CREATED']          = 1;
3066
        if( !empty( $this->freebusy ))        $output['FREEBUSY']         = count( $this->freebusy );
3067
        if( !empty( $this->geo ))             $output['GEO']              = 1;
3068
        if( !empty( $this->lastmodified ))    $output['LAST-MODIFIED']    = 1;
3069
        if( !empty( $this->location ))        $output['LOCATION']         = 1;
3070
        if( !empty( $this->organizer ))       $output['ORGANIZER']        = 1;
3071
        if( !empty( $this->percentcomplete )) $output['PERCENT-COMPLETE'] = 1;
3072
        if( !empty( $this->priority ))        $output['PRIORITY']         = 1;
3073
        if( !empty( $this->recurrenceid ))    $output['RECURRENCE-ID']    = 1;
3074
        if( !empty( $this->relatedto ))       $output['RELATED-TO']       = count( $this->relatedto );
3075
        if( !empty( $this->repeat ))          $output['REPEAT']           = 1;
3076
        if( !empty( $this->requeststatus ))   $output['REQUEST-STATUS']   = count( $this->requeststatus );
3077
        if( !empty( $this->resources ))       $output['RESOURCES']        = count( $this->resources );
3078
        if( !empty( $this->sequence ))        $output['SEQUENCE']         = 1;
3079
        if( !empty( $this->sequence ))        $output['SEQUENCE']         = 1;
3080
        if( !empty( $this->status ))          $output['STATUS']           = 1;
3081
        if( !empty( $this->transp ))          $output['TRANSP']           = 1;
3082
        if( !empty( $this->trigger ))         $output['TRIGGER']          = 1;
3083
        if( !empty( $this->tzid ))            $output['TZID']             = 1;
3084
        if( !empty( $this->tzname ))          $output['TZNAME']           = count( $this->tzname );
3085
        if( !empty( $this->tzoffsetfrom ))    $output['TZOFFSETFROM']     = 1;
3086
        if( !empty( $this->tzoffsetto ))      $output['TZOFFSETTO']       = 1;
3087
        if( !empty( $this->tzurl ))           $output['TZURL']            = 1;
3088
        if( !empty( $this->url ))             $output['URL']              = 1;
3089
        if( !empty( $this->xprop ))           $output['X-PROP']           = count( $this->xprop );
3090
        return $output;
3091
        break;
3092
      case 'SETPROPERTYNAMES':
3093
        return array_keys( $this->getConfig( 'propinfo' ));
3094
        break;
3095
      case 'TZID':
3096
        return $this->dtzid;
3097
        break;
3098
      case 'UNIQUE_ID':
3099
        if( empty( $this->unique_id ))
3100
          $this->unique_id  = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost';
3101
        return $this->unique_id;
3102
        break;
3103
    }
3104
  }
3105
/**
3106
 * general component config setting
3107
 *
3108
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3109
 * @since 2.10.18 - 2013-09-06
3110
 * @param mixed   $config
3111
 * @param string  $value
3112
 * @param bool    $softUpdate
3113
 * @uses calendarComponent::getConfig()
3114
 * @uses calendarComponent::$allowEmpty
3115
 * @uses calendarComponent::$format
3116
 * @uses calendarComponent::$language
3117
 * @uses calendarComponent::$nl
3118
 * @uses calendarComponent::$dtzid
3119
 * @uses calendarComponent::$unique_id
3120
 * @uses calendarComponent::$components
3121
 * @uses calendarComponent::copy()
3122
 * @return void
3123
 */
3124
  function setConfig( $config, $value = FALSE, $softUpdate = FALSE ) {
3125
    if( is_array( $config )) {
3126
      $config  = array_change_key_case( $config, CASE_UPPER );
3127
      if( isset( $config['NEWLINECHAR'] ) || isset( $config['NL'] )) {
3128
        $k = ( isset( $config['NEWLINECHAR'] )) ? 'NEWLINECHAR' : 'NL';
3129
        if( FALSE === $this->setConfig( 'NL', $config[$k] ))
3130
          return FALSE;
3131
        unset( $config[$k] );
3132
      }
3133
      foreach( $config as $cKey => $cValue ) {
3134
        if( FALSE === $this->setConfig( $cKey, $cValue, $softUpdate ))
3135
          return FALSE;
3136
      }
3137
      return TRUE;
3138
    }
3139
    else
3140
      $config = strtoupper( $config );
3141
    $res = FALSE;
3142
    switch( $config ) {
3143
      case 'ALLOWEMPTY':
3144
        $this->allowEmpty = $value;
3145
        $subcfg = array( 'ALLOWEMPTY' => $value );
3146
        $res    = TRUE;
3147
        break;
3148
      case 'FORMAT':
3149
        $value  = trim( strtolower( $value ));
3150
        $this->format = $value;
3151
        $this->_createFormat();
3152
        $subcfg = array( 'FORMAT' => $value );
3153
        $res    = TRUE;
3154
        break;
3155
      case 'LANGUAGE':
3156
         // set language for calendar component as defined in [RFC 1766]
3157
        $value  = trim( $value );
3158
        if( empty( $this->language ) || !$softUpdate )
3159
          $this->language = $value;
3160
        $subcfg = array( 'LANGUAGE' => $value );
3161
        $res    = TRUE;
3162
        break;
3163
      case 'NL':
3164
      case 'NEWLINECHAR':
3165
        $this->nl = $value;
3166
        $this->_createFormat();
3167
        $subcfg = array( 'NL' => $value );
3168
        $res    = TRUE;
3169
        break;
3170
      case 'TZID':
3171
        $this->dtzid = $value;
3172
        $subcfg = array( 'TZID' => $value );
3173
        $res    = TRUE;
3174
        break;
3175
      case 'UNIQUE_ID':
3176
        $value  = trim( $value );
3177
        $this->unique_id = $value;
3178
        $subcfg = array( 'UNIQUE_ID' => $value );
3179
        $res    = TRUE;
3180
        break;
3181
      default:  // any unvalid config key.. .
3182
        return TRUE;
3183
    }
3184
    if( !$res ) return FALSE;
3185
    if( isset( $subcfg ) && !empty( $this->components )) {
3186
      foreach( $subcfg as $cfgkey => $cfgvalue ) {
3187
        foreach( $this->components as $cix => $component ) {
3188
          $res = $component->setConfig( $cfgkey, $cfgvalue, $softUpdate );
3189
          if( !$res )
3190
            break 2;
3191
          $this->components[$cix] = $component->copy(); // PHP4 compliant
3192
        }
3193
      }
3194
    }
3195
    return $res;
3196
  }
3197
/*********************************************************************************/
3198
/**
3199
 * delete component property value
3200
 *
3201
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3202
 * @since 2.8.8 - 2011-03-15
3203
 * @param mixed  $propName  bool FALSE => X-property
3204
 * @param int    $propix    specific property in case of multiply occurences
3205
 * @uses calendarComponent::_notExistProp()
3206
 * @uses iCalUtilityFunctions::$mProps2
3207
 * @uses calendarComponent::$propdelix
3208
 * @uses calendarComponent::$action
3209
 * @uses calendarComponent::deletePropertyM()
3210
 * @uses calendarComponent::$attendee
3211
 * @uses calendarComponent::$categories
3212
 * @uses calendarComponent::$class
3213
 * @uses calendarComponent::$comment
3214
 * @uses calendarComponent::$completed
3215
 * @uses calendarComponent::$contact
3216
 * @uses calendarComponent::$created
3217
 * @uses calendarComponent::$description
3218
 * @uses calendarComponent::$dtend
3219
 * @uses iCalUtilityFunctions::$miscComps
3220
 * @uses calendarComponent::$objName
3221
 * @uses calendarComponent::$dtstamp
3222
 * @uses calendarComponent::$dtstart
3223
 * @uses calendarComponent::$due
3224
 * @uses calendarComponent::$duration
3225
 * @uses calendarComponent::$exdate
3226
 * @uses calendarComponent::$exrule
3227
 * @uses calendarComponent::$freebusy
3228
 * @uses calendarComponent::$geo
3229
 * @uses calendarComponent::$lastmodified
3230
 * @uses calendarComponent::$location
3231
 * @uses calendarComponent::$organizer
3232
 * @uses calendarComponent::$percentcomplete
3233
 * @uses calendarComponent::$priority
3234
 * @uses calendarComponent::$rdate
3235
 * @uses calendarComponent::$recurrenceid
3236
 * @uses calendarComponent::$relatedto
3237
 * @uses calendarComponent::$repeat
3238
 * @uses calendarComponent::$requeststatus
3239
 * @uses calendarComponent::$resources
3240
 * @uses calendarComponent::$rrule
3241
 * @uses calendarComponent::$sequence
3242
 * @uses calendarComponent::$status
3243
 * @uses calendarComponent::$summary
3244
 * @uses calendarComponent::$transp
3245
 * @uses calendarComponent::$trigger
3246
 * @uses calendarComponent::$tzid
3247
 * @uses calendarComponent::$tzname
3248
 * @uses calendarComponent::$tzoffsetfrom
3249
 * @uses calendarComponent::$tzoffsetto
3250
 * @uses calendarComponent::$tzurl
3251
 * @uses calendarComponent::$uid
3252
 * @uses calendarComponent::$url
3253
 * @uses calendarComponent::$xprop
3254
 * @return bool, if successfull delete TRUE
3255
 */
3256
  function deleteProperty( $propName=FALSE, $propix=FALSE ) {
3257
    if( $this->_notExistProp( $propName )) return FALSE;
3258
    $propName = strtoupper( $propName );
3259
    if( in_array( $propName, iCalUtilityFunctions::$mProps2 )) {
3260
      if( !$propix )
3261
        $propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1;
3262
      $this->propdelix[$propName] = --$propix;
3263
    }
3264
    $return = FALSE;
3265
    switch( $propName ) {
3266
      case 'ACTION':
3267
        if( !empty( $this->action )) {
3268
          $this->action = '';
3269
          $return = TRUE;
3270
        }
3271
        break;
3272
      case 'ATTACH':
3273
        return $this->deletePropertyM( $this->attach, $this->propdelix[$propName] );
3274
        break;
3275
      case 'ATTENDEE':
3276
        return $this->deletePropertyM( $this->attendee, $this->propdelix[$propName] );
3277
        break;
3278
      case 'CATEGORIES':
3279
        return $this->deletePropertyM( $this->categories, $this->propdelix[$propName] );
3280
        break;
3281
      case 'CLASS':
3282
        if( !empty( $this->class )) {
3283
          $this->class = '';
3284
          $return = TRUE;
3285
        }
3286
        break;
3287
      case 'COMMENT':
3288
        return $this->deletePropertyM( $this->comment, $this->propdelix[$propName] );
3289
        break;
3290
      case 'COMPLETED':
3291
        if( !empty( $this->completed )) {
3292
          $this->completed = '';
3293
          $return = TRUE;
3294
        }
3295
        break;
3296
      case 'CONTACT':
3297
        return $this->deletePropertyM( $this->contact, $this->propdelix[$propName] );
3298
        break;
3299
      case 'CREATED':
3300
        if( !empty( $this->created )) {
3301
          $this->created = '';
3302
          $return = TRUE;
3303
        }
3304
        break;
3305
      case 'DESCRIPTION':
3306
        return $this->deletePropertyM( $this->description, $this->propdelix[$propName] );
3307
        break;
3308
      case 'DTEND':
3309
        if( !empty( $this->dtend )) {
3310
          $this->dtend = '';
3311
          $return = TRUE;
3312
        }
3313
        break;
3314
      case 'DTSTAMP':
3315
        if( in_array( $this->objName, iCalUtilityFunctions::$miscComps ))
3316
          return FALSE;
3317
        if( !empty( $this->dtstamp )) {
3318
          $this->dtstamp = '';
3319
          $return = TRUE;
3320
        }
3321
        break;
3322
      case 'DTSTART':
3323
        if( !empty( $this->dtstart )) {
3324
          $this->dtstart = '';
3325
          $return = TRUE;
3326
        }
3327
        break;
3328
      case 'DUE':
3329
        if( !empty( $this->due )) {
3330
          $this->due = '';
3331
          $return = TRUE;
3332
        }
3333
        break;
3334
      case 'DURATION':
3335
        if( !empty( $this->duration )) {
3336
          $this->duration = '';
3337
          $return = TRUE;
3338
        }
3339
        break;
3340
      case 'EXDATE':
3341
        return $this->deletePropertyM( $this->exdate, $this->propdelix[$propName] );
3342
        break;
3343
      case 'EXRULE':
3344
        return $this->deletePropertyM( $this->exrule, $this->propdelix[$propName] );
3345
        break;
3346
      case 'FREEBUSY':
3347
        return $this->deletePropertyM( $this->freebusy, $this->propdelix[$propName] );
3348
        break;
3349
      case 'GEO':
3350
        if( !empty( $this->geo )) {
3351
          $this->geo = '';
3352
          $return = TRUE;
3353
        }
3354
        break;
3355
      case 'LAST-MODIFIED':
3356
        if( !empty( $this->lastmodified )) {
3357
          $this->lastmodified = '';
3358
          $return = TRUE;
3359
        }
3360
        break;
3361
      case 'LOCATION':
3362
        if( !empty( $this->location )) {
3363
          $this->location = '';
3364
          $return = TRUE;
3365
        }
3366
        break;
3367
      case 'ORGANIZER':
3368
        if( !empty( $this->organizer )) {
3369
          $this->organizer = '';
3370
          $return = TRUE;
3371
        }
3372
        break;
3373
      case 'PERCENT-COMPLETE':
3374
        if( !empty( $this->percentcomplete )) {
3375
          $this->percentcomplete = '';
3376
          $return = TRUE;
3377
        }
3378
        break;
3379
      case 'PRIORITY':
3380
        if( !empty( $this->priority )) {
3381
          $this->priority = '';
3382
          $return = TRUE;
3383
        }
3384
        break;
3385
      case 'RDATE':
3386
        return $this->deletePropertyM( $this->rdate, $this->propdelix[$propName] );
3387
        break;
3388
      case 'RECURRENCE-ID':
3389
        if( !empty( $this->recurrenceid )) {
3390
          $this->recurrenceid = '';
3391
          $return = TRUE;
3392
        }
3393
        break;
3394
      case 'RELATED-TO':
3395
        return $this->deletePropertyM( $this->relatedto, $this->propdelix[$propName] );
3396
        break;
3397
      case 'REPEAT':
3398
        if( !empty( $this->repeat )) {
3399
          $this->repeat = '';
3400
          $return = TRUE;
3401
        }
3402
        break;
3403
      case 'REQUEST-STATUS':
3404
        return $this->deletePropertyM( $this->requeststatus, $this->propdelix[$propName] );
3405
        break;
3406
      case 'RESOURCES':
3407
        return $this->deletePropertyM( $this->resources, $this->propdelix[$propName] );
3408
        break;
3409
      case 'RRULE':
3410
        return $this->deletePropertyM( $this->rrule, $this->propdelix[$propName] );
3411
        break;
3412
      case 'SEQUENCE':
3413
        if( !empty( $this->sequence )) {
3414
          $this->sequence = '';
3415
          $return = TRUE;
3416
        }
3417
        break;
3418
      case 'STATUS':
3419
        if( !empty( $this->status )) {
3420
          $this->status = '';
3421
          $return = TRUE;
3422
        }
3423
        break;
3424
      case 'SUMMARY':
3425
        if( !empty( $this->summary )) {
3426
          $this->summary = '';
3427
          $return = TRUE;
3428
        }
3429
        break;
3430
      case 'TRANSP':
3431
        if( !empty( $this->transp )) {
3432
          $this->transp = '';
3433
          $return = TRUE;
3434
        }
3435
        break;
3436
      case 'TRIGGER':
3437
        if( !empty( $this->trigger )) {
3438
          $this->trigger = '';
3439
          $return = TRUE;
3440
        }
3441
        break;
3442
      case 'TZID':
3443
        if( !empty( $this->tzid )) {
3444
          $this->tzid = '';
3445
          $return = TRUE;
3446
        }
3447
        break;
3448
      case 'TZNAME':
3449
        return $this->deletePropertyM( $this->tzname, $this->propdelix[$propName] );
3450
        break;
3451
      case 'TZOFFSETFROM':
3452
        if( !empty( $this->tzoffsetfrom )) {
3453
          $this->tzoffsetfrom = '';
3454
          $return = TRUE;
3455
        }
3456
        break;
3457
      case 'TZOFFSETTO':
3458
        if( !empty( $this->tzoffsetto )) {
3459
          $this->tzoffsetto = '';
3460
          $return = TRUE;
3461
        }
3462
        break;
3463
      case 'TZURL':
3464
        if( !empty( $this->tzurl )) {
3465
          $this->tzurl = '';
3466
          $return = TRUE;
3467
        }
3468
        break;
3469
      case 'UID':
3470
        if( in_array( $this->objName, iCalUtilityFunctions::$miscComps ))
3471
          return FALSE;
3472
        if( ! empty( $this->uid )) {
3473
          $this->uid = '';
3474
          $return = TRUE;
3475
        }
3476
        break;
3477
      case 'URL':
3478
        if( !empty( $this->url )) {
3479
          $this->url = '';
3480
          $return = TRUE;
3481
        }
3482
        break;
3483
      default:
3484
        $reduced = '';
3485
        if( $propName != 'X-PROP' ) {
3486
          if( !isset( $this->xprop[$propName] )) return FALSE;
3487
          foreach( $this->xprop as $k => $a ) {
3488
            if(( $k != $propName ) && !empty( $a ))
3489
              $reduced[$k] = $a;
3490
          }
3491
        }
3492
        else {
3493
          if( count( $this->xprop ) <= $propix ) { unset( $this->propdelix[$propName] ); return FALSE; }
3494
          $xpropno = 0;
3495
          foreach( $this->xprop as $xpropkey => $xpropvalue ) {
3496
            if( $propix != $xpropno )
3497
              $reduced[$xpropkey] = $xpropvalue;
3498
            $xpropno++;
3499
          }
3500
        }
3501
        $this->xprop = $reduced;
3502
        if( empty( $this->xprop )) {
3503
          unset( $this->propdelix[$propName] );
3504
          return FALSE;
3505
        }
3506
        return TRUE;
3507
    }
3508
    return $return;
3509
  }
3510
/*********************************************************************************/
3511
/**
3512
 * delete component property value, fixing components with multiple occurencies
3513
 *
3514
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3515
 * @since 2.8.8 - 2011-03-15
3516
 * @param array  $multiprop  component (multi-)property
3517
 * @param int    $propix     removal counter
3518
 * @return bool TRUE
3519
 */
3520
  function deletePropertyM( & $multiprop, & $propix ) {
3521
    if( isset( $multiprop[$propix] ))
3522
      unset( $multiprop[$propix] );
3523
    if( empty( $multiprop )) {
3524
      $multiprop = '';
3525
      unset( $propix );
3526
      return FALSE;
3527
    }
3528
    else
3529
      return TRUE;
3530
  }
3531
/**
3532
 * get component property value/params
3533
 *
3534
 * if property has multiply values, consequtive function calls are needed
3535
 *
3536
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3537
 * @since 2.21.13 - 2015-03-29
3538
 * @param string  $propName
3539
 * @param int     $propix   specific property in case of multiply occurences
3540
 * @param bool    $inclParam
3541
 * @param bool    $specform
3542
 * @uses calendarComponent::getProperty()
3543
 * @uses iCalUtilityFunctions::_geo2str2()
3544
 * @uses iCalUtilityFunctions::$geoLatFmt
3545
 * @uses iCalUtilityFunctions::$geoLongFmt
3546
 * @uses calendarComponent::_notExistProp()
3547
 * @uses iCalUtilityFunctions::$mProps2
3548
 * @uses calendarComponent::$propix
3549
 * @uses calendarComponent::$action
3550
 * @uses calendarComponent::$attendee
3551
 * @uses calendarComponent::$categories
3552
 * @uses calendarComponent::$class
3553
 * @uses calendarComponent::$comment
3554
 * @uses calendarComponent::$completed
3555
 * @uses calendarComponent::$contact
3556
 * @uses calendarComponent::$created
3557
 * @uses calendarComponent::$description
3558
 * @uses calendarComponent::$dtend
3559
 * @uses iCalUtilityFunctions::$miscComps
3560
 * @uses calendarComponent::$dtstamp
3561
 * @uses calendarComponent::_makeDtstamp()
3562
 * @uses calendarComponent::$dtstart
3563
 * @uses calendarComponent::$due
3564
 * @uses calendarComponent::$duration
3565
 * @uses iCalUtilityFunctions::_duration2date()
3566
 * @uses calendarComponent::$exdate
3567
 * @uses calendarComponent::$exrule
3568
 * @uses calendarComponent::$freebusy
3569
 * @uses calendarComponent::$geo
3570
 * @uses calendarComponent::$lastmodified
3571
 * @uses calendarComponent::$location
3572
 * @uses calendarComponent::$organizer
3573
 * @uses calendarComponent::$percentcomplete
3574
 * @uses calendarComponent::$priority
3575
 * @uses calendarComponent::$rdate
3576
 * @uses calendarComponent::$recurrenceid
3577
 * @uses calendarComponent::$relatedto
3578
 * @uses calendarComponent::$repeat
3579
 * @uses calendarComponent::$requeststatus
3580
 * @uses calendarComponent::$resources
3581
 * @uses calendarComponent::$rrule
3582
 * @uses calendarComponent::$sequence
3583
 * @uses calendarComponent::$status
3584
 * @uses calendarComponent::$summary
3585
 * @uses calendarComponent::$transp
3586
 * @uses calendarComponent::$trigger
3587
 * @uses calendarComponent::$tzid
3588
 * @uses calendarComponent::$tzname
3589
 * @uses calendarComponent::$tzoffsetfrom
3590
 * @uses calendarComponent::$tzoffsetto
3591
 * @uses calendarComponent::$tzurl
3592
 * @uses calendarComponent::$uid
3593
 * @uses calendarComponent::$objName
3594
 * @uses calendarComponent::_makeuid()
3595
 * @uses calendarComponent::$url
3596
 * @uses calendarComponent::$xprop
3597
 * @return mixed
3598
 */
3599
  function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE, $specform=FALSE ) {
3600
    if( 'GEOLOCATION' == strtoupper( $propName )) {
3601
      $content = ( FALSE === ( $loc = $this->getProperty( 'LOCATION' ))) ? '' : $loc.' ';
3602
      if( FALSE === ( $geo = $this->getProperty( 'GEO' )))
3603
        return FALSE;
3604
      return $content.
3605
             iCalUtilityFunctions::_geo2str2( $geo['latitude'],  iCalUtilityFunctions::$geoLatFmt ).
3606
             iCalUtilityFunctions::_geo2str2( $geo['longitude'], iCalUtilityFunctions::$geoLongFmt ).'/';
3607
    }
3608
    if( $this->_notExistProp( $propName )) return FALSE;
3609
    $propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP';
3610
    if( in_array( $propName, iCalUtilityFunctions::$mProps2 )) {
3611
      if( empty( $propix ))
3612
        $propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1;
3613
      $this->propix[$propName] = --$propix;
3614
    }
3615
    switch( $propName ) {
3616
      case 'ACTION':
3617
        if( isset( $this->action['value'] )) return ( $inclParam ) ? $this->action : $this->action['value'];
3618
        break;
3619
      case 'ATTACH':
3620
        $ak = ( is_array( $this->attach )) ? array_keys( $this->attach ) : array();
3621
        while( is_array( $this->attach ) && !isset( $this->attach[$propix] ) && ( 0 < count( $this->attach )) && ( $propix < end( $ak )))
3622
          $propix++;
3623
        $this->propix[$propName] = $propix;
3624
        if( !isset( $this->attach[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3625
        return ( $inclParam ) ? $this->attach[$propix] : $this->attach[$propix]['value'];
3626
        break;
3627
      case 'ATTENDEE':
3628
        $ak = ( is_array( $this->attendee )) ? array_keys( $this->attendee ) : array();
3629
        while( is_array( $this->attendee ) && !isset( $this->attendee[$propix] ) && ( 0 < count( $this->attendee )) && ( $propix < end( $ak )))
3630
          $propix++;
3631
        $this->propix[$propName] = $propix;
3632
        if( !isset( $this->attendee[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3633
        return ( $inclParam ) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
3634
        break;
3635
      case 'CATEGORIES':
3636
        $ak = ( is_array( $this->categories )) ? array_keys( $this->categories ) : array();
3637
        while( is_array( $this->categories ) && !isset( $this->categories[$propix] ) && ( 0 < count( $this->categories )) && ( $propix < end( $ak )))
3638
          $propix++;
3639
        $this->propix[$propName] = $propix;
3640
        if( !isset( $this->categories[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3641
        return ( $inclParam ) ? $this->categories[$propix] : $this->categories[$propix]['value'];
3642
        break;
3643
      case 'CLASS':
3644
        if( isset( $this->class['value'] )) return ( $inclParam ) ? $this->class : $this->class['value'];
3645
        break;
3646
      case 'COMMENT':
3647
        $ak = ( is_array( $this->comment )) ? array_keys( $this->comment ) : array();
3648
        while( is_array( $this->comment ) && !isset( $this->comment[$propix] ) && ( 0 < count( $this->comment )) && ( $propix < end( $ak )))
3649
          $propix++;
3650
        $this->propix[$propName] = $propix;
3651
        if( !isset( $this->comment[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3652
        return ( $inclParam ) ? $this->comment[$propix] : $this->comment[$propix]['value'];
3653
        break;
3654
      case 'COMPLETED':
3655
        if( isset( $this->completed['value'] )) return ( $inclParam ) ? $this->completed : $this->completed['value'];
3656
        break;
3657
      case 'CONTACT':
3658
        $ak = ( is_array( $this->contact )) ? array_keys( $this->contact ) : array();
3659
        while( is_array( $this->contact ) && !isset( $this->contact[$propix] ) && ( 0 < count( $this->contact )) && ( $propix < end( $ak )))
3660
          $propix++;
3661
        $this->propix[$propName] = $propix;
3662
        if( !isset( $this->contact[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3663
        return ( $inclParam ) ? $this->contact[$propix] : $this->contact[$propix]['value'];
3664
        break;
3665
      case 'CREATED':
3666
        if( isset( $this->created['value'] )) return ( $inclParam ) ? $this->created : $this->created['value'];
3667
        break;
3668
      case 'DESCRIPTION':
3669
        $ak = ( is_array( $this->description )) ? array_keys( $this->description ) : array();
3670
        while( is_array( $this->description ) && !isset( $this->description[$propix] ) && ( 0 < count( $this->description )) && ( $propix < end( $ak )))
3671
          $propix++;
3672
        $this->propix[$propName] = $propix;
3673
        if( !isset( $this->description[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3674
        return ( $inclParam ) ? $this->description[$propix] : $this->description[$propix]['value'];
3675
        break;
3676
      case 'DTEND':
3677
        if( isset( $this->dtend['value'] )) return ( $inclParam ) ? $this->dtend : $this->dtend['value'];
3678
        break;
3679
      case 'DTSTAMP':
3680
        if( in_array( $this->objName, iCalUtilityFunctions::$miscComps ))
3681
          return;
3682
        if( !isset( $this->dtstamp['value'] ))
3683
          $this->_makeDtstamp();
3684
        return ( $inclParam ) ? $this->dtstamp : $this->dtstamp['value'];
3685
        break;
3686
      case 'DTSTART':
3687
        if( isset( $this->dtstart['value'] )) return ( $inclParam ) ? $this->dtstart : $this->dtstart['value'];
3688
        break;
3689
      case 'DUE':
3690
        if( isset( $this->due['value'] )) return ( $inclParam ) ? $this->due : $this->due['value'];
3691
        break;
3692
      case 'DURATION':
3693
        if( ! isset( $this->duration['value'] )) return FALSE;
3694
        $value  = ( $specform && isset( $this->dtstart['value'] ) && isset( $this->duration['value'] )) ? iCalUtilityFunctions::_duration2date( $this->dtstart['value'], $this->duration['value'] ) : $this->duration['value'];
3695
        $params = ( $specform && $inclParam && isset( $this->dtstart['params']['TZID'] )) ? array_merge((array) $this->duration['params'], $this->dtstart['params'] ) : $this->duration['params'];
3696
        return ( $inclParam ) ? array( 'value' => $value, 'params' =>  $params ) : $value;
3697
        break;
3698
      case 'EXDATE':
3699
        $ak = ( is_array( $this->exdate )) ? array_keys( $this->exdate ) : array();
3700
        while( is_array( $this->exdate ) && !isset( $this->exdate[$propix] ) && ( 0 < count( $this->exdate )) && ( $propix < end( $ak )))
3701
          $propix++;
3702
        $this->propix[$propName] = $propix;
3703
        if( !isset( $this->exdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3704
        return ( $inclParam ) ? $this->exdate[$propix] : $this->exdate[$propix]['value'];
3705
        break;
3706
      case 'EXRULE':
3707
        $ak = ( is_array( $this->exrule )) ? array_keys( $this->exrule ) : array();
3708
        while( is_array( $this->exrule ) && !isset( $this->exrule[$propix] ) && ( 0 < count( $this->exrule )) && ( $propix < end( $ak )))
3709
          $propix++;
3710
        $this->propix[$propName] = $propix;
3711
        if( !isset( $this->exrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3712
        return ( $inclParam ) ? $this->exrule[$propix] : $this->exrule[$propix]['value'];
3713
        break;
3714
      case 'FREEBUSY':
3715
        $ak = ( is_array( $this->freebusy )) ? array_keys( $this->freebusy ) : array();
3716
        while( is_array( $this->freebusy ) && !isset( $this->freebusy[$propix] ) && ( 0 < count( $this->freebusy )) && ( $propix < end( $ak )))
3717
          $propix++;
3718
        $this->propix[$propName] = $propix;
3719
        if( !isset( $this->freebusy[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3720
        return ( $inclParam ) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value'];
3721
        break;
3722
      case 'GEO':
3723
        if( isset( $this->geo['value'] )) return ( $inclParam ) ? $this->geo : $this->geo['value'];
3724
        break;
3725
      case 'LAST-MODIFIED':
3726
        if( isset( $this->lastmodified['value'] )) return ( $inclParam ) ? $this->lastmodified : $this->lastmodified['value'];
3727
        break;
3728
      case 'LOCATION':
3729
        if( isset( $this->location['value'] )) return ( $inclParam ) ? $this->location : $this->location['value'];
3730
        break;
3731
      case 'ORGANIZER':
3732
        if( isset( $this->organizer['value'] )) return ( $inclParam ) ? $this->organizer : $this->organizer['value'];
3733
        break;
3734
      case 'PERCENT-COMPLETE':
3735
        if( isset( $this->percentcomplete['value'] )) return ( $inclParam ) ? $this->percentcomplete : $this->percentcomplete['value'];
3736
        break;
3737
      case 'PRIORITY':
3738
        if( isset( $this->priority['value'] )) return ( $inclParam ) ? $this->priority : $this->priority['value'];
3739
        break;
3740
      case 'RDATE':
3741
        $ak = ( is_array( $this->rdate )) ? array_keys( $this->rdate ) : array();
3742
        while( is_array( $this->rdate ) && !isset( $this->rdate[$propix] ) && ( 0 < count( $this->rdate )) && ( $propix < end( $ak )))
3743
          $propix++;
3744
        $this->propix[$propName] = $propix;
3745
        if( !isset( $this->rdate[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3746
        return ( $inclParam ) ? $this->rdate[$propix] : $this->rdate[$propix]['value'];
3747
        break;
3748
      case 'RECURRENCE-ID':
3749
        if( isset( $this->recurrenceid['value'] )) return ( $inclParam ) ? $this->recurrenceid : $this->recurrenceid['value'];
3750
        break;
3751
      case 'RELATED-TO':
3752
        $ak = ( is_array( $this->relatedto )) ? array_keys( $this->relatedto ) : array();
3753
        while( is_array( $this->relatedto ) && !isset( $this->relatedto[$propix] ) && ( 0 < count( $this->relatedto )) && ( $propix < end( $ak )))
3754
          $propix++;
3755
        $this->propix[$propName] = $propix;
3756
        if( !isset( $this->relatedto[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3757
        return ( $inclParam ) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value'];
3758
        break;
3759
      case 'REPEAT':
3760
        if( isset( $this->repeat['value'] )) return ( $inclParam ) ? $this->repeat : $this->repeat['value'];
3761
        break;
3762
      case 'REQUEST-STATUS':
3763
        $ak = ( is_array( $this->requeststatus )) ? array_keys( $this->requeststatus ) : array();
3764
        while( is_array( $this->requeststatus ) && !isset( $this->requeststatus[$propix] ) && ( 0 < count( $this->requeststatus )) && ( $propix < end( $ak )))
3765
          $propix++;
3766
        $this->propix[$propName] = $propix;
3767
        if( !isset( $this->requeststatus[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3768
        return ( $inclParam ) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value'];
3769
        break;
3770
      case 'RESOURCES':
3771
        $ak = ( is_array( $this->resources )) ? array_keys( $this->resources ) : array();
3772
        while( is_array( $this->resources ) && !isset( $this->resources[$propix] ) && ( 0 < count( $this->resources )) && ( $propix < end( $ak )))
3773
          $propix++;
3774
        $this->propix[$propName] = $propix;
3775
        if( !isset( $this->resources[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3776
        return ( $inclParam ) ? $this->resources[$propix] : $this->resources[$propix]['value'];
3777
        break;
3778
      case 'RRULE':
3779
        $ak = ( is_array( $this->rrule )) ? array_keys( $this->rrule ) : array();
3780
        while( is_array( $this->rrule ) && !isset( $this->rrule[$propix] ) && ( 0 < count( $this->rrule )) && ( $propix < end( $ak )))
3781
          $propix++;
3782
        $this->propix[$propName] = $propix;
3783
        if( !isset( $this->rrule[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3784
        return ( $inclParam ) ? $this->rrule[$propix] : $this->rrule[$propix]['value'];
3785
        break;
3786
      case 'SEQUENCE':
3787
        if( isset( $this->sequence['value'] )) return ( $inclParam ) ? $this->sequence : $this->sequence['value'];
3788
        break;
3789
      case 'STATUS':
3790
        if( isset( $this->status['value'] )) return ( $inclParam ) ? $this->status : $this->status['value'];
3791
        break;
3792
      case 'SUMMARY':
3793
        if( isset( $this->summary['value'] )) return ( $inclParam ) ? $this->summary : $this->summary['value'];
3794
        break;
3795
      case 'TRANSP':
3796
        if( isset( $this->transp['value'] )) return ( $inclParam ) ? $this->transp : $this->transp['value'];
3797
        break;
3798
      case 'TRIGGER':
3799
        if( isset( $this->trigger['value'] )) return ( $inclParam ) ? $this->trigger : $this->trigger['value'];
3800
        break;
3801
      case 'TZID':
3802
        if( isset( $this->tzid['value'] )) return ( $inclParam ) ? $this->tzid : $this->tzid['value'];
3803
        break;
3804
      case 'TZNAME':
3805
        $ak = ( is_array( $this->tzname )) ? array_keys( $this->tzname ) : array();
3806
        while( is_array( $this->tzname ) && !isset( $this->tzname[$propix] ) && ( 0 < count( $this->tzname )) && ( $propix < end( $ak )))
3807
          $propix++;
3808
        $this->propix[$propName] = $propix;
3809
        if( !isset( $this->tzname[$propix] )) { unset( $this->propix[$propName] ); return FALSE; }
3810
        return ( $inclParam ) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
3811
        break;
3812
      case 'TZOFFSETFROM':
3813
        if( isset( $this->tzoffsetfrom['value'] )) return ( $inclParam ) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
3814
        break;
3815
      case 'TZOFFSETTO':
3816
        if( isset( $this->tzoffsetto['value'] )) return ( $inclParam ) ? $this->tzoffsetto : $this->tzoffsetto['value'];
3817
        break;
3818
      case 'TZURL':
3819
        if( isset( $this->tzurl['value'] )) return ( $inclParam ) ? $this->tzurl : $this->tzurl['value'];
3820
        break;
3821
      case 'UID':
3822
        if( in_array( $this->objName, iCalUtilityFunctions::$miscComps ))
3823
          return FALSE;
3824
        if( empty( $this->uid ))
3825
          $this->_makeuid();
3826
        return ( $inclParam ) ? $this->uid : $this->uid['value'];
3827
        break;
3828
      case 'URL':
3829
        if( isset( $this->url['value'] )) return ( $inclParam ) ? $this->url : $this->url['value'];
3830
        break;
3831
      default:
3832
        if( $propName != 'X-PROP' ) {
3833
          if( !isset( $this->xprop[$propName] )) return FALSE;
3834
          return ( $inclParam ) ? array( $propName, $this->xprop[$propName] )
3835
                                : array( $propName, $this->xprop[$propName]['value'] );
3836
        }
3837
        else {
3838
          if( empty( $this->xprop )) return FALSE;
3839
          $xpropno = 0;
3840
          foreach( $this->xprop as $xpropkey => $xpropvalue ) {
3841
            if( $propix == $xpropno )
3842
              return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] )
3843
                                    : array( $xpropkey, $this->xprop[$xpropkey]['value'] );
3844
            else
3845
              $xpropno++;
3846
          }
3847
          return FALSE; // not found ??
3848
        }
3849
    }
3850
    return FALSE;
3851
  }
3852
/**
3853
 * returns calendar property unique values for 'ATTENDEE', 'CATEGORIES', 'CONTACT', 'RELATED-TO' or 'RESOURCES' and for each, number of occurrence
3854
 *
3855
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3856
 * @since 2.21.11 - 2015-03-21
3857
 * @param string  $propName
3858
 * @param array   $output    incremented result array
3859
 * @uses iCalUtilityFunctions::$mProps1
3860
 * @uses calendarComponent::getProperty()
3861
 * return void
3862
 */
3863
  function _getProperties( $propName, & $output ) {
3864
    if( empty( $output ))
3865
      $output = array();
3866
    if( !in_array( strtoupper( $propName ), iCalUtilityFunctions::$mProps1 ))
3867
      return $output;
3868
    while( FALSE !== ( $content = $this->getProperty( $propName ))) {
3869
      if( empty( $content ))
3870
        continue;
3871
      if( is_array( $content )) {
3872
        foreach( $content as $part ) {
3873
          if( FALSE !== strpos( $part, ',' )) {
3874
            $part = explode( ',', $part );
3875
            foreach( $part as $thePart ) {
3876
              $thePart = trim( $thePart );
3877
              if( !empty( $thePart )) {
3878
                if( !isset( $output[$thePart] ))
3879
                  $output[$thePart] = 1;
3880
                else
3881
                  $output[$thePart] += 1;
3882
              }
3883
            }
3884
          }
3885
          else {
3886
            $part = trim( $part );
3887
            if( !isset( $output[$part] ))
3888
              $output[$part] = 1;
3889
            else
3890
              $output[$part] += 1;
3891
          }
3892
        }
3893
      } // end if( is_array( $content ))
3894
      elseif( FALSE !== strpos( $content, ',' )) {
3895
        $content = explode( ',', $content );
3896
        foreach( $content as $thePart ) {
3897
          $thePart = trim( $thePart );
3898
          if( !empty( $thePart )) {
3899
            if( !isset( $output[$thePart] ))
3900
              $output[$thePart] = 1;
3901
            else
3902
              $output[$thePart] += 1;
3903
          }
3904
        }
3905
      } // end elseif( FALSE !== strpos( $content, ',' ))
3906
      else {
3907
        $content = trim( $content );
3908
        if( !empty( $content )) {
3909
          if( !isset( $output[$content] ))
3910
            $output[$content] = 1;
3911
          else
3912
            $output[$content] += 1;
3913
        }
3914
      }
3915
    }
3916
    ksort( $output );
3917
  }
3918
/**
3919
 * general component property setting
3920
 *
3921
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
3922
 * @since 2.5.1 - 2008-11-05
3923
 * @param mixed $args variable number of function arguments,
3924
 *                    first argument is ALWAYS component name,
3925
 *                    second ALWAYS component value!
3926
 * @uses calendarComponent::getProperty()
3927
 * @uses calendarComponent::_notExistProp()
3928
 * @uses calendarComponent::getConfig()
3929
 * @uses calendarComponent::setAction()
3930
 * @uses calendarComponent::setAttendee()
3931
 * @uses calendarComponent::setCategories()
3932
 * @uses calendarComponent::setClass()
3933
 * @uses calendarComponent::setComment()
3934
 * @uses calendarComponent::setCompleted()
3935
 * @uses calendarComponent::setContact()
3936
 * @uses calendarComponent::setCreated()
3937
 * @uses calendarComponent::setDescription()
3938
 * @uses calendarComponent::setDtend()
3939
 * @uses calendarComponent::setDtstamp()
3940
 * @uses calendarComponent::setDtstart()
3941
 * @uses calendarComponent::setDue()
3942
 * @uses calendarComponent::setDuration()
3943
 * @uses calendarComponent::setExdate()
3944
 * @uses calendarComponent::setExrule()
3945
 * @uses calendarComponent::setFreebusy()
3946
 * @uses calendarComponent::setGeo()
3947
 * @uses calendarComponent::setLastmodified()
3948
 * @uses calendarComponent::setLocation()
3949
 * @uses calendarComponent::setOrganizer()
3950
 * @uses calendarComponent::setPercentcomplete()
3951
 * @uses calendarComponent::setPriority()
3952
 * @uses calendarComponent::setRdate()
3953
 * @uses calendarComponent::setRecurrenceid()
3954
 * @uses calendarComponent::setRelatedto()
3955
 * @uses calendarComponent::setRepeat()
3956
 * @uses calendarComponent::setRequeststatus()
3957
 * @uses calendarComponent::setResources()
3958
 * @uses calendarComponent::setRrule()
3959
 * @uses calendarComponent::setSequence()
3960
 * @uses calendarComponent::setStatus()
3961
 * @uses calendarComponent::setSummary()
3962
 * @uses calendarComponent::setTransp()
3963
 * @uses calendarComponent::setTrigger()
3964
 * @uses calendarComponent::setTzid()
3965
 * @uses calendarComponent::setTzname()
3966
 * @uses calendarComponent::setTzoffsetfrom()
3967
 * @uses calendarComponent::setTzoffsetto()
3968
 * @uses calendarComponent::setTzurl()
3969
 * @uses calendarComponent::setUid()
3970
 * @uses calendarComponent::$objName
3971
 * @uses calendarComponent::setUrl()
3972
 * @uses calendarComponent::setXprop()
3973
 * @return void
3974
 */
3975
  function setProperty() {
3976
    $numargs    = func_num_args();
3977
    if( 1 > $numargs ) return FALSE;
3978
    $arglist    = func_get_args();
3979
    if( $this->_notExistProp( $arglist[0] )) return FALSE;
3980
    if( !$this->getConfig( 'allowEmpty' ) && ( !isset( $arglist[1] ) || empty( $arglist[1] )))
3981
      return FALSE;
3982
    $arglist[0] = strtoupper( $arglist[0] );
3983
    for( $argix=$numargs; $argix < 12; $argix++ ) {
3984
      if( !isset( $arglist[$argix] ))
3985
        $arglist[$argix] = null;
3986
    }
3987
    switch( $arglist[0] ) {
3988
      case 'ACTION':
3989
        return $this->setAction(          $arglist[1], $arglist[2] );
3990
      case 'ATTACH':
3991
        return $this->setAttach(          $arglist[1], $arglist[2], $arglist[3] );
3992
      case 'ATTENDEE':
3993
        return $this->setAttendee(        $arglist[1], $arglist[2], $arglist[3] );
3994
      case 'CATEGORIES':
3995
        return $this->setCategories(      $arglist[1], $arglist[2], $arglist[3] );
3996
      case 'CLASS':
3997
        return $this->setClass(           $arglist[1], $arglist[2] );
3998
      case 'COMMENT':
3999
        return $this->setComment(         $arglist[1], $arglist[2], $arglist[3] );
4000
      case 'COMPLETED':
4001
        return $this->setCompleted(       $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
4002
      case 'CONTACT':
4003
        return $this->setContact(         $arglist[1], $arglist[2], $arglist[3] );
4004
      case 'CREATED':
4005
        return $this->setCreated(         $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
4006
      case 'DESCRIPTION':
4007
        return $this->setDescription(     $arglist[1], $arglist[2], $arglist[3] );
4008
      case 'DTEND':
4009
        return $this->setDtend(           $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
4010
      case 'DTSTAMP':
4011
        return $this->setDtstamp(         $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
4012
      case 'DTSTART':
4013
        return $this->setDtstart(         $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
4014
      case 'DUE':
4015
        return $this->setDue(             $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
4016
      case 'DURATION':
4017
        return $this->setDuration(        $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6] );
4018
      case 'EXDATE':
4019
        return $this->setExdate(          $arglist[1], $arglist[2], $arglist[3] );
4020
      case 'EXRULE':
4021
        return $this->setExrule(          $arglist[1], $arglist[2], $arglist[3] );
4022
      case 'FREEBUSY':
4023
        return $this->setFreebusy(        $arglist[1], $arglist[2], $arglist[3], $arglist[4] );
4024
      case 'GEO':
4025
        return $this->setGeo(             $arglist[1], $arglist[2], $arglist[3] );
4026
      case 'LAST-MODIFIED':
4027
        return $this->setLastModified(    $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7] );
4028
      case 'LOCATION':
4029
        return $this->setLocation(        $arglist[1], $arglist[2] );
4030
      case 'ORGANIZER':
4031
        return $this->setOrganizer(       $arglist[1], $arglist[2] );
4032
      case 'PERCENT-COMPLETE':
4033
        return $this->setPercentComplete( $arglist[1], $arglist[2] );
4034
      case 'PRIORITY':
4035
        return $this->setPriority(        $arglist[1], $arglist[2] );
4036
      case 'RDATE':
4037
        return $this->setRdate(           $arglist[1], $arglist[2], $arglist[3] );
4038
      case 'RECURRENCE-ID':
4039
       return $this->setRecurrenceid(     $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8] );
4040
      case 'RELATED-TO':
4041
        return $this->setRelatedTo(       $arglist[1], $arglist[2], $arglist[3] );
4042
      case 'REPEAT':
4043
        return $this->setRepeat(          $arglist[1], $arglist[2] );
4044
      case 'REQUEST-STATUS':
4045
        return $this->setRequestStatus(   $arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5] );
4046
      case 'RESOURCES':
4047
        return $this->setResources(       $arglist[1], $arglist[2], $arglist[3] );
4048
      case 'RRULE':
4049
        return $this->setRrule(           $arglist[1], $arglist[2], $arglist[3] );
4050
      case 'SEQUENCE':
4051
        return $this->setSequence(        $arglist[1], $arglist[2] );
4052
      case 'STATUS':
4053
        return $this->setStatus(          $arglist[1], $arglist[2] );
4054
      case 'SUMMARY':
4055
        return $this->setSummary(         $arglist[1], $arglist[2] );
4056
      case 'TRANSP':
4057
        return $this->setTransp(          $arglist[1], $arglist[2] );
4058
      case 'TRIGGER':
4059
        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] );
4060
      case 'TZID':
4061
        return $this->setTzid(            $arglist[1], $arglist[2] );
4062
      case 'TZNAME':
4063
        return $this->setTzname(          $arglist[1], $arglist[2], $arglist[3] );
4064
      case 'TZOFFSETFROM':
4065
        return $this->setTzoffsetfrom(    $arglist[1], $arglist[2] );
4066
      case 'TZOFFSETTO':
4067
        return $this->setTzoffsetto(      $arglist[1], $arglist[2] );
4068
      case 'TZURL':
4069
        return $this->setTzurl(           $arglist[1], $arglist[2] );
4070
      case 'UID':
4071
        return $this->setUid(             $arglist[1], $arglist[2] );
4072
      case 'URL':
4073
        return $this->setUrl(             $arglist[1], $arglist[2] );
4074
      default:
4075
        return $this->setXprop(           $arglist[0], $arglist[1], $arglist[2] );
4076
    }
4077
    return FALSE;
4078
  }
4079
/*********************************************************************************/
4080
/**
4081
 * parse component unparsed data into properties
4082
 *
4083
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4084
 * @since 2.20.3 - 2015-03-05
4085
 * @param mixed $unparsedtext   strict rfc2445 formatted, single property string or array of strings
4086
 * @uses calendarComponent::getConfig()
4087
 * @uses iCalUtilityFunctions::convEolChar()
4088
 * @uses calendarComponent::$unparsed
4089
 * @uses calendarComponent::$components
4090
 * @uses calendarComponent::copy()
4091
 * @uses iCalUtilityFunctions::_splitContent()
4092
 * @uses calendarComponent::setProperty()
4093
 * @uses iCalUtilityFunctions::_strunrep()
4094
 * @uses calendarComponent::parse()
4095
 * @return bool FALSE if error occurs during parsing
4096
 */
4097
  function parse( $unparsedtext=null ) {
4098
    $nl = $this->getConfig( 'nl' );
4099
    if( !empty( $unparsedtext )) {
4100
      if( is_array( $unparsedtext ))
4101
        $unparsedtext = implode( '\n'.$nl, $unparsedtext );
4102
      $unparsedtext = iCalUtilityFunctions::convEolChar( $unparsedtext, $nl );
4103
    }
4104
    elseif( !isset( $this->unparsed ))
4105
      $unparsedtext = array();
4106
    else
4107
      $unparsedtext = $this->unparsed;
4108
            /* skip leading (empty/invalid) lines */
4109
    foreach( $unparsedtext as $lix => $line ) {
4110
      if( FALSE !== ( $pos = stripos( $line, 'BEGIN:' ))) {
4111
        $unparsedtext[$lix] = substr( $unparsedtext[$lix], $pos );
4112
        break;
4113
      }
4114
      $tst = trim( $line );
4115
      if(( '\n' == $tst ) || empty( $tst ))
4116
        unset( $unparsedtext[$lix] );
4117
    }
4118
    $this->unparsed = array();
4119
    $comp           = & $this;
4120
    $config         = $this->getConfig();
4121
    $compsync = $subsync = 0;
4122
    foreach ( $unparsedtext as $lix => $line ) {
4123
      if( 'END:VALARM'         == strtoupper( substr( $line, 0, 10 ))) {
4124
        if( 1 != $subsync ) return FALSE;
4125
        $this->components[]     = $comp->copy();
4126
        $subsync--;
4127
      }
4128
      elseif( 'END:DAYLIGHT'   == strtoupper( substr( $line, 0, 12 ))) {
4129
        if( 1 != $subsync ) return FALSE;
4130
        $this->components[]     = $comp->copy();
4131
        $subsync--;
4132
      }
4133
      elseif( 'END:STANDARD'   == strtoupper( substr( $line, 0, 12 ))) {
4134
        if( 1 != $subsync ) return FALSE;
4135
        array_unshift( $this->components, $comp->copy());
4136
        $subsync--;
4137
      }
4138
      elseif( 'END:'           == strtoupper( substr( $line, 0, 4 ))) { // end:<component>
4139
        if( 1 != $compsync ) return FALSE;
4140
        if( 0 < $subsync )
4141
          $this->components[]   = $comp->copy();
4142
        $compsync--;
4143
        break;                       /* skip trailing empty lines */
4144
      }
4145
      elseif( 'BEGIN:VALARM'   == strtoupper( substr( $line, 0, 12 ))) {
4146
        $comp = new valarm( $config);
4147
        $subsync++;
4148
      }
4149
      elseif( 'BEGIN:STANDARD' == strtoupper( substr( $line, 0, 14 ))) {
4150
        $comp = new vtimezone( 'standard', $config );
4151
        $subsync++;
4152
      }
4153
      elseif( 'BEGIN:DAYLIGHT' == strtoupper( substr( $line, 0, 14 ))) {
4154
        $comp = new vtimezone( 'daylight', $config );
4155
        $subsync++;
4156
      }
4157
      elseif( 'BEGIN:'         == strtoupper( substr( $line, 0, 6 )))  // begin:<component>
4158
        $compsync++;
4159
      else
4160
        $comp->unparsed[]       = $line;
4161
    }
4162
    if( 0 < $subsync )
4163
      $this->components[]   = $comp->copy();
4164
    unset( $config );
4165
            /* concatenate property values spread over several lines */
4166
    $lastix    = -1;
4167
    $propnames = array( 'action', 'attach', 'attendee', 'categories', 'comment', 'completed'
4168
                      , 'contact', 'class', 'created', 'description', 'dtend', 'dtstart'
4169
                      , 'dtstamp', 'due', 'duration', 'exdate', 'exrule', 'freebusy', 'geo'
4170
                      , 'last-modified', 'location', 'organizer', 'percent-complete'
4171
                      , 'priority', 'rdate', 'recurrence-id', 'related-to', 'repeat'
4172
                      , 'request-status', 'resources', 'rrule', 'sequence', 'status'
4173
                      , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom'
4174
                      , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-' );
4175
    $proprows  = array();
4176
    for( $i = 0; $i < count( $this->unparsed ); $i++ ) { // concatenate lines
4177
      $line = rtrim( $this->unparsed[$i], $nl );
4178
      while( isset( $this->unparsed[$i+1] ) && !empty( $this->unparsed[$i+1] ) && ( ' ' == $this->unparsed[$i+1]{0} ))
4179
        $line .= rtrim( substr( $this->unparsed[++$i], 1 ), $nl );
4180
      $proprows[] = $line;
4181
    }
4182
            /* parse each property 'line' */
4183
    foreach( $proprows as $line ) {
4184
      if( '\n' == substr( $line, -2 ))
4185
        $line = substr( $line, 0, -2 );
4186
            /* get propname */
4187
      $propname = null;
4188
      $cix = 0;
4189
      while( isset( $line[$cix] )) {
4190
        if( in_array( $line[$cix], array( ':', ';' )))
4191
          break;
4192
        else
4193
          $propname .= $line[$cix];
4194
        $cix++;
4195
      }
4196
      if(( 'x-' == substr( $propname, 0, 2 )) || ( 'X-' == substr( $propname, 0, 2 ))) {
4197
        $propname2 = $propname;
4198
        $propname  = 'X-';
4199
      }
4200
      if( !in_array( strtolower( $propname ), $propnames )) // skip non standard property names
4201
        continue;
4202
            /* rest of the line is opt.params and value */
4203
      $line = substr( $line, $cix );
4204
            /* separate attributes from value */
4205
      iCalUtilityFunctions::_splitContent( $line, $propAttr );
4206
            /* call setProperty( $propname.. . */
4207
      switch( strtoupper( $propname )) {
4208
        case 'ATTENDEE':
4209
          foreach( $propAttr as $pix => $attr ) {
4210
            if( !in_array( strtoupper( $pix ), array( 'MEMBER', 'DELEGATED-TO', 'DELEGATED-FROM' )))
4211
              continue;
4212
            $attr2 = explode( ',', $attr );
4213
              if( 1 < count( $attr2 ))
4214
                $propAttr[$pix] = $attr2;
4215
          }
4216
          $this->setProperty( $propname, $line, $propAttr );
4217
          break;
4218
        case 'CATEGORIES':
4219
        case 'RESOURCES':
4220
          if( FALSE !== strpos( $line, ',' )) {
4221
            $content  = array( 0 => '' );
4222
            $cix = $lix = 0;
4223
            while( FALSE !== substr( $line, $lix, 1 )) {
4224
              if(( ',' == $line[$lix] ) && ( "\\" != $line[( $lix - 1 )])) {
4225
                $cix++;
4226
                $content[$cix] = '';
4227
              }
4228
              else
4229
                $content[$cix] .= $line[$lix];
4230
              $lix++;
4231
            }
4232
            if( 1 < count( $content )) {
4233
              $content = array_values( $content );
4234
              foreach( $content as $cix => $contentPart )
4235
                $content[$cix] = iCalUtilityFunctions::_strunrep( $contentPart );
4236
              $this->setProperty( $propname, $content, $propAttr );
4237
              break;
4238
            }
4239
            else
4240
              $line = reset( $content );
4241
          }
4242
        case 'COMMENT':
4243
        case 'CONTACT':
4244
        case 'DESCRIPTION':
4245
        case 'LOCATION':
4246
        case 'SUMMARY':
4247
          if( empty( $line ))
4248
            $propAttr = null;
4249
          $this->setProperty( $propname, iCalUtilityFunctions::_strunrep( $line ), $propAttr );
4250
          break;
4251
        case 'REQUEST-STATUS':
4252
          $values    = explode( ';', $line, 3 );
4253
          $values[1] = ( !isset( $values[1] )) ? null : iCalUtilityFunctions::_strunrep( $values[1] );
4254
          $values[2] = ( !isset( $values[2] )) ? null : iCalUtilityFunctions::_strunrep( $values[2] );
4255
          $this->setProperty( $propname
4256
                            , $values[0]  // statcode
4257
                            , $values[1]  // statdesc
4258
                            , $values[2]  // extdata
4259
                            , $propAttr );
4260
          break;
4261
        case 'FREEBUSY':
4262
          $fbtype = ( isset( $propAttr['FBTYPE'] )) ? $propAttr['FBTYPE'] : ''; // force setting default, if missing
4263
          unset( $propAttr['FBTYPE'] );
4264
          $values = explode( ',', $line );
4265
          foreach( $values as $vix => $value ) {
4266
            $value2 = explode( '/', $value );
4267
            if( 1 < count( $value2 ))
4268
              $values[$vix] = $value2;
4269
          }
4270
          $this->setProperty( $propname, $fbtype, $values, $propAttr );
4271
          break;
4272
        case 'GEO':
4273
          $value = explode( ';', $line, 2 );
4274
          if( 2 > count( $value ))
4275
            $value[1] = null;
4276
          $this->setProperty( $propname, $value[0], $value[1], $propAttr );
4277
          break;
4278
        case 'EXDATE':
4279
          $values = ( !empty( $line )) ? explode( ',', $line ) : null;
4280
          $this->setProperty( $propname, $values, $propAttr );
4281
          break;
4282
        case 'RDATE':
4283
          if( empty( $line )) {
4284
            $this->setProperty( $propname, $line, $propAttr );
4285
            break;
4286
          }
4287
          $values = explode( ',', $line );
4288
          foreach( $values as $vix => $value ) {
4289
            $value2 = explode( '/', $value );
4290
            if( 1 < count( $value2 ))
4291
              $values[$vix] = $value2;
4292
          }
4293
          $this->setProperty( $propname, $values, $propAttr );
4294
          break;
4295
        case 'EXRULE':
4296
        case 'RRULE':
4297
          $values = explode( ';', $line );
4298
          $recur = array();
4299
          foreach( $values as $value2 ) {
4300
            if( empty( $value2 ))
4301
              continue; // ;-char in ending position ???
4302
            $value3 = explode( '=', $value2, 2 );
4303
            $rulelabel = strtoupper( $value3[0] );
4304
            switch( $rulelabel ) {
4305
              case 'BYDAY': {
4306
                $value4 = explode( ',', $value3[1] );
4307
                if( 1 < count( $value4 )) {
4308
                  foreach( $value4 as $v5ix => $value5 ) {
4309
                    $value6 = array();
4310
                    $dayno = $dayname = null;
4311
                    $value5 = trim( (string) $value5 );
4312
                    if(( ctype_alpha( substr( $value5, -1 ))) &&
4313
                       ( ctype_alpha( substr( $value5, -2, 1 )))) {
4314
                      $dayname = substr( $value5, -2, 2 );
4315
                      if( 2 < strlen( $value5 ))
4316
                        $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
4317
                    }
4318
                    if( $dayno )
4319
                      $value6[] = $dayno;
4320
                    if( $dayname )
4321
                      $value6['DAY'] = $dayname;
4322
                    $value4[$v5ix] = $value6;
4323
                  }
4324
                }
4325
                else {
4326
                  $value4 = array();
4327
                  $dayno  = $dayname = null;
4328
                  $value5 = trim( (string) $value3[1] );
4329
                  if(( ctype_alpha( substr( $value5, -1 ))) &&
4330
                     ( ctype_alpha( substr( $value5, -2, 1 )))) {
4331
                      $dayname = substr( $value5, -2, 2 );
4332
                    if( 2 < strlen( $value5 ))
4333
                      $dayno = substr( $value5, 0, ( strlen( $value5 ) - 2 ));
4334
                  }
4335
                  if( $dayno )
4336
                    $value4[] = $dayno;
4337
                  if( $dayname )
4338
                    $value4['DAY'] = $dayname;
4339
                }
4340
                $recur[$rulelabel] = $value4;
4341
                break;
4342
              }
4343
              default: {
4344
                $value4 = explode( ',', $value3[1] );
4345
                if( 1 < count( $value4 ))
4346
                  $value3[1] = $value4;
4347
                $recur[$rulelabel] = $value3[1];
4348
                break;
4349
              }
4350
            } // end - switch $rulelabel
4351
          } // end - foreach( $values.. .
4352
          $this->setProperty( $propname, $recur, $propAttr );
4353
          break;
4354
        case 'X-':
4355
          $propname = ( isset( $propname2 )) ? $propname2 : $propname;
4356
          unset( $propname2 );
4357
        case 'ACTION':
4358
        case 'CLASSIFICATION':
4359
        case 'STATUS':
4360
        case 'TRANSP':
4361
        case 'UID':
4362
        case 'TZID':
4363
        case 'RELATED-TO':
4364
        case 'TZNAME':
4365
          $line = iCalUtilityFunctions::_strunrep( $line );
4366
        default:
4367
          $this->setProperty( $propname, $line, $propAttr );
4368
          break;
4369
      } // end  switch( $propname.. .
4370
    } // end - foreach( $proprows.. .
4371
    unset( $unparsedtext, $this->unparsed, $proprows );
4372
    if( isset( $this->components ) && is_array( $this->components ) && ( 0 < count( $this->components ))) {
4373
      $ckeys = array_keys( $this->components );
4374
      foreach( $ckeys as $ckey ) {
4375
        if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) {
4376
          $this->components[$ckey]->parse();
4377
        }
4378
      }
4379
    }
4380
    return TRUE;
4381
  }
4382
/*********************************************************************************/
4383
/*********************************************************************************/
4384
/**
4385
 * return a copy of this component
4386
 *
4387
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4388
 * @since 2.15.4 - 2012-10-18
4389
 * @return object
4390
 */
4391
  function copy() {
4392
    return unserialize( serialize( $this ));
4393
 }
4394
/*********************************************************************************/
4395
/*********************************************************************************/
4396
/**
4397
 * delete calendar subcomponent from component container
4398
 *
4399
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4400
 * @since 2.8.8 - 2011-03-15
4401
 * @param mixed  $arg1 ordno / component type / component uid
4402
 * @param mixed  $arg2 ordno if arg1 = component type
4403
 * @uses calendarComponent::$components
4404
 * @uses calendarComponent::$objName
4405
 * @uses calendarComponent::getProperty()
4406
 * @return void
4407
 */
4408
  function deleteComponent( $arg1, $arg2=FALSE  ) {
4409
    if( !isset( $this->components )) return FALSE;
4410
    $argType = $index = null;
4411
    if ( ctype_digit( (string) $arg1 )) {
4412
      $argType = 'INDEX';
4413
      $index   = (int) $arg1 - 1;
4414
    }
4415
    elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
4416
      $argType = strtolower( $arg1 );
4417
      $index   = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0;
4418
    }
4419
    $cix2dC = 0;
4420
    foreach ( $this->components as $cix => $component) {
4421
      if( empty( $component )) continue;
4422
      if(( 'INDEX' == $argType ) && ( $index == $cix )) {
4423
        unset( $this->components[$cix] );
4424
        return TRUE;
4425
      }
4426
      elseif( $argType == $component->objName ) {
4427
        if( $index == $cix2dC ) {
4428
          unset( $this->components[$cix] );
4429
          return TRUE;
4430
        }
4431
        $cix2dC++;
4432
      }
4433
      elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) {
4434
        unset( $this->components[$cix] );
4435
        return TRUE;
4436
      }
4437
    }
4438
    return FALSE;
4439
  }
4440
/**
4441
 * get calendar component subcomponent from component container
4442
 *
4443
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4444
 * @since 2.8.8 - 2011-03-15
4445
 * @param mixed $arg1  ordno/component type/ component uid
4446
 * @param mixed $arg2  ordno if arg1 = component type
4447
 * @uses calendarComponent::$components
4448
 * @uses calendarComponent::$compix
4449
 * @uses calendarComponent::$objName
4450
 * @uses calendarComponent::copy()
4451
 * @uses calendarComponent::getProperty()
4452
 * @return object
4453
 */
4454
  function getComponent ( $arg1=FALSE, $arg2=FALSE ) {
4455
    if( !isset( $this->components )) return FALSE;
4456
    $index = $argType = null;
4457
    if ( !$arg1 ) {
4458
      $argType = 'INDEX';
4459
      $index   = $this->compix['INDEX'] =
4460
        ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1;
4461
    }
4462
    elseif ( ctype_digit( (string) $arg1 )) {
4463
      $argType = 'INDEX';
4464
      $index   = (int) $arg1;
4465
      unset( $this->compix );
4466
    }
4467
    elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) {
4468
      unset( $this->compix['INDEX'] );
4469
      $argType = strtolower( $arg1 );
4470
      if( !$arg2 )
4471
        $index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1;
4472
      else
4473
        $index = (int) $arg2;
4474
    }
4475
    $index  -= 1;
4476
    $ckeys = array_keys( $this->components );
4477
    if( !empty( $index) && ( $index > end( $ckeys )))
4478
      return FALSE;
4479
    $cix2gC = 0;
4480
    foreach( $this->components as $cix => $component ) {
4481
      if( empty( $component )) continue;
4482
      if(( 'INDEX' == $argType ) && ( $index == $cix ))
4483
        return $component->copy();
4484
      elseif( $argType == $component->objName ) {
4485
         if( $index == $cix2gC )
4486
           return $component->copy();
4487
         $cix2gC++;
4488
      }
4489
      elseif( !$argType && ( $arg1 == $component->getProperty( 'uid' )))
4490
        return $component->copy();
4491
    }
4492
            /* not found.. . */
4493
    unset( $this->compix );
4494
    return false;
4495
  }
4496
/**
4497
 * add calendar component as subcomponent to container for subcomponents
4498
 *
4499
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4500
 * @since 1.x.x - 2007-04-24
4501
 * @param object $component calendar component
4502
 * @uses calendarComponent::setComponent( $component )
4503
 * @return void
4504
 */
4505
  function addSubComponent ( $component ) {
4506
    $this->setComponent( $component );
4507
  }
4508
/**
4509
 * create new calendar component subcomponent, already included within component
4510
 *
4511
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4512
 * @since 2.6.33 - 2011-01-03
4513
 * @param string $compType  subcomponent type
4514
 * @uses calendarComponent::getConfig()
4515
 * @uses calendarComponent::$components
4516
 * @uses calendarComponent::calendarComponent()
4517
 * @return object (reference)
4518
 */
4519
  function & newComponent( $compType ) {
4520
    $config = $this->getConfig();
4521
    $keys   = array_keys( $this->components );
4522
    $ix     = end( $keys) + 1;
4523
    switch( strtoupper( $compType )) {
4524
      case 'ALARM':
4525
      case 'VALARM':
4526
        $this->components[$ix] = new valarm( $config );
4527
        break;
4528
      case 'STANDARD':
4529
        array_unshift( $this->components, new vtimezone( 'STANDARD', $config ));
4530
        $ix = 0;
4531
        break;
4532
      case 'DAYLIGHT':
4533
        $this->components[$ix] = new vtimezone( 'DAYLIGHT', $config );
4534
        break;
4535
      default:
4536
        return FALSE;
4537
    }
4538
    return $this->components[$ix];
4539
  }
4540
/**
4541
 * add calendar component as subcomponent to container for subcomponents
4542
 *
4543
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4544
 * @since 2.21.11 - 2015-03-21
4545
 * @param object  $component calendar component
4546
 * @param mixed   $arg1      ordno/component type/ component uid
4547
 * @param mixed   $arg2      ordno if arg1 = component type
4548
 * @uses calendarComponent::$components
4549
 * @uses calendarComponent::setConfig()
4550
 * @uses calendarComponent::getConfig()
4551
 * @uses calendarComponent::$objName
4552
 * @uses iCalUtilityFunctions::$miscComps
4553
 * @uses calendarComponent::getProperty()
4554
 * @uses calendarComponent::copy()
4555
 * @uses iCalUtilityFunctions::$mComps
4556
 * @return bool
4557
 */
4558
  function setComponent( $component, $arg1=FALSE, $arg2=FALSE  ) {
4559
    if( !isset( $this->components )) return FALSE;
4560
    $component->setConfig( $this->getConfig(), FALSE, TRUE );
4561
    if( ! in_array( $component->objName, iCalUtilityFunctions::$miscComps )) {
4562
            /* make sure dtstamp and uid is set */
4563
      $dummy = $component->getProperty( 'dtstamp' );
4564
      $dummy = $component->getProperty( 'uid' );
4565
    }
4566
    if( !$arg1 ) { // plain insert, last in chain
4567
      $this->components[] = $component->copy();
4568
      return TRUE;
4569
    }
4570
    $argType = $index = null;
4571
    if ( ctype_digit( (string) $arg1 )) { // index insert/replace
4572
      $argType = 'INDEX';
4573
      $index   = (int) $arg1 - 1;
4574
    }
4575
    elseif( in_array( strtolower( $arg1 ), iCalUtilityFunctions::$mComps )) {
4576
      $argType = strtolower( $arg1 );
4577
      $index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0;
4578
    }
4579
    // else if arg1 is set, arg1 must be an UID
4580
    $cix2sC = 0;
4581
    foreach ( $this->components as $cix => $component2 ) {
4582
      if( empty( $component2 )) continue;
4583
      if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace
4584
        $this->components[$cix] = $component->copy();
4585
        return TRUE;
4586
      }
4587
      elseif( $argType == $component2->objName ) { // component Type index insert/replace
4588
        if( $index == $cix2sC ) {
4589
          $this->components[$cix] = $component->copy();
4590
          return TRUE;
4591
        }
4592
        $cix2sC++;
4593
      }
4594
      elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace
4595
        $this->components[$cix] = $component->copy();
4596
        return TRUE;
4597
      }
4598
    }
4599
            /* arg1=index and not found.. . insert at index .. .*/
4600
    if( 'INDEX' == $argType ) {
4601
      $this->components[$index] = $component->copy();
4602
      ksort( $this->components, SORT_NUMERIC );
4603
    }
4604
    else    /* not found.. . insert last in chain anyway .. .*/
4605
    $this->components[] = $component->copy();
4606
    return TRUE;
4607
  }
4608
/**
4609
 * creates formatted output for subcomponents
4610
 *
4611
 * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
4612
 * @since 2.21.11 - 2015-03-10
4613
 * @param array $xcaldecl
4614
 * @uses calendarComponent::$objName
4615
 * @uses calendarComponent::$components
4616
 * @uses calendarComponent::getProperty()
4617
 * @uses iCalUtilityFunctions::$fmt
4618
 * @uses calendarComponent::copy()
4619
 * @uses calendarComponent::setConfig()
4620
 * @uses calendarComponent::getConfig()
4621
 * @uses calendarComponent::createComponent()
4622
 * @uses calendarComponent::$xcaldecl()
4623
 * @return string
4624
 */
4625
  function createSubComponent() {
4626
    $output = null;
4627
    if( 'vtimezone' == $this->objName ) { // sort subComponents, first standard, then daylight, in dtstart order
4628
      $stdarr = $dlarr = array();
4629
      foreach( $this->components as $component ) {
4630
        if( empty( $component ))
4631
          continue;
4632
        $dt  = $component->getProperty( 'dtstart' );
4633
        $key = (int) sprintf( iCalUtilityFunctions::$fmt['dateKey'], (int) $dt['year'], (int) $dt['month'], (int) $dt['day'], (int) $dt['hour'], (int) $dt['min'], (int) $dt['sec'] );
4634
        if( 'standard' == $component->objName ) {
4635
          while( isset( $stdarr[$key] ))
4636
            $key += 1;
4637
          $stdarr[$key] = $component->copy();
4638
        }
4639
        elseif( 'daylight' == $component->objName ) {
4640
          while( isset( $dlarr[$key] ))
4641
            $key += 1;
4642
          $dlarr[$key] = $component->copy();
4643
        }
4644
      } // end foreach( $this->components as $component )
4645
      $this->components = array();
4646
      ksort( $stdarr, SORT_NUMERIC );
4647
      foreach( $stdarr as $std )
4648
        $this->components[] = $std->copy();
4649
      unset( $stdarr );
4650
      ksort( $dlarr,  SORT_NUMERIC );
4651
      foreach( $dlarr as $dl )
4652
        $this->components[] = $dl->copy();
4653
      unset( $dlarr );
4654
    } // end if( 'vtimezone' == $this->objName )
4655
    foreach( $this->components as $component ) {
4656
      $component->setConfig( $this->getConfig(), FALSE, TRUE );
4657
      $output .= $component->createComponent( $this->xcaldecl );
4658
    }
4659
    return $output;
4660
  }
4661
}