root / drupal7 / sites / all / libraries / iCalcreator-2.22.1 / lib / vcalendar.class.php @ 0f8e34f8
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 |
* vcalendar class
|
31 |
*
|
32 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
33 |
* @since 2.21.11 - 2015-03-31
|
34 |
*/
|
35 |
class vcalendar extends iCalBase { |
36 |
/**
|
37 |
* @var array $calscale calendar property variable
|
38 |
* @var array $method calendar property variable
|
39 |
* @var array $prodid calendar property variable
|
40 |
* @var array $version calendar property variable
|
41 |
* @access private
|
42 |
*/
|
43 |
private $calscale; |
44 |
private $method; |
45 |
private $prodid; |
46 |
private $version; |
47 |
/**
|
48 |
* @var array $directory calendar config variable
|
49 |
* @var array $filename calendar config variable
|
50 |
* @var array $url calendar config variable
|
51 |
* @access private
|
52 |
*/
|
53 |
private $directory; |
54 |
private $filename; |
55 |
private $url; |
56 |
/**
|
57 |
* redirect headers
|
58 |
*
|
59 |
* @var array $headers
|
60 |
* @access private
|
61 |
* @static
|
62 |
*/
|
63 |
private static $headers = array( 'Content-Encoding: gzip', |
64 |
'Vary: *',
|
65 |
'Content-Length: %s',
|
66 |
'Content-Type: application/calendar+xml; charset=utf-8',
|
67 |
'Content-Type: text/calendar; charset=utf-8',
|
68 |
'Content-Disposition: attachment; filename="%s"',
|
69 |
'Content-Disposition: inline; filename="%s"',
|
70 |
'Cache-Control: max-age=10',
|
71 |
); |
72 |
/**
|
73 |
* constructor for calendar object
|
74 |
*
|
75 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
76 |
* @since 2.21.15 - 2015-04-04
|
77 |
* @param array $config
|
78 |
* @uses vcalendar::_makeVersion()
|
79 |
* @uses vcalendar::$calscale
|
80 |
* @uses vcalendar::$method
|
81 |
* @uses vcalendar::_makeUnique_id()
|
82 |
* @uses vcalendar::$prodid
|
83 |
* @uses vcalendar::$xprop
|
84 |
* @uses vcalendar::$language
|
85 |
* @uses vcalendar::$directory
|
86 |
* @uses vcalendar::$filename
|
87 |
* @uses vcalendar::$url
|
88 |
* @uses vcalendar::$dtzid
|
89 |
* @uses vcalendar::setConfig()
|
90 |
* @uses vcalendar::$xcaldecl
|
91 |
* @uses vcalendar::$components
|
92 |
*/
|
93 |
function vcalendar ( $config = array()) { |
94 |
$this->_makeVersion();
|
95 |
$this->calscale = null; |
96 |
$this->method = null; |
97 |
$this->_makeUnique_id();
|
98 |
$this->prodid = null; |
99 |
$this->xprop = array(); |
100 |
$this->language = null; |
101 |
$this->directory = '.'; |
102 |
$this->filename = null; |
103 |
$this->url = null; |
104 |
$this->dtzid = null; |
105 |
/**
|
106 |
* language = <Text identifying a language, as defined in [RFC 1766]>
|
107 |
*/
|
108 |
if( defined( 'ICAL_LANG' ) && !isset( $config['language'] )) |
109 |
$config['language'] = ICAL_LANG; |
110 |
if( !isset( $config['allowEmpty'] )) $config['allowEmpty'] = TRUE; |
111 |
if( !isset( $config['nl'] )) $config['nl'] = "\r\n"; |
112 |
if( !isset( $config['format'] )) $config['format'] = 'iCal'; |
113 |
if( !isset( $config['delimiter'] )) $config['delimiter'] = DIRECTORY_SEPARATOR; |
114 |
$this->setConfig( $config ); |
115 |
$this->xcaldecl = array(); |
116 |
$this->components = array(); |
117 |
} |
118 |
/**
|
119 |
* return iCalcreator version number
|
120 |
*
|
121 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
122 |
* @since 2.18.5 - 2013-08-29
|
123 |
* @uses ICALCREATOR_VERSION
|
124 |
* @return string
|
125 |
*/
|
126 |
public static function iCalcreatorVersion() { |
127 |
return trim( substr( ICALCREATOR_VERSION, strpos( ICALCREATOR_VERSION, ' ' ))); |
128 |
} |
129 |
/*********************************************************************************/
|
130 |
/**
|
131 |
* Property Name: CALSCALE
|
132 |
*/
|
133 |
/**
|
134 |
* creates formatted output for calendar property calscale
|
135 |
*
|
136 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
137 |
* @since 2.10.16 - 2011-10-28
|
138 |
* @uses vcalendar::$calscale
|
139 |
* @uses vcalendar::$format
|
140 |
* @uses vcalendar::$nl
|
141 |
* @return string
|
142 |
*/
|
143 |
function createCalscale() { |
144 |
if( empty( $this->calscale )) return FALSE; |
145 |
switch( $this->format ) { |
146 |
case 'xcal': |
147 |
return $this->nl.' calscale="'.$this->calscale.'"'; |
148 |
break;
|
149 |
default:
|
150 |
return 'CALSCALE:'.$this->calscale.$this->nl; |
151 |
break;
|
152 |
} |
153 |
} |
154 |
/**
|
155 |
* set calendar property calscale
|
156 |
*
|
157 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
158 |
* @since 2.4.8 - 2008-10-21
|
159 |
* @param string $value
|
160 |
* @uses vcalendar::$calscale
|
161 |
* @return void
|
162 |
*/
|
163 |
function setCalscale( $value ) { |
164 |
if( empty( $value )) return FALSE; |
165 |
$this->calscale = $value; |
166 |
} |
167 |
/*********************************************************************************/
|
168 |
/**
|
169 |
* Property Name: METHOD
|
170 |
*/
|
171 |
/**
|
172 |
* creates formatted output for calendar property method
|
173 |
*
|
174 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
175 |
* @since 2.10.16 - 2011-10-28
|
176 |
* @uses vcalendar::$method
|
177 |
* @uses vcalendar::$format
|
178 |
* @uses vcalendar::$nl
|
179 |
* @return string
|
180 |
*/
|
181 |
function createMethod() { |
182 |
if( empty( $this->method )) return FALSE; |
183 |
switch( $this->format ) { |
184 |
case 'xcal': |
185 |
return $this->nl.' method="'.$this->method.'"'; |
186 |
break;
|
187 |
default:
|
188 |
return 'METHOD:'.$this->method.$this->nl; |
189 |
break;
|
190 |
} |
191 |
} |
192 |
/**
|
193 |
* set calendar property method
|
194 |
*
|
195 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
196 |
* @since 2.4.8 - 2008-20-23
|
197 |
* @param string $value
|
198 |
* @uses vcalendar::$method
|
199 |
* @return bool
|
200 |
*/
|
201 |
function setMethod( $value ) { |
202 |
if( empty( $value )) return FALSE; |
203 |
$this->method = $value; |
204 |
return TRUE; |
205 |
} |
206 |
/*********************************************************************************/
|
207 |
/**
|
208 |
* Property Name: PRODID
|
209 |
*
|
210 |
*/
|
211 |
/**
|
212 |
* creates formatted output for calendar property prodid
|
213 |
*
|
214 |
* @copyright copyright (c) 2007-2013 Kjell-Inge Gustafsson, kigkonsult, All rights reserved
|
215 |
* @license http://kigkonsult.se/downloads/dl.php?f=LGPL
|
216 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
217 |
* @since 2.21.11 - 2015-03-31
|
218 |
* @uses vcalendar::$prodid
|
219 |
* @uses vcalendar::_makeProdid()
|
220 |
* @uses vcalendar::$format
|
221 |
* @uses vcalendar::$nl
|
222 |
* @uses vcalendar::_createElement()
|
223 |
* @return string
|
224 |
*/
|
225 |
function createProdid() { |
226 |
if( !isset( $this->prodid )) |
227 |
$this->_makeProdid();
|
228 |
switch( $this->format ) { |
229 |
case 'xcal': |
230 |
return $this->nl.' prodid="'.$this->prodid.'"'; |
231 |
break;
|
232 |
default:
|
233 |
return $this->_createElement( 'PRODID', '', $this->prodid ); |
234 |
break;
|
235 |
} |
236 |
} |
237 |
/**
|
238 |
* make default value for calendar prodid, do NOT alter or remove this method or invoke of this method
|
239 |
*
|
240 |
* @copyright copyright (c) 2007-2013 Kjell-Inge Gustafsson, kigkonsult, All rights reserved
|
241 |
* @license http://kigkonsult.se/downloads/dl.php?f=LGPL
|
242 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
243 |
* @since 2.6.8 - 2009-12-30
|
244 |
* @uses vcalendar::$prodid
|
245 |
* @uses vcalendar::$unique_id
|
246 |
* @uses ICALCREATOR_VERSION
|
247 |
* @uses vcalendar::$language
|
248 |
* @return void
|
249 |
*/
|
250 |
function _makeProdid() { |
251 |
$this->prodid = '-//'.$this->unique_id.'//NONSGML kigkonsult.se '.ICALCREATOR_VERSION.'//'.strtoupper( $this->language ); |
252 |
} |
253 |
/**
|
254 |
* Conformance: The property MUST be specified once in an iCalendar object.
|
255 |
* Description: The vendor of the implementation SHOULD assure that this
|
256 |
* is a globally unique identifier; using some technique such as an FPI
|
257 |
* value, as defined in [ISO 9070].
|
258 |
*/
|
259 |
/**
|
260 |
* make default unique_id for calendar prodid
|
261 |
*
|
262 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
263 |
* @since 0.3.0 - 2006-08-10
|
264 |
* @uses vcalendar::$unique_id
|
265 |
* @return void
|
266 |
*/
|
267 |
function _makeUnique_id() { |
268 |
$this->unique_id = ( isset( $_SERVER['SERVER_NAME'] )) ? gethostbyname( $_SERVER['SERVER_NAME'] ) : 'localhost'; |
269 |
} |
270 |
/*********************************************************************************/
|
271 |
/**
|
272 |
* Property Name: VERSION
|
273 |
*
|
274 |
* Description: A value of "2.0" corresponds to this memo.
|
275 |
*/
|
276 |
/**
|
277 |
* creates formatted output for calendar property version
|
278 |
|
279 |
*
|
280 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
281 |
* @since 2.10.16 - 2011-10-28
|
282 |
* @uses vcalendar::$version
|
283 |
* @uses vcalendar::$format
|
284 |
* @uses vcalendar::$nl
|
285 |
* @return string
|
286 |
*/
|
287 |
function createVersion() { |
288 |
if( empty( $this->version )) |
289 |
$this->_makeVersion();
|
290 |
switch( $this->format ) { |
291 |
case 'xcal': |
292 |
return $this->nl.' version="'.$this->version.'"'; |
293 |
break;
|
294 |
default:
|
295 |
return 'VERSION:'.$this->version.$this->nl; |
296 |
break;
|
297 |
} |
298 |
} |
299 |
/**
|
300 |
* set default calendar version
|
301 |
*
|
302 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
303 |
* @since 0.3.0 - 2006-08-10
|
304 |
* @uses vcalendar::$version
|
305 |
* @return void
|
306 |
*/
|
307 |
function _makeVersion() { |
308 |
$this->version = '2.0'; |
309 |
} |
310 |
/**
|
311 |
* set calendar version
|
312 |
*
|
313 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
314 |
* @since 2.4.8 - 2008-10-23
|
315 |
* @param string $value
|
316 |
* @uses vcalendar::$version
|
317 |
* @return void
|
318 |
*/
|
319 |
function setVersion( $value ) { |
320 |
if( empty( $value )) return FALSE; |
321 |
$this->version = $value; |
322 |
return TRUE; |
323 |
} |
324 |
/*********************************************************************************/
|
325 |
/*********************************************************************************/
|
326 |
/**
|
327 |
* delete calendar property value
|
328 |
*
|
329 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
330 |
* @since 2.8.8 - 2011-03-15
|
331 |
* @param mixed $propName bool FALSE => X-property
|
332 |
* @param int $propix specific property in case of multiply occurences
|
333 |
* @uses vcalendar::$propdelix
|
334 |
* @uses vcalendar::$calscale
|
335 |
* @uses vcalendar::$method
|
336 |
* @uses vcalendar::$xprop
|
337 |
* @return bool, if successfull delete
|
338 |
*/
|
339 |
function deleteProperty( $propName=FALSE, $propix=FALSE ) { |
340 |
$propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP'; |
341 |
if( !$propix ) |
342 |
$propix = ( isset( $this->propdelix[$propName] ) && ( 'X-PROP' != $propName )) ? $this->propdelix[$propName] + 2 : 1; |
343 |
$this->propdelix[$propName] = --$propix; |
344 |
$return = FALSE; |
345 |
switch( $propName ) { |
346 |
case 'CALSCALE': |
347 |
if( isset( $this->calscale )) { |
348 |
$this->calscale = null; |
349 |
$return = TRUE; |
350 |
} |
351 |
break;
|
352 |
case 'METHOD': |
353 |
if( isset( $this->method )) { |
354 |
$this->method = null; |
355 |
$return = TRUE; |
356 |
} |
357 |
break;
|
358 |
default:
|
359 |
$reduced = array(); |
360 |
if( $propName != 'X-PROP' ) { |
361 |
if( !isset( $this->xprop[$propName] )) { unset( $this->propdelix[$propName] ); return FALSE; } |
362 |
foreach( $this->xprop as $k => $a ) { |
363 |
if(( $k != $propName ) && !empty( $a )) |
364 |
$reduced[$k] = $a; |
365 |
} |
366 |
} |
367 |
else {
|
368 |
if( count( $this->xprop ) <= $propix ) return FALSE; |
369 |
$xpropno = 0; |
370 |
foreach( $this->xprop as $xpropkey => $xpropvalue ) { |
371 |
if( $propix != $xpropno ) |
372 |
$reduced[$xpropkey] = $xpropvalue; |
373 |
$xpropno++;
|
374 |
} |
375 |
} |
376 |
$this->xprop = $reduced; |
377 |
if( empty( $this->xprop )) { |
378 |
unset( $this->propdelix[$propName] ); |
379 |
return FALSE; |
380 |
} |
381 |
return TRUE; |
382 |
} |
383 |
return $return; |
384 |
} |
385 |
/**
|
386 |
* get calendar property value/params
|
387 |
*
|
388 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
389 |
* @since 2.21.09 - 2015-03-29
|
390 |
* @param string $propName
|
391 |
* @param int $propix specific property in case of multiply occurences
|
392 |
* @param bool $inclParam
|
393 |
* @uses vcalendar::$propix
|
394 |
* @uses vcalendar::$components
|
395 |
* @uses calendarComponent::$objName
|
396 |
* @uses iCalUtilityFunctions::$vComps
|
397 |
* @uses iCalUtilityFunctions::$mProps1
|
398 |
* @uses calendarComponent::_getProperties()
|
399 |
* @uses calendarComponent::getProperty()
|
400 |
* @uses iCalUtilityFunctions::_geo2str2()
|
401 |
* @uses iCalUtilityFunctions::$geoLatFmt
|
402 |
* @uses iCalUtilityFunctions::$geoLongFmt
|
403 |
* @uses iCalUtilityFunctions::$fmt
|
404 |
* @uses vcalendar::$calscale
|
405 |
* @uses vcalendar::$method
|
406 |
* @uses vcalendar::$prodid
|
407 |
* @uses vcalendar::_makeProdid()
|
408 |
* @uses vcalendar::$version
|
409 |
* @uses vcalendar::$xprop
|
410 |
* @return mixed
|
411 |
*/
|
412 |
function getProperty( $propName=FALSE, $propix=FALSE, $inclParam=FALSE ) { |
413 |
$propName = ( $propName ) ? strtoupper( $propName ) : 'X-PROP'; |
414 |
if( 'X-PROP' == $propName ) { |
415 |
if( empty( $propix )) |
416 |
$propix = ( isset( $this->propix[$propName] )) ? $this->propix[$propName] + 2 : 1; |
417 |
$this->propix[$propName] = --$propix; |
418 |
} |
419 |
switch( $propName ) { |
420 |
case 'ATTENDEE': |
421 |
case 'CATEGORIES': |
422 |
case 'CONTACT': |
423 |
case 'DTSTART': |
424 |
case 'GEOLOCATION': |
425 |
case 'LOCATION': |
426 |
case 'ORGANIZER': |
427 |
case 'PRIORITY': |
428 |
case 'RESOURCES': |
429 |
case 'STATUS': |
430 |
case 'SUMMARY': |
431 |
case 'RECURRENCE-ID-UID': |
432 |
case 'RELATED-TO': |
433 |
case 'R-UID': |
434 |
case 'UID': |
435 |
case 'URL': |
436 |
$output = array(); |
437 |
foreach ( $this->components as $cix => $component) { |
438 |
if( !in_array( $component->objName, iCalUtilityFunctions::$vComps )) |
439 |
continue;
|
440 |
if( in_array( $propName, iCalUtilityFunctions::$mProps1 )) { |
441 |
$component->_getProperties( $propName, $output ); |
442 |
continue;
|
443 |
} |
444 |
elseif(( 3 < strlen( $propName )) && ( 'UID' == substr( $propName, -3 ))) { |
445 |
if( FALSE !== ( $content = $component->getProperty( 'RECURRENCE-ID' ))) |
446 |
$content = $component->getProperty( 'UID' ); |
447 |
} |
448 |
elseif( 'GEOLOCATION' == $propName ) { |
449 |
$content = ( FALSE === ( $loc = $component->getProperty( 'LOCATION' ))) ? '' : $loc.' '; |
450 |
if( FALSE === ( $geo = $component->getProperty( 'GEO' ))) |
451 |
continue;
|
452 |
$content .= iCalUtilityFunctions::_geo2str2( $geo['latitude'], iCalUtilityFunctions::$geoLatFmt ). |
453 |
iCalUtilityFunctions::_geo2str2( $geo['longitude'], iCalUtilityFunctions::$geoLongFmt ).'/'; |
454 |
} |
455 |
elseif( FALSE === ( $content = $component->getProperty( $propName ))) |
456 |
continue;
|
457 |
if(( FALSE === $content ) || empty( $content )) |
458 |
continue;
|
459 |
elseif( is_array( $content )) { |
460 |
if( isset( $content['year'] )) { |
461 |
$key = sprintf( iCalUtilityFunctions::$fmt['Ymd'], (int) $content['year'], (int) $content['month'], (int) $content['day'] ); |
462 |
if( !isset( $output[$key] )) |
463 |
$output[$key] = 1; |
464 |
else
|
465 |
$output[$key] += 1; |
466 |
} |
467 |
else {
|
468 |
foreach( $content as $partValue => $partCount ) { |
469 |
if( !isset( $output[$partValue] )) |
470 |
$output[$partValue] = $partCount; |
471 |
else
|
472 |
$output[$partValue] += $partCount; |
473 |
} |
474 |
} |
475 |
} // end elseif( is_array( $content )) {
|
476 |
elseif( !isset( $output[$content] )) |
477 |
$output[$content] = 1; |
478 |
else
|
479 |
$output[$content] += 1; |
480 |
} // end foreach ( $this->components as $cix => $component)
|
481 |
if( !empty( $output )) |
482 |
ksort( $output ); |
483 |
return $output; |
484 |
break;
|
485 |
case 'CALSCALE': |
486 |
return ( !empty( $this->calscale )) ? $this->calscale : FALSE; |
487 |
break;
|
488 |
case 'METHOD': |
489 |
return ( !empty( $this->method )) ? $this->method : FALSE; |
490 |
break;
|
491 |
case 'PRODID': |
492 |
if( empty( $this->prodid )) |
493 |
$this->_makeProdid();
|
494 |
return $this->prodid; |
495 |
break;
|
496 |
case 'VERSION': |
497 |
return ( !empty( $this->version )) ? $this->version : FALSE; |
498 |
break;
|
499 |
default:
|
500 |
if( $propName != 'X-PROP' ) { |
501 |
if( !isset( $this->xprop[$propName] )) return FALSE; |
502 |
return ( $inclParam ) ? array( $propName, $this->xprop[$propName] ) |
503 |
: array( $propName, $this->xprop[$propName]['value'] ); |
504 |
} |
505 |
else {
|
506 |
if( empty( $this->xprop )) return FALSE; |
507 |
$xpropno = 0; |
508 |
foreach( $this->xprop as $xpropkey => $xpropvalue ) { |
509 |
if( $propix == $xpropno ) |
510 |
return ( $inclParam ) ? array( $xpropkey, $this->xprop[$xpropkey] ) |
511 |
: array( $xpropkey, $this->xprop[$xpropkey]['value'] ); |
512 |
else
|
513 |
$xpropno++;
|
514 |
} |
515 |
unset( $this->propix[$propName] ); |
516 |
return FALSE; // not found ?? |
517 |
} |
518 |
} |
519 |
return FALSE; |
520 |
} |
521 |
/**
|
522 |
* general vcalendar property setting
|
523 |
*
|
524 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
525 |
* @since 2.2.13 - 2007-11-04
|
526 |
* @param mixed $args variable number of function arguments,
|
527 |
* first argument is ALWAYS component name,
|
528 |
* second ALWAYS component value!
|
529 |
* @uses vcalendar::setCalscale()
|
530 |
* @uses vcalendar::setMethod()
|
531 |
* @uses vcalendar::setVersion()
|
532 |
* @uses vcalendar::setXprop()
|
533 |
* @return bool
|
534 |
*/
|
535 |
function setProperty () { |
536 |
$numargs = func_num_args(); |
537 |
if( 1 > $numargs ) |
538 |
return FALSE; |
539 |
$arglist = func_get_args(); |
540 |
$arglist[0] = strtoupper( $arglist[0] ); |
541 |
switch( $arglist[0] ) { |
542 |
case 'CALSCALE': |
543 |
return $this->setCalscale( $arglist[1] ); |
544 |
case 'METHOD': |
545 |
return $this->setMethod( $arglist[1] ); |
546 |
case 'VERSION': |
547 |
return $this->setVersion( $arglist[1] ); |
548 |
default:
|
549 |
if( !isset( $arglist[1] )) $arglist[1] = null; |
550 |
if( !isset( $arglist[2] )) $arglist[2] = null; |
551 |
return $this->setXprop( $arglist[0], $arglist[1], $arglist[2] ); |
552 |
} |
553 |
return FALSE; |
554 |
} |
555 |
/*********************************************************************************/
|
556 |
/**
|
557 |
* get vcalendar config values or * calendar components
|
558 |
*
|
559 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
560 |
* @since 2.11.7 - 2012-01-12
|
561 |
* @param mixed $config
|
562 |
* @uses vcalendar::getConfig()
|
563 |
* @uses vcalendar::$allowEmpty
|
564 |
* @uses vcalendar::$components
|
565 |
* @uses calendarComponent::_getProperties()
|
566 |
* @uses calendarComponent::$objName
|
567 |
* @uses calendarComponent::getProperty()
|
568 |
* @uses calendarComponent::_getConfig()
|
569 |
* @uses vcalendar::$url
|
570 |
* @uses vcalendar::$delimiter
|
571 |
* @uses vcalendar::$directory
|
572 |
* @uses vcalendar::$filename
|
573 |
* @uses vcalendar::$format
|
574 |
* @uses vcalendar::$language
|
575 |
* @uses vcalendar::$nl
|
576 |
* @uses vcalendar::$dtzid
|
577 |
* @uses vcalendar::$unique_id
|
578 |
* @return value
|
579 |
*/
|
580 |
function getConfig( $config = FALSE ) { |
581 |
if( !$config ) { |
582 |
$return = array(); |
583 |
$return['ALLOWEMPTY'] = $this->getConfig( 'ALLOWEMPTY' ); |
584 |
$return['DELIMITER'] = $this->getConfig( 'DELIMITER' ); |
585 |
$return['DIRECTORY'] = $this->getConfig( 'DIRECTORY' ); |
586 |
$return['FILENAME'] = $this->getConfig( 'FILENAME' ); |
587 |
$return['DIRFILE'] = $this->getConfig( 'DIRFILE' ); |
588 |
$return['FILESIZE'] = $this->getConfig( 'FILESIZE' ); |
589 |
$return['FORMAT'] = $this->getConfig( 'FORMAT' ); |
590 |
if( FALSE !== ( $lang = $this->getConfig( 'LANGUAGE' ))) |
591 |
$return['LANGUAGE'] = $lang; |
592 |
$return['NEWLINECHAR'] = $this->getConfig( 'NEWLINECHAR' ); |
593 |
$return['UNIQUE_ID'] = $this->getConfig( 'UNIQUE_ID' ); |
594 |
if( FALSE !== ( $url = $this->getConfig( 'URL' ))) |
595 |
$return['URL'] = $url; |
596 |
$return['TZID'] = $this->getConfig( 'TZID' ); |
597 |
return $return; |
598 |
} |
599 |
switch( strtoupper( $config )) { |
600 |
case 'ALLOWEMPTY': |
601 |
return $this->allowEmpty; |
602 |
break;
|
603 |
case 'COMPSINFO': |
604 |
unset( $this->compix ); |
605 |
$info = array(); |
606 |
foreach( $this->components as $cix => $component ) { |
607 |
if( empty( $component )) continue; |
608 |
$info[$cix]['ordno'] = $cix + 1; |
609 |
$info[$cix]['type'] = $component->objName; |
610 |
$info[$cix]['uid'] = $component->getProperty( 'uid' ); |
611 |
$info[$cix]['props'] = $component->getConfig( 'propinfo' ); |
612 |
$info[$cix]['sub'] = $component->getConfig( 'compsinfo' ); |
613 |
} |
614 |
return $info; |
615 |
break;
|
616 |
case 'DELIMITER': |
617 |
return $this->delimiter; |
618 |
break;
|
619 |
case 'DIRECTORY': |
620 |
if( empty( $this->directory ) && ( '0' != $this->directory )) |
621 |
$this->directory = '.'; |
622 |
return $this->directory; |
623 |
break;
|
624 |
case 'DIRFILE': |
625 |
return $this->getConfig( 'directory' ).$this->getConfig( 'delimiter' ).$this->getConfig( 'filename' ); |
626 |
break;
|
627 |
case 'FILEINFO': |
628 |
return array( $this->getConfig( 'directory' ) |
629 |
, $this->getConfig( 'filename' ) |
630 |
, $this->getConfig( 'filesize' )); |
631 |
break;
|
632 |
case 'FILENAME': |
633 |
if( empty( $this->filename ) && ( '0' != $this->filename )) { |
634 |
if( 'xcal' == $this->format ) |
635 |
$this->filename = date( 'YmdHis' ).'.xml'; // recommended xcs.. . |
636 |
else
|
637 |
$this->filename = date( 'YmdHis' ).'.ics'; |
638 |
} |
639 |
return $this->filename; |
640 |
break;
|
641 |
case 'FILESIZE': |
642 |
$size = 0; |
643 |
if( empty( $this->url )) { |
644 |
$dirfile = $this->getConfig( 'dirfile' ); |
645 |
if( !is_file( $dirfile ) || ( FALSE === ( $size = filesize( $dirfile )))) |
646 |
$size = 0; |
647 |
clearstatcache();
|
648 |
} |
649 |
return $size; |
650 |
break;
|
651 |
case 'FORMAT': |
652 |
return ( $this->format == 'xcal' ) ? 'xCal' : 'iCal'; |
653 |
break;
|
654 |
case 'LANGUAGE': |
655 |
/* get language for calendar component as defined in [RFC 1766] */
|
656 |
return $this->language; |
657 |
break;
|
658 |
case 'NL': |
659 |
case 'NEWLINECHAR': |
660 |
return $this->nl; |
661 |
break;
|
662 |
case 'TZID': |
663 |
return $this->dtzid; |
664 |
break;
|
665 |
case 'UNIQUE_ID': |
666 |
return $this->unique_id; |
667 |
break;
|
668 |
case 'URL': |
669 |
if( !empty( $this->url )) |
670 |
return $this->url; |
671 |
else
|
672 |
return FALSE; |
673 |
break;
|
674 |
} |
675 |
} |
676 |
/**
|
677 |
* general vcalendar config setting
|
678 |
*
|
679 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
680 |
* @since 2.20.2 - 2014-05-09
|
681 |
* @param mixed $config
|
682 |
* @param string $value
|
683 |
* @uses vcalendar::setConfig()
|
684 |
* @uses vcalendar::$allowEmpty
|
685 |
* @uses vcalendar::$components
|
686 |
* @uses vcalendar::$url
|
687 |
* @uses vcalendar::$delimiter
|
688 |
* @uses vcalendar::$directory
|
689 |
* @uses vcalendar::$filename
|
690 |
* @uses vcalendar::$format
|
691 |
* @uses vcalendar::$language
|
692 |
* @uses vcalendar::$nl
|
693 |
* @uses vcalendar::$dtzid
|
694 |
* @uses vcalendar::$unique_id
|
695 |
* @uses vcalendar::_makeProdid()
|
696 |
* @uses vcalendar::$components
|
697 |
* @uses calendarComponent::setConfig()
|
698 |
* @uses calendarComponent::copy()
|
699 |
* @return void
|
700 |
*/
|
701 |
function setConfig( $config, $value = FALSE) { |
702 |
if( is_array( $config )) { |
703 |
$config = array_change_key_case( $config, CASE_UPPER ); |
704 |
if( isset( $config['DELIMITER'] )) { |
705 |
if( FALSE === $this->setConfig( 'DELIMITER', $config['DELIMITER'] )) |
706 |
return FALSE; |
707 |
unset( $config['DELIMITER'] ); |
708 |
} |
709 |
if( isset( $config['DIRECTORY'] )) { |
710 |
if( FALSE === $this->setConfig( 'DIRECTORY', $config['DIRECTORY'] )) |
711 |
return FALSE; |
712 |
unset( $config['DIRECTORY'] ); |
713 |
} |
714 |
foreach( $config as $cKey => $cValue ) { |
715 |
if( FALSE === $this->setConfig( $cKey, $cValue )) |
716 |
return FALSE; |
717 |
} |
718 |
return TRUE; |
719 |
} |
720 |
else
|
721 |
$res = FALSE; |
722 |
$config = strtoupper( $config ); |
723 |
switch( $config ) { |
724 |
case 'ALLOWEMPTY': |
725 |
$this->allowEmpty = $value; |
726 |
$subcfg = array( 'ALLOWEMPTY' => $value ); |
727 |
$res = TRUE; |
728 |
break;
|
729 |
case 'DELIMITER': |
730 |
$this->delimiter = $value; |
731 |
return TRUE; |
732 |
break;
|
733 |
case 'DIRECTORY': |
734 |
if( FALSE === ( $value = realpath( rtrim( trim( $value ), $this->delimiter )))) |
735 |
return FALSE; |
736 |
else {
|
737 |
/* local directory */
|
738 |
$this->directory = $value; |
739 |
$this->url = null; |
740 |
return TRUE; |
741 |
} |
742 |
break;
|
743 |
case 'FILENAME': |
744 |
$value = trim( $value ); |
745 |
$dirfile = $this->directory.$this->delimiter.$value; |
746 |
if( file_exists( $dirfile )) { |
747 |
/* local file exists */
|
748 |
if( is_readable( $dirfile ) || is_writable( $dirfile )) { |
749 |
clearstatcache();
|
750 |
$this->filename = $value; |
751 |
return TRUE; |
752 |
} |
753 |
else
|
754 |
return FALSE; |
755 |
} |
756 |
elseif( is_readable( $this->directory ) || is_writable( $this->directory )) { |
757 |
/* read- or writable directory */
|
758 |
clearstatcache();
|
759 |
$this->filename = $value; |
760 |
return TRUE; |
761 |
} |
762 |
else
|
763 |
return FALSE; |
764 |
break;
|
765 |
case 'FORMAT': |
766 |
$value = trim( strtolower( $value )); |
767 |
if( 'xcal' == $value ) { |
768 |
$this->format = 'xcal'; |
769 |
$this->attributeDelimiter = $this->nl; |
770 |
$this->valueInit = null; |
771 |
} |
772 |
else {
|
773 |
$this->format = null; |
774 |
$this->attributeDelimiter = ';'; |
775 |
$this->valueInit = ':'; |
776 |
} |
777 |
$subcfg = array( 'FORMAT' => $value ); |
778 |
$res = TRUE; |
779 |
break;
|
780 |
case 'LANGUAGE': // set language for calendar component as defined in [RFC 1766] |
781 |
$value = trim( $value ); |
782 |
$this->language = $value; |
783 |
$this->_makeProdid();
|
784 |
$subcfg = array( 'LANGUAGE' => $value ); |
785 |
$res = TRUE; |
786 |
break;
|
787 |
case 'NL': |
788 |
case 'NEWLINECHAR': |
789 |
$this->nl = $value; |
790 |
if( 'xcal' == $value ) { |
791 |
$this->attributeDelimiter = $this->nl; |
792 |
$this->valueInit = null; |
793 |
} |
794 |
else {
|
795 |
$this->attributeDelimiter = ';'; |
796 |
$this->valueInit = ':'; |
797 |
} |
798 |
$subcfg = array( 'NL' => $value ); |
799 |
$res = TRUE; |
800 |
break;
|
801 |
case 'TZID': |
802 |
$this->dtzid = $value; |
803 |
$subcfg = array( 'TZID' => $value ); |
804 |
$res = TRUE; |
805 |
break;
|
806 |
case 'UNIQUE_ID': |
807 |
$value = trim( $value ); |
808 |
$this->unique_id = $value; |
809 |
$this->_makeProdid();
|
810 |
$subcfg = array( 'UNIQUE_ID' => $value ); |
811 |
$res = TRUE; |
812 |
break;
|
813 |
case 'URL': |
814 |
/* remote file - URL */
|
815 |
$value = str_replace( array( 'HTTP://', 'WEBCAL://', 'webcal://' ), 'http://', trim( $value )); |
816 |
$value = str_replace( 'HTTPS://', 'https://', trim( $value )); |
817 |
if(( 'http://' != substr( $value, 0, 7 )) && ( 'https://' != substr( $value, 0, 8 ))) |
818 |
return FALSE; |
819 |
$this->directory = '.'; |
820 |
$this->url = $value; |
821 |
if( '.ics' != strtolower( substr( $value, -4 ))) |
822 |
unset( $this->filename ); |
823 |
else
|
824 |
$this->filename = basename( $value ); |
825 |
return TRUE; |
826 |
break;
|
827 |
default: // any unvalid config key.. . |
828 |
return TRUE; |
829 |
} |
830 |
if( !$res ) return FALSE; |
831 |
if( isset( $subcfg ) && !empty( $this->components )) { |
832 |
foreach( $subcfg as $cfgkey => $cfgvalue ) { |
833 |
foreach( $this->components as $cix => $component ) { |
834 |
$res = $component->setConfig( $cfgkey, $cfgvalue, TRUE ); |
835 |
if( !$res ) |
836 |
break 2; |
837 |
$this->components[$cix] = $component->copy(); // PHP4 compliant |
838 |
} |
839 |
} |
840 |
} |
841 |
return $res; |
842 |
} |
843 |
/*********************************************************************************/
|
844 |
/**
|
845 |
* add calendar component to container
|
846 |
*
|
847 |
* alias to setComponent
|
848 |
*
|
849 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
850 |
* @since 1.x.x - 2007-04-24
|
851 |
* @param object $component calendar component
|
852 |
* @uses vcalendar::setComponent()
|
853 |
* @return void
|
854 |
*/
|
855 |
function addComponent( $component ) { |
856 |
$this->setComponent( $component ); |
857 |
} |
858 |
/**
|
859 |
* delete calendar component from container
|
860 |
*
|
861 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
862 |
* @since 2.8.8 - 2011-03-15
|
863 |
* @param mixed $arg1 ordno / component type / component uid
|
864 |
* @param mixed $arg2 optional, ordno if arg1 = component type
|
865 |
* @uses vcalendar::$components
|
866 |
* @uses calendarComponent::$objName
|
867 |
* @uses calendarComponent::getProperty()
|
868 |
* @return void
|
869 |
*/
|
870 |
function deleteComponent( $arg1, $arg2=FALSE ) { |
871 |
$argType = $index = null; |
872 |
if ( ctype_digit( (string) $arg1 )) { |
873 |
$argType = 'INDEX'; |
874 |
$index = (int) $arg1 - 1; |
875 |
} |
876 |
elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) { |
877 |
$argType = strtolower( $arg1 ); |
878 |
$index = ( !empty( $arg2 ) && ctype_digit( (string) $arg2 )) ? (( int ) $arg2 - 1 ) : 0; |
879 |
} |
880 |
$cix1dC = 0; |
881 |
foreach ( $this->components as $cix => $component) { |
882 |
if( empty( $component )) continue; |
883 |
if(( 'INDEX' == $argType ) && ( $index == $cix )) { |
884 |
unset( $this->components[$cix] ); |
885 |
return TRUE; |
886 |
} |
887 |
elseif( $argType == $component->objName ) { |
888 |
if( $index == $cix1dC ) { |
889 |
unset( $this->components[$cix] ); |
890 |
return TRUE; |
891 |
} |
892 |
$cix1dC++;
|
893 |
} |
894 |
elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) { |
895 |
unset( $this->components[$cix] ); |
896 |
return TRUE; |
897 |
} |
898 |
} |
899 |
return FALSE; |
900 |
} |
901 |
/**
|
902 |
* get calendar component from container
|
903 |
*
|
904 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
905 |
* @since 2.21.11 - 2015-03-21
|
906 |
* @param mixed $arg1 optional, ordno/component type/ component uid
|
907 |
* @param mixed $arg2 optional, ordno if arg1 = component type
|
908 |
* @uses vcalendar::$compix
|
909 |
* @uses vcalendar::$components
|
910 |
* @uses iCalUtilityFunctions::$dateProps
|
911 |
* @uses iCalUtilityFunctions::$otherProps
|
912 |
* @uses iCalUtilityFunctions::$mProps1
|
913 |
* @uses calendarComponent::copy()
|
914 |
* @uses calendarComponent::$objName
|
915 |
* @uses calendarComponent::_getProperties()
|
916 |
* @uses calendarComponent::getProperty()
|
917 |
* @uses iCalUtilityFunctions::$fmt
|
918 |
* @return object
|
919 |
*/
|
920 |
function getComponent( $arg1=FALSE, $arg2=FALSE ) { |
921 |
$index = $argType = null; |
922 |
if ( !$arg1 ) { // first or next in component chain |
923 |
$argType = 'INDEX'; |
924 |
$index = $this->compix['INDEX'] = ( isset( $this->compix['INDEX'] )) ? $this->compix['INDEX'] + 1 : 1; |
925 |
} |
926 |
elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] ) |
927 |
$arg2 = implode( '-', array_keys( $arg1 )); |
928 |
$index = $this->compix[$arg2] = ( isset( $this->compix[$arg2] )) ? $this->compix[$arg2] + 1 : 1; |
929 |
} |
930 |
elseif ( ctype_digit( (string) $arg1 )) { // specific component in chain |
931 |
$argType = 'INDEX'; |
932 |
$index = (int) $arg1; |
933 |
unset( $this->compix ); |
934 |
} |
935 |
elseif(( strlen( $arg1 ) <= strlen( 'vfreebusy' )) && ( FALSE === strpos( $arg1, '@' ))) { // object class name |
936 |
unset( $this->compix['INDEX'] ); |
937 |
$argType = strtolower( $arg1 ); |
938 |
if( !$arg2 ) |
939 |
$index = $this->compix[$argType] = ( isset( $this->compix[$argType] )) ? $this->compix[$argType] + 1 : 1; |
940 |
elseif( isset( $arg2 ) && ctype_digit( (string) $arg2 )) |
941 |
$index = (int) $arg2; |
942 |
} |
943 |
elseif(( strlen( $arg1 ) > strlen( 'vfreebusy' )) && ( FALSE !== strpos( $arg1, '@' ))) { // UID as 1st argument |
944 |
if( !$arg2 ) |
945 |
$index = $this->compix[$arg1] = ( isset( $this->compix[$arg1] )) ? $this->compix[$arg1] + 1 : 1; |
946 |
elseif( isset( $arg2 ) && ctype_digit( (string) $arg2 )) |
947 |
$index = (int) $arg2; |
948 |
} |
949 |
if( isset( $index )) |
950 |
$index -= 1; |
951 |
$ckeys = array_keys( $this->components ); |
952 |
if( !empty( $index) && ( $index > end( $ckeys ))) |
953 |
return FALSE; |
954 |
$cix1gC = 0; |
955 |
foreach ( $this->components as $cix => $component) { |
956 |
if( empty( $component )) continue; |
957 |
if(( 'INDEX' == $argType ) && ( $index == $cix )) |
958 |
return $component->copy(); |
959 |
elseif( $argType == $component->objName ) { |
960 |
if( $index == $cix1gC ) |
961 |
return $component->copy(); |
962 |
$cix1gC++;
|
963 |
} |
964 |
elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] ) |
965 |
$hit = array(); |
966 |
$arg1 = array_change_key_case( $arg1, CASE_UPPER ); |
967 |
foreach( $arg1 as $pName => $pValue ) { |
968 |
if( !in_array( $pName, iCalUtilityFunctions::$dateProps ) && !in_array( $pName, iCalUtilityFunctions::$otherProps )) |
969 |
continue;
|
970 |
if( in_array( $pName, iCalUtilityFunctions::$mProps1 )) { // multiple occurrence |
971 |
$propValues = array(); |
972 |
$component->_getProperties( $pName, $propValues ); |
973 |
$propValues = array_keys( $propValues ); |
974 |
$hit[] = ( in_array( $pValue, $propValues )) ? TRUE : FALSE; |
975 |
continue;
|
976 |
} // end if(.. .// multiple occurrence
|
977 |
if( FALSE === ( $value = $component->getProperty( $pName ))) { // single occurrence |
978 |
$hit[] = FALSE; // missing property |
979 |
continue;
|
980 |
} |
981 |
if( 'SUMMARY' == $pName ) { // exists within (any case) |
982 |
$hit[] = ( FALSE !== stripos( $value, $pValue )) ? TRUE : FALSE; |
983 |
continue;
|
984 |
} |
985 |
if( in_array( $pName, iCalUtilityFunctions::$dateProps )) { |
986 |
$valuedate = sprintf( iCalUtilityFunctions::$fmt['Ymd'], (int) $value['year'], (int) $value['month'], (int) $value['day'] ); |
987 |
if( 8 < strlen( $pValue )) { |
988 |
if( isset( $value['hour'] )) { |
989 |
if( 'T' == substr( $pValue, 8, 1 )) |
990 |
$pValue = str_replace( 'T', '', $pValue ); |
991 |
$valuedate .= sprintf( iCalUtilityFunctions::$fmt['His'], (int) $value['hour'], (int) $value['min'], (int) $value['sec'] ); |
992 |
} |
993 |
else
|
994 |
$pValue = substr( $pValue, 0, 8 ); |
995 |
} |
996 |
$hit[] = ( $pValue == $valuedate ) ? TRUE : FALSE; |
997 |
continue;
|
998 |
} |
999 |
elseif( !is_array( $value )) |
1000 |
$value = array( $value ); |
1001 |
foreach( $value as $part ) { |
1002 |
$part = ( FALSE !== strpos( $part, ',' )) ? explode( ',', $part ) : array( $part ); |
1003 |
foreach( $part as $subPart ) { |
1004 |
if( $pValue == $subPart ) { |
1005 |
$hit[] = TRUE; |
1006 |
continue 3; |
1007 |
} |
1008 |
} |
1009 |
} // end foreach( $value as $part )
|
1010 |
$hit[] = FALSE; // no hit in property |
1011 |
} // end foreach( $arg1 as $pName => $pValue )
|
1012 |
if( in_array( TRUE, $hit )) { |
1013 |
if( $index == $cix1gC ) |
1014 |
return $component->copy(); |
1015 |
$cix1gC++;
|
1016 |
} |
1017 |
} // end elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] )
|
1018 |
elseif( !$argType && ($arg1 == $component->getProperty( 'uid' ))) { // UID |
1019 |
if( $index == $cix1gC ) |
1020 |
return $component->copy(); |
1021 |
$cix1gC++;
|
1022 |
} |
1023 |
} // end foreach ( $this->components.. .
|
1024 |
/* not found.. . */
|
1025 |
unset( $this->compix ); |
1026 |
return FALSE; |
1027 |
} |
1028 |
/**
|
1029 |
* create new calendar component, already included within calendar
|
1030 |
*
|
1031 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1032 |
* @since 2.20.4 - 2014-08-24
|
1033 |
* @param string $compType component type
|
1034 |
* @uses vcalendar::$components
|
1035 |
* @return object
|
1036 |
*/
|
1037 |
function & newComponent( $compType ) { |
1038 |
$config = $this->getConfig(); |
1039 |
$keys = array_keys( $this->components ); |
1040 |
$ix = ( empty( $keys )) ? 0 : end( $keys) + 1; |
1041 |
switch( strtoupper( $compType )) { |
1042 |
case 'EVENT': |
1043 |
case 'VEVENT': |
1044 |
$this->components[$ix] = new vevent( $config ); |
1045 |
break;
|
1046 |
case 'TODO': |
1047 |
case 'VTODO': |
1048 |
$this->components[$ix] = new vtodo( $config ); |
1049 |
break;
|
1050 |
case 'JOURNAL': |
1051 |
case 'VJOURNAL': |
1052 |
$this->components[$ix] = new vjournal( $config ); |
1053 |
break;
|
1054 |
case 'FREEBUSY': |
1055 |
case 'VFREEBUSY': |
1056 |
$this->components[$ix] = new vfreebusy( $config ); |
1057 |
break;
|
1058 |
case 'TIMEZONE': |
1059 |
case 'VTIMEZONE': |
1060 |
array_unshift( $this->components, new vtimezone( $config )); |
1061 |
$ix = 0; |
1062 |
break;
|
1063 |
default:
|
1064 |
return FALSE; |
1065 |
} |
1066 |
return $this->components[$ix]; |
1067 |
} |
1068 |
/**
|
1069 |
* select components from calendar on date or selectOption basis
|
1070 |
*
|
1071 |
* Ensure DTSTART is set for every component.
|
1072 |
* No date controls occurs.
|
1073 |
*
|
1074 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1075 |
* @since 2.21.11 - 2015-03-31
|
1076 |
* @param mixed $startY optional, (int) start Year, default current Year
|
1077 |
* ALT. (obj) start date (datetime)
|
1078 |
* ALT. array selecOptions ( *[ <propName> => <uniqueValue> ] )
|
1079 |
* @param mixed $startM optional, (int) start Month, default current Month
|
1080 |
* ALT. (obj) end date (datetime)
|
1081 |
* @param int $startD optional, start Day, default current Day
|
1082 |
* @param int $endY optional, end Year, default $startY
|
1083 |
* @param int $endM optional, end Month, default $startM
|
1084 |
* @param int $endD optional, end Day, default $startD
|
1085 |
* @param mixed $cType optional, calendar component type(-s), default FALSE=all else string/array type(-s)
|
1086 |
* @param bool $flat optional, FALSE (default) => output : array[Year][Month][Day][]
|
1087 |
* TRUE => output : array[] (ignores split)
|
1088 |
* @param bool $any optional, TRUE (default) - select component(-s) that occurs within period
|
1089 |
* FALSE - only component(-s) that starts within period
|
1090 |
* @param bool $split optional, TRUE (default) - one component copy every DAY it occurs during the
|
1091 |
* period (implies flat=FALSE)
|
1092 |
* FALSE - one occurance of component only in output array
|
1093 |
* @uses vcalendar::$components
|
1094 |
* @uses vcalendar::selectComponents2()
|
1095 |
* @uses iCalUtilityFunctions::$vComps
|
1096 |
* @uses calendarComponent::$objName
|
1097 |
* @uses calendarComponent::getProperty()
|
1098 |
* @uses iCaldateTime::factory()
|
1099 |
* @uses iCaldateTime::getTimezoneName()
|
1100 |
* @uses iCaldateTime::getTime()
|
1101 |
* @uses iCalUtilityFunctions::$fmt
|
1102 |
* @uses iCaldateTime::$SCbools
|
1103 |
* @uses iCaldateTime::format()
|
1104 |
* @uses iCalUtilityFunctions::_strDate2arr()
|
1105 |
* @uses iCalUtilityFunctions::_recur2date()
|
1106 |
* @uses iCalUtilityFunctions::_inScope()
|
1107 |
* @uses calendarComponent::copy()
|
1108 |
* @uses calendarComponent::setProperty()
|
1109 |
* @uses iCalUtilityFunctions::$fmt
|
1110 |
* @uses calendarComponent::deleteProperty()
|
1111 |
* @uses iCalUtilityFunctions::_setSortArgs()
|
1112 |
* @uses iCalUtilityFunctions::_cmpfcn()
|
1113 |
* @return array or FALSE
|
1114 |
*/
|
1115 |
function selectComponents( $startY=FALSE, $startM=FALSE, $startD=FALSE, $endY=FALSE, $endM=FALSE, $endD=FALSE, $cType=FALSE, $flat=FALSE, $any=TRUE, $split=TRUE ) { |
1116 |
/* check if empty calendar */
|
1117 |
if( 0 >= count( $this->components )) return FALSE; |
1118 |
if( is_array( $startY )) |
1119 |
return $this->selectComponents2( $startY ); |
1120 |
/* check default dates */
|
1121 |
if( is_a( $startY, 'DateTime' ) && is_a( $startM, 'DateTime' )) { |
1122 |
$endY = $startM->format( 'Y' ); |
1123 |
$endM = $startM->format( 'm' ); |
1124 |
$endD = $startM->format( 'd' ); |
1125 |
$startD = $startY->format( 'd' ); |
1126 |
$startM = $startY->format( 'm' ); |
1127 |
$startY = $startY->format( 'Y' ); |
1128 |
} |
1129 |
else {
|
1130 |
if( ! $startY ) $startY = date( 'Y' ); |
1131 |
if( ! $startM ) $startM = date( 'm' ); |
1132 |
if( ! $startD ) $startD = date( 'd' ); |
1133 |
if( ! $endY ) $endY = $startY; |
1134 |
if( ! $endM ) $endM = $startM; |
1135 |
if( ! $endD ) $endD = $startD; |
1136 |
} |
1137 |
// echo "selectComp args={$startY}-{$startM}-{$startD} - {$endY}-{$endM}-{$endD}<br>\n"; $tcnt = 0;// test ###
|
1138 |
/* check component types */
|
1139 |
if( empty( $cType )) |
1140 |
$cType = iCalUtilityFunctions::$vComps; |
1141 |
else {
|
1142 |
if( ! is_array( $cType )) |
1143 |
$cType = array( $cType ); |
1144 |
$cType = array_map( 'strtolower', $cType ); |
1145 |
foreach( $cType as $cix => $theType ) { |
1146 |
if( !in_array( $theType, iCalUtilityFunctions::$vComps )) |
1147 |
$cType[$cix] = 'vevent'; |
1148 |
} |
1149 |
$cType = array_unique( $cType ); |
1150 |
} |
1151 |
if(( FALSE === $flat ) && ( FALSE === $any )) // invalid combination |
1152 |
$split = FALSE; |
1153 |
if(( TRUE === $flat ) && ( TRUE === $split )) // invalid combination |
1154 |
$split = FALSE; |
1155 |
/* iterate components */
|
1156 |
$result = array(); |
1157 |
$this->sort( 'UID' ); |
1158 |
$compUIDcmp = null; |
1159 |
$exdatelist = $recurridList = array(); |
1160 |
$intervalP1D = new DateInterval( 'P1D' ); |
1161 |
foreach ( $this->components as $cix => $component ) { |
1162 |
if( empty( $component )) continue; |
1163 |
/* deselect unvalid type components */
|
1164 |
if( !in_array( $component->objName, $cType )) |
1165 |
continue;
|
1166 |
unset( $compStart, $compEnd ); |
1167 |
/* select start from dtstart or due if dtstart is missing */
|
1168 |
$prop = $component->getProperty( 'dtstart', FALSE, TRUE ); |
1169 |
if( empty( $prop ) && ( $component->objName == 'vtodo' ) && ( FALSE === ( $prop = $component->getProperty( 'due', FALSE, TRUE )))) |
1170 |
continue;
|
1171 |
if( empty( $prop )) |
1172 |
continue;
|
1173 |
/* get UID */
|
1174 |
$compUID = $component->getProperty( 'UID' ); |
1175 |
if( $compUIDcmp != $compUID ) { |
1176 |
$compUIDcmp = $compUID; |
1177 |
$exdatelist = $recurridList = array(); |
1178 |
} |
1179 |
$recurrid = FALSE; |
1180 |
// file_put_contents( '/opt/work/iCal/iCalcreator/iCalcreator-2.20.x/log/log.txt', "#$cix".PHP_EOL.var_export( $component, TRUE ).PHP_EOL.PHP_EOL, FILE_APPEND ); // test ###
|
1181 |
$compStart = iCaldateTime::factory( $prop['value'], $prop['params'], $prop['value'] ); |
1182 |
$dtstartTz = $compStart->getTimezoneName(); |
1183 |
if( isset( $prop['params']['VALUE'] ) && ( 'DATE' == $prop['params']['VALUE'] )) |
1184 |
$compStartHis = ''; |
1185 |
else {
|
1186 |
$his = $compStart->getTime(); |
1187 |
$compStartHis = sprintf( iCalUtilityFunctions::$fmt['His'], (int) $his[0], (int) $his[1], (int) $his[2] ); |
1188 |
} |
1189 |
/* get end date from dtend/due/duration properties */
|
1190 |
if( FALSE !== ( $prop = $component->getProperty( 'dtend', FALSE, TRUE ))) { |
1191 |
$compEnd = iCaldateTime::factory( $prop['value'], $prop['params'], $prop['value'], $dtstartTz ); |
1192 |
$compEnd->SCbools[ 'dtendExist'] = TRUE; |
1193 |
} |
1194 |
if( empty( $prop ) && ( $component->objName == 'vtodo' ) && ( FALSE !== ( $prop = $component->getProperty( 'due', FALSE, TRUE )))) { |
1195 |
$compEnd = iCaldateTime::factory( $prop['value'], $prop['params'], $prop['value'], $dtstartTz ); |
1196 |
$compEnd->SCbools[ 'dueExist'] = TRUE; |
1197 |
} |
1198 |
if( empty( $prop ) && ( FALSE !== ( $prop = $component->getProperty( 'duration', FALSE, TRUE, TRUE )))) { // in dtend (array) format |
1199 |
$compEnd = iCaldateTime::factory( $prop['value'], $prop['params'], $prop['value'], $dtstartTz ); |
1200 |
$compEnd->SCbools[ 'durationExist'] = TRUE; |
1201 |
} |
1202 |
if( ! empty( $prop ) && ! isset( $prop['value']['hour'] )) { |
1203 |
/* a DTEND without time part denotes an end of an event that actually ends the day before,
|
1204 |
for an all-day event DTSTART=20071201 DTEND=20071202, taking place 20071201!!! */
|
1205 |
$compEnd->SCbools[ 'endAllDayEvent'] = TRUE; |
1206 |
$compEnd->modify( '-1 day' ); |
1207 |
$compEnd->setTime( 23, 59, 59 ); |
1208 |
} |
1209 |
unset( $prop ); |
1210 |
if( empty( $compEnd )) { |
1211 |
$compDuration = FALSE; |
1212 |
$compEnd = clone $compStart; |
1213 |
$compEnd->setTime( 23, 59, 59 ); // 23:59:59 the same day as start |
1214 |
} |
1215 |
else {
|
1216 |
if( $compEnd->format( 'Ymd' ) < $compStart->format( 'Ymd' )) { // MUST be after start date!! |
1217 |
$compEnd = clone $compStart; |
1218 |
$compEnd->setTime( 23, 59, 59 ); // 23:59:59 the same day as start or ??? |
1219 |
} |
1220 |
$compDuration = $compStart->diff( $compEnd ); // DateInterval |
1221 |
} |
1222 |
/* check recurrence-id (note, a missing sequence is the same as sequence=0 so don't test for sequence), to alter when hit dtstart/recurlist */
|
1223 |
if( FALSE !== ( $prop = $component->getProperty( 'recurrence-id', FALSE, TRUE ))) { |
1224 |
$recurrid = iCaldateTime::factory( $prop['value'], $prop['params'], $prop['value'], $dtstartTz ); |
1225 |
$rangeSet = ( isset( $prop['params']['RANGE'] ) && ( 'THISANDFUTURE' == $prop['params']['RANGE'] )) ? TRUE : FALSE; |
1226 |
$recurridList[$recurrid->key] = array( clone $compStart, clone $compEnd, $compDuration, $rangeSet ); // change recur this day to new YmdHis/duration/range |
1227 |
// echo "adding comp no:$cix with date=".$compStart->format(iCalUtilityFunctions::$fmt['YmdHis2e'])." to recurridList id={$recurrid->key}, newDate={$compStart->key}<br>\n"; // test ###
|
1228 |
unset( $prop ); |
1229 |
continue; // ignore any other props in the component |
1230 |
} // end recurrence-id/sequence test
|
1231 |
// else echo "comp no:$cix with date=".$compStart->format().", NO recurrence-id<br>\n"; // test ###
|
1232 |
ksort( $recurridList, SORT_STRING ); |
1233 |
// echo 'recurridList='.implode(', ', array_keys( $recurridList ))."<br>\n"; // test ###
|
1234 |
$fcnStart = clone $compStart; |
1235 |
$fcnStart->setDate((int) $startY, (int) $startM, (int) $startD ); |
1236 |
$fcnStart->setTime( 0, 0, 0 ); |
1237 |
$fcnEnd = clone $compEnd; |
1238 |
$fcnEnd->setDate((int) $endY, (int) $endM, (int) $endD ); |
1239 |
$fcnEnd->setTime( 23, 59, 59 ); |
1240 |
// echo 'compStart='.$compStart->format().', compEnd'.$compEnd->format(); if($compDuration)echo ', interval='.$compDuration->format( iCalUtilityFunctions::$fmt['durDHis'] ); echo "<br>\n"; $tcnt = 0;// test ###
|
1241 |
/* *************************************************************
|
1242 |
make a list of optional exclude dates for component occurence from exrule and exdate
|
1243 |
*********************************************************** */
|
1244 |
$workStart = clone $compStart; |
1245 |
$workStart->sub( $compDuration ? $compDuration : $intervalP1D ); |
1246 |
$workEnd = clone $fcnEnd; |
1247 |
$workEnd->add( $compDuration ? $compDuration : $intervalP1D ); |
1248 |
while( FALSE !== ( $prop = $component->getProperty( 'EXRULE' ))) { |
1249 |
$exdatelist2 = array(); |
1250 |
if( isset( $prop['UNTIL']['hour'] )) { // convert until date to dtstart timezone |
1251 |
$until = iCaldateTime::factory( $prop['UNTIL'], array( 'TZID' => 'UTC' ), null, $dtstartTz ); |
1252 |
$until = $until->format(); |
1253 |
iCalUtilityFunctions::_strDate2arr( $until );
|
1254 |
$prop['UNTIL'] = $until; |
1255 |
} |
1256 |
iCalUtilityFunctions::_recur2date( $exdatelist2, $prop, $compStart, $workStart, $workEnd ); |
1257 |
foreach( $exdatelist2 as $k => $v ) |
1258 |
$exdatelist[$k.$compStartHis] = $v; // point out exact every excluded ocurrence (incl. opt. His) |
1259 |
unset( $until, $exdatelist2 ); |
1260 |
} |
1261 |
while( FALSE !== ( $prop = $component->getProperty( 'EXDATE', FALSE, TRUE ))) { // - start check exdate |
1262 |
foreach( $prop['value'] as $exdate ) { |
1263 |
$exdate = iCaldateTime::factory( $exdate, $prop['params'], $exdate, $dtstartTz ); |
1264 |
$exdatelist[$exdate->key] = TRUE; |
1265 |
} // end - foreach( $exdate as $exdate )
|
1266 |
} // end - check exdate
|
1267 |
unset( $prop, $exdate ); |
1268 |
// echo 'exdatelist=' .implode(', ', array_keys( $exdatelist )) ."<br>\n"; // test ###
|
1269 |
/* *************************************************************
|
1270 |
select only components within.. .
|
1271 |
*********************************************************** */
|
1272 |
$xRecurrence = 1; |
1273 |
if(( ! $any && iCalUtilityFunctions::_inScope( $compStart, $fcnStart, $compStart, $fcnEnd, $compStart->dateFormat )) || |
1274 |
( $any && iCalUtilityFunctions::_inScope( $fcnEnd, $compStart, $fcnStart, $compEnd, $compStart->dateFormat ))) { |
1275 |
/* add the selected component (WITHIN valid dates) to output array */
|
1276 |
if( $flat ) { // any=true/false, ignores split |
1277 |
if( !$recurrid ) |
1278 |
$result[$compUID] = $component->copy(); // copy original to output (but not anyone with recurrence-id) |
1279 |
} |
1280 |
elseif( $split ) { // split the original component |
1281 |
// echo 'split org.:'.$compStart->format().' < '.$fcnStart->format( 'Ymd His e' )."<br>\n"; // test ###
|
1282 |
if( $compStart->format( iCalUtilityFunctions::$fmt['YmdHis2'] ) < $fcnStart->format( iCalUtilityFunctions::$fmt['YmdHis2'] )) |
1283 |
$rstart = clone $fcnStart; |
1284 |
else
|
1285 |
$rstart = clone $compStart; |
1286 |
if( $compEnd->format( iCalUtilityFunctions::$fmt['YmdHis2'] ) > $fcnEnd->format( iCalUtilityFunctions::$fmt['YmdHis2'] )) |
1287 |
$rend = clone $fcnEnd; |
1288 |
else
|
1289 |
$rend = clone $compEnd; |
1290 |
// echo "going to test comp no:$cix, rstart=".$rstart->format( iCalUtilityFunctions::$fmt['YmdHis2e'] )." (key={$rstart->key}), end=".$rend->format( iCalUtilityFunctions::$fmt['YmdHis2e'] )."<br>\n"; // test ###
|
1291 |
if( ! isset( $exdatelist[$rstart->key] )) { // not excluded in exrule/exdate |
1292 |
if( isset( $recurridList[$rstart->key] )) { // change start day to new YmdHis/duration |
1293 |
$k = $rstart->key; |
1294 |
// echo "recurridList HIT, key={$k}, recur Date=".$recurridList[$k][0]->key."<br>\n"; // test ###
|
1295 |
$rstart = clone $recurridList[$k][0]; |
1296 |
$startHis = $rstart->getTime(); |
1297 |
$rend = clone $rstart; |
1298 |
if( FALSE !== $recurridList[$k][2] ) |
1299 |
$rend->add( $recurridList[$k][2] ); |
1300 |
elseif( FALSE !== $compDuration ) |
1301 |
$rend->add( $compDuration ); |
1302 |
$endHis = $rend->getTime(); |
1303 |
unset( $recurridList[$k] ); |
1304 |
} |
1305 |
else {
|
1306 |
$startHis = $compStart->getTime(); |
1307 |
$endHis = $compEnd->getTime(); |
1308 |
} |
1309 |
// echo "_____testing comp no:$cix, rstart=".$rstart->format( iCalUtilityFunctions::$fmt['YmdHis2e'] )." (key={$rstart->key}), end=".$rend->format( iCalUtilityFunctions::$fmt['YmdHis2e'] )."<br>\n"; // test ###
|
1310 |
$cnt = 0; // exclude any recurrence START date, found in exdatelist or recurridList but accept the reccurence-id comp itself |
1311 |
$occurenceDays = 1 + (int) $rstart->diff( $rend )->format( '%a' ); // count the days (incl start day) |
1312 |
while( $rstart->format( iCalUtilityFunctions::$fmt['Ymd2'] ) <= $rend->format( iCalUtilityFunctions::$fmt['Ymd2'] )) { |
1313 |
$cnt += 1; |
1314 |
if( 1 < $occurenceDays ) |
1315 |
$component->setProperty( 'X-OCCURENCE', sprintf( iCalUtilityFunctions::$fmt['dayOfDays'], $cnt, $occurenceDays )); |
1316 |
if( 1 < $cnt ) |
1317 |
$rstart->setTime( 0, 0, 0 ); |
1318 |
else {
|
1319 |
$rstart->setTime( $startHis[0], $startHis[1], $startHis[2] ); |
1320 |
$exdatelist[$rstart->key] = $compDuration; // make sure to exclude start day from the recurrence pattern |
1321 |
} |
1322 |
$component->setProperty( 'X-CURRENT-DTSTART', $rstart->format( $compStart->dateFormat )); |
1323 |
if( FALSE !== $compDuration ) { |
1324 |
$propName = ( isset( $compEnd->SCbools[ 'dueExist'] )) ? 'X-CURRENT-DUE' : 'X-CURRENT-DTEND'; |
1325 |
if( $cnt < $occurenceDays ) |
1326 |
$rstart->setTime( 23, 59, 59 ); |
1327 |
else
|
1328 |
$rstart->setTime( $endHis[0], $endHis[1], $endHis[2] ); |
1329 |
$component->setProperty( $propName, $rstart->format( $compEnd->dateFormat )); |
1330 |
} |
1331 |
$result[(int)$rstart->format( 'Y' )][(int)$rstart->format( 'm' )][(int)$rstart->format( 'd' )][$compUID] = $component->copy(); // copy to output |
1332 |
$rstart->add( $intervalP1D ); |
1333 |
} // end while(( $rstart->format( 'Ymd' ) < $rend->format( 'Ymd' ))
|
1334 |
unset( $cnt, $occurenceDays ); |
1335 |
} // end if( ! isset( $exdatelist[$rstart->key] ))
|
1336 |
// else echo "skip no:$cix with date=".$compStart->format()."<br>\n"; // test ###
|
1337 |
unset( $rstart, $rend ); |
1338 |
} // end elseif( $split ) - else use component date
|
1339 |
else { // !$flat && !$split, i.e. no flat array and DTSTART within period |
1340 |
$tstart = ( isset( $recurridList[$compStart->key] )) ? clone $recurridList[$k][0] : clone $compStart; |
1341 |
// echo "going to test comp no:$cix with checkDate={$compStart->key} with recurridList=".implode(',',array_keys($recurridList)); // test ###
|
1342 |
if( ! $any || ! isset( $exdatelist[$tstart->key] )) { // exclude any recurrence date, found in exdatelist |
1343 |
// echo " and copied to output<br>\n"; // test ###
|
1344 |
$result[(int)$tstart->format( 'Y' )][(int)$tstart->format( 'm' )][(int)$tstart->format( 'd' )][$compUID] = $component->copy(); // copy to output |
1345 |
} |
1346 |
unset( $tstart ); |
1347 |
} |
1348 |
} // end (dt)start within the period OR occurs within the period
|
1349 |
/* *************************************************************
|
1350 |
if 'any' components, check components with reccurrence rules, removing all excluding dates
|
1351 |
*********************************************************** */
|
1352 |
if( TRUE === $any ) { |
1353 |
$recurlist = array(); |
1354 |
/* make a list of optional repeating dates for component occurence, rrule, rdate */
|
1355 |
while( FALSE !== ( $prop = $component->getProperty( 'RRULE' ))) { // get all rrule dates (multiple values allowed) |
1356 |
$recurlist2 = array(); |
1357 |
if( isset( $prop['UNTIL']['hour'] )) { // convert $rrule['UNTIL'] to the same timezone as DTSTART !! |
1358 |
$until = iCaldateTime::factory( $prop['UNTIL'], array( 'TZID' => 'UTC' ), null, $dtstartTz ); |
1359 |
$until = $until->format(); |
1360 |
iCalUtilityFunctions::_strDate2arr( $until );
|
1361 |
$prop['UNTIL'] = $until; |
1362 |
} |
1363 |
iCalUtilityFunctions::_recur2date( $recurlist2, $prop, $compStart, $workStart, $workEnd ); |
1364 |
foreach( $recurlist2 as $recurkey => $recurvalue ) { // recurkey=Ymd |
1365 |
$recurkey .= $compStartHis; // add opt His |
1366 |
if( ! isset( $exdatelist[$recurkey] )) |
1367 |
$recurlist[$recurkey] = $compDuration; // DateInterval or FALSE |
1368 |
} |
1369 |
unset( $prop, $until, $recurlist2 ); |
1370 |
} |
1371 |
$workStart = clone $fcnStart; |
1372 |
$workStart->sub( $compDuration ? $compDuration : $intervalP1D ); |
1373 |
$format = $compStart->dateFormat; |
1374 |
while( FALSE !== ( $prop = $component->getProperty( 'RDATE', FALSE, TRUE ))) { |
1375 |
$rdateFmt = ( isset( $prop['params']['VALUE'] )) ? $prop['params']['VALUE'] : 'DATETIME'; |
1376 |
$params = $prop['params']; |
1377 |
$prop = $prop['value']; |
1378 |
foreach( $prop as $theRdate ) { |
1379 |
if( 'PERIOD' == $rdateFmt ) { // all days within PERIOD |
1380 |
$rdate = iCaldateTime::factory( $theRdate[0], $params, $theRdate[0], $dtstartTz ); |
1381 |
if( ! iCalUtilityFunctions::_inScope( $rdate, $workStart, $rdate, $fcnEnd, $format ) || isset( $exdatelist[$rdate->key] )) |
1382 |
continue;
|
1383 |
if( isset( $theRdate[1]['year'] )) // date-date period end |
1384 |
$recurlist[$rdate->key] = $rdate->diff( iCaldateTime::factory( $theRdate[1], $params, $theRdate[1], $dtstartTz )); |
1385 |
else // period duration |
1386 |
$recurlist[$rdate->key] = new DateInterval( iCalUtilityFunctions::_duration2str( $theRdate[1] )); |
1387 |
} // end if( 'PERIOD' == $rdateFmt )
|
1388 |
elseif( 'DATE' == $rdateFmt ) { // single recurrence, date |
1389 |
$rdate = iCaldateTime::factory( $theRdate, array_merge( $params, array( 'TZID' => $dtstartTz )), null, $dtstartTz ); |
1390 |
if( iCalUtilityFunctions::_inScope( $rdate, $workStart, $rdate, $fcnEnd, $format ) && ! isset( $exdatelist[$rdate->key] )) |
1391 |
$recurlist[$rdate->key.$compStartHis] = $compDuration; // set start date for recurrence + DateInterval/FALSE (+opt His) |
1392 |
} // end DATE
|
1393 |
else { // start DATETIME |
1394 |
$rdate = iCaldateTime::factory( $theRdate, $params, $theRdate, $dtstartTz ); |
1395 |
if( iCalUtilityFunctions::_inScope( $rdate, $workStart, $rdate, $fcnEnd, $format ) && ! isset( $exdatelist[$rdate->key] )) |
1396 |
$recurlist[$rdate->key] = $compDuration; // set start datetime for recurrence DateInterval/FALSE |
1397 |
} // end DATETIME
|
1398 |
} // end foreach( $prop as $theRdate )
|
1399 |
} // end while( FALSE !== ( $prop = $component->getProperty( 'rdate', FALSE, TRUE )))
|
1400 |
unset( $prop, $workStart, $format, $theRdate, $rdate, $rend ); |
1401 |
foreach( $recurridList as $rKey => $rVal ) { // check for recurrence-id, i.e. alter recur Ymd[His] and duration |
1402 |
if( isset( $recurlist[$rKey] )) { |
1403 |
unset( $recurlist[$rKey] ); |
1404 |
$recurlist[$rVal[0]->key] = ( FALSE !== $rVal[2] ) ? $rVal[2] : $compDuration; |
1405 |
// echo "alter recurfrom {$rKey} to {$rVal[0]->key} ";if(FALSE!==$dur)echo " ({$dur->format( '%a days, %h-%i-%s' )})";echo "<br>\n"; // test ###
|
1406 |
} |
1407 |
} |
1408 |
ksort( $recurlist, SORT_STRING ); |
1409 |
// echo 'recurlist=' .implode(', ', array_keys( $recurlist )) ."<br>\n"; // test ###
|
1410 |
// echo 'recurridList=' .implode(', ', array_keys( $recurridList )) ."<br>\n"; // test ###
|
1411 |
/* *************************************************************
|
1412 |
output all remaining components in recurlist
|
1413 |
*********************************************************** */
|
1414 |
if( 0 < count( $recurlist )) { |
1415 |
$component2 = $component->copy(); |
1416 |
$compUID = $component2->getProperty( 'UID' ); |
1417 |
$workStart = clone $fcnStart; |
1418 |
$workStart->sub( $compDuration ? $compDuration : $intervalP1D ); |
1419 |
$YmdOld = null; |
1420 |
foreach( $recurlist as $recurkey => $durvalue ) { |
1421 |
if( $YmdOld == substr( $recurkey, 0, 8 )) // skip overlapping recur the same day, i.e. RDATE before RRULE |
1422 |
continue;
|
1423 |
$YmdOld = substr( $recurkey, 0, 8 ); |
1424 |
$rstart = clone $compStart; |
1425 |
$rstart->setDate((int) substr( $recurkey, 0, 4 ), (int) substr( $recurkey, 4, 2 ), (int) substr( $recurkey, 6, 2 )); |
1426 |
$rstart->setTime((int) substr( $recurkey, 8, 2 ), (int) substr( $recurkey, 10, 2 ), (int) substr( $recurkey, 12, 2 )); |
1427 |
// echo "recur start=".$rstart->format( iCalUtilityFunctions::$fmt['YmdHis2e'] )."<br>\n"; // test ###;
|
1428 |
/* add recurring components within valid dates to output array, only start date set */
|
1429 |
if( $flat ) { |
1430 |
if( !isset( $result[$compUID] )) // only one comp |
1431 |
$result[$compUID] = $component2->copy(); // copy to output |
1432 |
} |
1433 |
/* add recurring components within valid dates to output array, split for each day */
|
1434 |
elseif( $split ) { |
1435 |
$rend = clone $rstart; |
1436 |
if( FALSE !== $durvalue ) |
1437 |
$rend->add( $durvalue ); |
1438 |
if( $rend->format( iCalUtilityFunctions::$fmt['Ymd2'] ) > $fcnEnd->format( iCalUtilityFunctions::$fmt['Ymd2'] )) |
1439 |
$rend = clone $fcnEnd; |
1440 |
// echo "recur 1={$recurkey}, start=".$rstart->format( iCalUtilityFunctions::$fmt['YmdHis2e'] ).", end=".$rend->format( iCalUtilityFunctions::$fmt['YmdHis2e'] );if($durvalue) echo ", duration=".$durvalue->format( iCalUtilityFunctions::$fmt['durDHis'] );echo "<br>\n"; // test ###
|
1441 |
$xRecurrence += 1; |
1442 |
$cnt = 0; |
1443 |
$occurenceDays = 1 + (int) $rstart->diff( $rend )->format( '%a' ); // count the days (incl start day) |
1444 |
while( $rstart->format( iCalUtilityFunctions::$fmt['Ymd2'] ) <= $rend->format( iCalUtilityFunctions::$fmt['Ymd2'] )) { // iterate.. . |
1445 |
$cnt += 1; |
1446 |
if( $rstart->format( iCalUtilityFunctions::$fmt['Ymd2'] ) < $fcnStart->format( iCalUtilityFunctions::$fmt['Ymd2'] )) { // date before dtstart |
1447 |
// echo "recur 3, start=".$rstart->format( 'Y-m-d H:i:s' )." >= fcnStart=".$fcnStart->format( 'Y-m-d H:i:s' )."<br>\n"; // test ###
|
1448 |
$rstart->add( $intervalP1D ); |
1449 |
$rstart->setTime( 0, 0, 0 ); |
1450 |
continue;
|
1451 |
} |
1452 |
elseif( 2 == $cnt ) |
1453 |
$rstart->setTime( 0, 0, 0 ); |
1454 |
$component2->setProperty( 'X-RECURRENCE', $xRecurrence ); |
1455 |
if( 1 < $occurenceDays ) |
1456 |
$component2->setProperty( 'X-OCCURENCE', sprintf( iCalUtilityFunctions::$fmt['dayOfDays'], $cnt, $occurenceDays )); |
1457 |
else
|
1458 |
$component2->deleteProperty( 'X-OCCURENCE' ); |
1459 |
$component2->setProperty( 'X-CURRENT-DTSTART', $rstart->format( $compStart->dateFormat )); |
1460 |
$propName = ( isset( $compEnd->SCbools[ 'dueExist'] )) ? 'X-CURRENT-DUE' : 'X-CURRENT-DTEND'; |
1461 |
if( FALSE !== $durvalue ) { |
1462 |
if( $cnt < $occurenceDays ) |
1463 |
$rstart->setTime( 23, 59, 59 ); |
1464 |
else {
|
1465 |
$His = $rend->getTime(); // set end time |
1466 |
$rstart->setTime( $His[0], $His[1], $His[2] ); |
1467 |
} |
1468 |
$component2->setProperty( $propName, $rstart->format( $compEnd->dateFormat )); |
1469 |
// echo "checking date, (day {$cnt} of {$occurenceDays}), _end_=".$rstart->format( 'Y-m-d H:i:s e' )."<br>"; // test ###;
|
1470 |
} |
1471 |
else
|
1472 |
$component2->deleteProperty( $propName ); |
1473 |
$result[(int)$rstart->format( 'Y' )][(int)$rstart->format( 'm' )][(int)$rstart->format( 'd' )][$compUID] = $component2->copy(); // copy to output |
1474 |
$rstart->add( $intervalP1D ); |
1475 |
} // end while( $rstart->format( 'Ymd' ) <= $rend->format( 'Ymd' ))
|
1476 |
unset( $rstart, $rend ); |
1477 |
} // end elseif( $split )
|
1478 |
elseif( $rstart->format( iCalUtilityFunctions::$fmt['Ymd2'] ) >= $fcnStart->format( iCalUtilityFunctions::$fmt['Ymd2'] )) { |
1479 |
$xRecurrence += 1; // date within period //* flat=FALSE && split=FALSE => one comp every recur startdate *// |
1480 |
$component2->setProperty( 'X-RECURRENCE', $xRecurrence ); |
1481 |
$component2->setProperty( 'X-CURRENT-DTSTART', $rstart->format( $compStart->dateFormat )); |
1482 |
$propName = ( isset( $compEnd->SCbools[ 'dueExist'] )) ? 'X-CURRENT-DUE' : 'X-CURRENT-DTEND'; |
1483 |
if( FALSE !== $durvalue ) { |
1484 |
$rstart->add( $durvalue ); |
1485 |
$component2->setProperty( $propName, $rstart->format( $compEnd->dateFormat )); |
1486 |
} |
1487 |
else
|
1488 |
$component2->deleteProperty( $propName ); |
1489 |
$result[(int)$rstart->format( 'Y' )][(int)$rstart->format( 'm' )][(int)$rstart->format( 'd' )][$compUID] = $component2->copy(); // copy to output |
1490 |
} // end elseif( $rstart >= $fcnStart )
|
1491 |
unset( $rstart ); |
1492 |
} // end foreach( $recurlist as $recurkey => $durvalue )
|
1493 |
unset( $component2, $xRecurrence, $compUID, $workStart, $rstart ); |
1494 |
} // end if( 0 < count( $recurlist ))
|
1495 |
} // end if( TRUE === $any )
|
1496 |
unset( $component ); |
1497 |
} // end foreach ( $this->components as $cix => $component )
|
1498 |
unset( $recurrid, $recurridList, $fcnStart, $fcnEnd, $compStart, $compEnd, $exdatelist, $recurlist ); // clean up |
1499 |
if( 0 >= count( $result )) |
1500 |
return FALSE; |
1501 |
elseif( !$flat ) { |
1502 |
foreach( $result as $y => $yeararr ) { |
1503 |
foreach( $yeararr as $m => $montharr ) { |
1504 |
foreach( $montharr as $d => $dayarr ) { |
1505 |
if( empty( $result[$y][$m][$d] )) |
1506 |
unset( $result[$y][$m][$d] ); |
1507 |
else {
|
1508 |
$result[$y][$m][$d] = array_values( $dayarr ); // skip tricky UID-index |
1509 |
if( 1 < count( $result[$y][$m][$d] )) { |
1510 |
foreach( $result[$y][$m][$d] as & $c ) // sort |
1511 |
iCalUtilityFunctions::_setSortArgs( $c );
|
1512 |
usort( $result[$y][$m][$d], array( 'iCalUtilityFunctions', '_cmpfcn' )); |
1513 |
} |
1514 |
} |
1515 |
} // end foreach( $montharr as $d => $dayarr )
|
1516 |
if( empty( $result[$y][$m] )) |
1517 |
unset( $result[$y][$m] ); |
1518 |
else
|
1519 |
ksort( $result[$y][$m] ); |
1520 |
} // end foreach( $yeararr as $m => $montharr )
|
1521 |
if( empty( $result[$y] )) |
1522 |
unset( $result[$y] ); |
1523 |
else
|
1524 |
ksort( $result[$y] ); |
1525 |
}// end foreach( $result as $y => $yeararr )
|
1526 |
if( empty( $result )) |
1527 |
unset( $result ); |
1528 |
else
|
1529 |
ksort( $result ); |
1530 |
} // end elseif( !$flat )
|
1531 |
if( 0 >= count( $result )) |
1532 |
return FALSE; |
1533 |
return $result; |
1534 |
} |
1535 |
/**
|
1536 |
* select components from calendar on based on specific property value(-s)
|
1537 |
*
|
1538 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1539 |
* @since 2.21.11 - 2015-03-21
|
1540 |
* @param array $selectOptions (string) key => (mixed) value, (key=propertyName)
|
1541 |
* @uses vcalendar::$components
|
1542 |
* @uses calendarComponent::$objName
|
1543 |
* @uses iCalUtilityFunctions::$vComps
|
1544 |
* @uses calendarComponent::getProperty()
|
1545 |
* @uses iCalUtilityFunctions::$otherProps
|
1546 |
* @uses calendarComponent::copy()
|
1547 |
* @uses iCalUtilityFunctions::$mProps1
|
1548 |
* @uses calendarComponent::_getProperties()
|
1549 |
* @return array
|
1550 |
*/
|
1551 |
function selectComponents2( $selectOptions ) { |
1552 |
// $output = array();
|
1553 |
$selectOptions = array_change_key_case( $selectOptions, CASE_UPPER ); |
1554 |
foreach( $this->components as $cix => $component3 ) { |
1555 |
if( !in_array( $component3->objName, iCalUtilityFunctions::$vComps )) |
1556 |
continue;
|
1557 |
$uid = $component3->getProperty( 'UID' ); |
1558 |
foreach( $selectOptions as $propName => $pvalue ) { |
1559 |
if( !in_array( $propName, iCalUtilityFunctions::$otherProps )) |
1560 |
continue;
|
1561 |
if( !is_array( $pvalue )) |
1562 |
$pvalue = array( $pvalue ); |
1563 |
if(( 'UID' == $propName ) && in_array( $uid, $pvalue )) { |
1564 |
$output[$uid][] = $component3->copy(); |
1565 |
continue;
|
1566 |
} |
1567 |
elseif( in_array( $propName, iCalUtilityFunctions::$mProps1 )) { |
1568 |
$propValues = array(); |
1569 |
$component3->_getProperties( $propName, $propValues ); |
1570 |
$propValues = array_keys( $propValues ); |
1571 |
foreach( $pvalue as $theValue ) { |
1572 |
if( in_array( $theValue, $propValues )) { // && !isset( $output[$uid] )) { |
1573 |
$output[$uid][] = $component3->copy(); |
1574 |
break;
|
1575 |
} |
1576 |
} |
1577 |
continue;
|
1578 |
} // end elseif( // multiple occurrence?
|
1579 |
elseif( FALSE === ( $d = $component3->getProperty( $propName ))) // single occurrence |
1580 |
continue;
|
1581 |
if( is_array( $d )) { |
1582 |
foreach( $d as $part ) { |
1583 |
if( in_array( $part, $pvalue ) && !isset( $output[$uid] )) |
1584 |
$output[$uid][] = $component3->copy(); |
1585 |
} |
1586 |
} |
1587 |
elseif(( 'SUMMARY' == $propName ) && !isset( $output[$uid] )) { |
1588 |
foreach( $pvalue as $pval ) { |
1589 |
if( FALSE !== stripos( $d, $pval )) { |
1590 |
$output[$uid][] = $component3->copy(); |
1591 |
break;
|
1592 |
} |
1593 |
} |
1594 |
} |
1595 |
elseif( in_array( $d, $pvalue ) && !isset( $output[$uid] )) |
1596 |
$output[$uid][] = $component3->copy(); |
1597 |
} // end foreach( $selectOptions as $propName => $pvalue ) {
|
1598 |
} // end foreach( $this->components as $cix => $component3 ) {
|
1599 |
if( !empty( $output )) { |
1600 |
ksort( $output ); // uid order |
1601 |
$output2 = array(); |
1602 |
foreach( $output as $uid => $components ) { |
1603 |
foreach( $components as $component ) |
1604 |
$output2[] = $component; |
1605 |
} |
1606 |
$output = $output2; |
1607 |
} |
1608 |
return $output; |
1609 |
} |
1610 |
/**
|
1611 |
* replace calendar component in vcalendar
|
1612 |
*
|
1613 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1614 |
* @since 2.21.11 - 2015-03-21
|
1615 |
* @param object $component calendar component
|
1616 |
* @uses calendarComponent::$objName
|
1617 |
* @uses iCalUtilityFunctions::$vComps
|
1618 |
* @uses vcalendar::setComponent()
|
1619 |
* @uses calendarComponent::getProperty()
|
1620 |
* @return bool
|
1621 |
*/
|
1622 |
function replaceComponent( $component ) { |
1623 |
if( in_array( $component->objName, iCalUtilityFunctions::$vComps )) |
1624 |
return $this->setComponent( $component, $component->getProperty( 'UID' )); |
1625 |
if(( 'vtimezone' != $component->objName ) || ( FALSE === ( $tzid = $component->getProperty( 'TZID' )))) |
1626 |
return FALSE; |
1627 |
foreach( $this->components as $cix => $comp ) { |
1628 |
if( 'vtimezone' != $component->objName ) |
1629 |
continue;
|
1630 |
if( $tzid == $comp->getComponent( 'TZID' )) { |
1631 |
unset( $component->propix, $component->compix ); |
1632 |
$this->components[$cix] = $component; |
1633 |
return TRUE; |
1634 |
} |
1635 |
} |
1636 |
return FALSE; |
1637 |
} |
1638 |
/**
|
1639 |
* add calendar component to calendar
|
1640 |
*
|
1641 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1642 |
* @since 2.21.11 - 2015-03-21
|
1643 |
* @param object $component calendar component
|
1644 |
* @param mixed $arg1 optional, ordno/component type/ component uid
|
1645 |
* @param mixed $arg2 optional, ordno if arg1 = component type
|
1646 |
* @uses calendarComponent::setConfig()
|
1647 |
* @uses vcalendar::getConfig()
|
1648 |
* @uses calendarComponent::$objName
|
1649 |
* @uses calendarComponent::getProperty()
|
1650 |
* @uses vcalendar::$components
|
1651 |
* @uses iCalUtilityFunctions::$mComps
|
1652 |
* @uses calendarComponent::copy()
|
1653 |
* @return bool
|
1654 |
*/
|
1655 |
function setComponent( $component, $arg1=FALSE, $arg2=FALSE ) { |
1656 |
$component->setConfig( $this->getConfig(), FALSE, TRUE ); |
1657 |
if( !in_array( $component->objName, array( 'valarm', 'vtimezone' ))) { |
1658 |
/* make sure dtstamp and uid is set */
|
1659 |
$dummy1 = $component->getProperty( 'dtstamp' ); |
1660 |
$dummy2 = $component->getProperty( 'uid' ); |
1661 |
} |
1662 |
unset( $component->propix, $component->compix ); |
1663 |
if( !$arg1 ) { // plain insert, last in chain |
1664 |
$this->components[] = $component->copy(); |
1665 |
return TRUE; |
1666 |
} |
1667 |
$argType = $index = null; |
1668 |
if ( ctype_digit( (string) $arg1 )) { // index insert/replace |
1669 |
$argType = 'INDEX'; |
1670 |
$index = (int) $arg1 - 1; |
1671 |
} |
1672 |
elseif( in_array( strtolower( $arg1 ), iCalUtilityFunctions::$mComps )) { |
1673 |
$argType = strtolower( $arg1 ); |
1674 |
$index = ( ctype_digit( (string) $arg2 )) ? ((int) $arg2) - 1 : 0; |
1675 |
} |
1676 |
// else if arg1 is set, arg1 must be an UID
|
1677 |
$cix1sC = 0; |
1678 |
foreach ( $this->components as $cix => $component2) { |
1679 |
if( empty( $component2 )) continue; |
1680 |
if(( 'INDEX' == $argType ) && ( $index == $cix )) { // index insert/replace |
1681 |
$this->components[$cix] = $component->copy(); |
1682 |
return TRUE; |
1683 |
} |
1684 |
elseif( $argType == $component2->objName ) { // component Type index insert/replace |
1685 |
if( $index == $cix1sC ) { |
1686 |
$this->components[$cix] = $component->copy(); |
1687 |
return TRUE; |
1688 |
} |
1689 |
$cix1sC++;
|
1690 |
} |
1691 |
elseif( !$argType && ( $arg1 == $component2->getProperty( 'uid' ))) { // UID insert/replace |
1692 |
$this->components[$cix] = $component->copy(); |
1693 |
return TRUE; |
1694 |
} |
1695 |
} |
1696 |
/* arg1=index and not found.. . insert at index .. .*/
|
1697 |
if( 'INDEX' == $argType ) { |
1698 |
$this->components[$index] = $component->copy(); |
1699 |
ksort( $this->components, SORT_NUMERIC ); |
1700 |
} |
1701 |
else /* not found.. . insert last in chain anyway .. .*/ |
1702 |
$this->components[] = $component->copy(); |
1703 |
return TRUE; |
1704 |
} |
1705 |
/**
|
1706 |
* sort iCal compoments
|
1707 |
*
|
1708 |
* ascending sort on properties (if exist) x-current-dtstart, dtstart,
|
1709 |
* x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid if called without arguments,
|
1710 |
* otherwise sorting on specific (argument) property values
|
1711 |
*
|
1712 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1713 |
* @since 2.21.11 - 2015-03-21
|
1714 |
* @param string $sortArg
|
1715 |
* @uses vcalendar::$components
|
1716 |
* @uses iCalUtilityFunctions::$otherProps
|
1717 |
* @uses iCalUtilityFunctions::_setSortArgs()
|
1718 |
* @uses iCalUtilityFunctions::_cmpfcn()
|
1719 |
* @return void
|
1720 |
*/
|
1721 |
function sort( $sortArg=FALSE ) { |
1722 |
if( ! is_array( $this->components ) || ( 2 > count( $this->components ))) |
1723 |
return;
|
1724 |
if( $sortArg ) { |
1725 |
$sortArg = strtoupper( $sortArg ); |
1726 |
if( ! in_array( $sortArg, iCalUtilityFunctions::$otherProps ) && ( 'DTSTAMP' != $sortArg )) |
1727 |
$sortArg = FALSE; |
1728 |
} |
1729 |
foreach( $this->components as & $c ) |
1730 |
iCalUtilityFunctions::_setSortArgs( $c, $sortArg ); |
1731 |
usort( $this->components, array( 'iCalUtilityFunctions', '_cmpfcn' )); |
1732 |
} |
1733 |
/**
|
1734 |
* parse iCal text/file into vcalendar, components, properties and parameters
|
1735 |
*
|
1736 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1737 |
* @since 2.21.12 - 2014-03-10
|
1738 |
* @param mixed $unparsedtext strict rfc2445 formatted, single property string or array of property strings
|
1739 |
* @param resource $context PHP resource context
|
1740 |
* @uses iCalUtilityFunctions::convEolChar()
|
1741 |
* @uses vcalendar::getConfig()
|
1742 |
* @uses vcalendar::$components
|
1743 |
* @uses calendarComponent::copy()
|
1744 |
* @uses vevent::construct()
|
1745 |
* @uses vfreebusy::construct()
|
1746 |
* @uses vjournal::construct()
|
1747 |
* @uses vtodo::construct()
|
1748 |
* @uses vtimezone::construct()
|
1749 |
* @uses vcalendar::$unparsed
|
1750 |
* @uses iCalUtilityFunctions::_splitContent()
|
1751 |
* @uses iCalUtilityFunctions::_strunrep()
|
1752 |
* @uses vcalendar::setProperty()
|
1753 |
* @uses calendarComponent::$unparsed
|
1754 |
* @uses calendarComponent::parse()
|
1755 |
* @return bool FALSE if error occurs during parsing
|
1756 |
*/
|
1757 |
function parse( $unparsedtext=FALSE, $context=null ) { |
1758 |
$nl = $this->getConfig( 'nl' ); |
1759 |
if(( FALSE === $unparsedtext ) || empty( $unparsedtext )) { |
1760 |
/* directory+filename is set previously via setConfig url or directory+filename */
|
1761 |
if( FALSE === ( $file = $this->getConfig( 'url' ))) { |
1762 |
if( FALSE === ( $file = $this->getConfig( 'dirfile' ))) |
1763 |
return FALSE; /* err 1 */ |
1764 |
if( ! is_file( $file )) |
1765 |
return FALSE; /* err 2 */ |
1766 |
if( ! is_readable( $file )) |
1767 |
return FALSE; /* err 3 */ |
1768 |
} |
1769 |
/* READ FILE */
|
1770 |
if( ! empty( $context ) && filter_var( $file, FILTER_VALIDATE_URL ) && |
1771 |
( FALSE === ( $rows = file_get_contents( $file, FALSE, $context )))) |
1772 |
return FALSE; /* err 6 */ |
1773 |
elseif( FALSE === ( $rows = file_get_contents( $file ))) |
1774 |
return FALSE; /* err 5 */ |
1775 |
} // end if(( FALSE === $unparsedtext ) || empty( $unparsedtext ))
|
1776 |
elseif( is_array( $unparsedtext )) |
1777 |
$rows = implode( '\n'.$nl, $unparsedtext ); |
1778 |
else
|
1779 |
$rows = & $unparsedtext; |
1780 |
/* fix line folding */
|
1781 |
$rows = iCalUtilityFunctions::convEolChar( $rows, $nl ); |
1782 |
/* skip leading (empty/invalid) lines (and remove leading BOM chars etc) */
|
1783 |
foreach( $rows as $lix => $line ) { |
1784 |
if( FALSE !== stripos( $line, 'BEGIN:VCALENDAR' )) { |
1785 |
$rows[$lix] = 'BEGIN:VCALENDAR'; |
1786 |
break;
|
1787 |
} |
1788 |
unset( $rows[$lix] ); |
1789 |
} |
1790 |
$rcnt = count( $rows ); |
1791 |
if( 3 > $rcnt ) /* err 10 */ |
1792 |
return FALSE; |
1793 |
/* skip trailing empty lines and ensure an end row */
|
1794 |
$lix = array_keys( $rows ); |
1795 |
$lix = end( $lix ); |
1796 |
while( 3 < $lix ) { |
1797 |
$tst = trim( $rows[$lix] ); |
1798 |
if(( '\n' == $tst ) || empty( $tst )) { |
1799 |
unset( $rows[$lix] ); |
1800 |
$lix--;
|
1801 |
continue;
|
1802 |
} |
1803 |
if( FALSE === stripos( $rows[$lix], 'END:VCALENDAR' )) |
1804 |
$rows[] = 'END:VCALENDAR'; |
1805 |
else
|
1806 |
$rows[$lix] = 'END:VCALENDAR'; |
1807 |
break;
|
1808 |
} |
1809 |
$comp = & $this; |
1810 |
$calsync = $compsync = 0; |
1811 |
/* identify components and update unparsed data within component */
|
1812 |
$config = $this->getConfig(); |
1813 |
$endtxt = array( 'END:VE', 'END:VF', 'END:VJ', 'END:VT' ); |
1814 |
foreach( $rows as $lix => $line ) { |
1815 |
if( 'BEGIN:VCALENDAR' == strtoupper( substr( $line, 0, 15 ))) { |
1816 |
$calsync++;
|
1817 |
continue;
|
1818 |
} |
1819 |
elseif( 'END:VCALENDAR' == strtoupper( substr( $line, 0, 13 ))) { |
1820 |
if( 0 < $compsync ) |
1821 |
$this->components[] = $comp->copy(); |
1822 |
$compsync--;
|
1823 |
$calsync--;
|
1824 |
break;
|
1825 |
} |
1826 |
elseif( 1 != $calsync ) |
1827 |
return FALSE; /* err 20 */ |
1828 |
elseif( in_array( strtoupper( substr( $line, 0, 6 )), $endtxt )) { |
1829 |
$this->components[] = $comp->copy(); |
1830 |
$compsync--;
|
1831 |
continue;
|
1832 |
} |
1833 |
if( 'BEGIN:VEVENT' == strtoupper( substr( $line, 0, 12 ))) { |
1834 |
$comp = new vevent( $config ); |
1835 |
$compsync++;
|
1836 |
} |
1837 |
elseif( 'BEGIN:VFREEBUSY' == strtoupper( substr( $line, 0, 15 ))) { |
1838 |
$comp = new vfreebusy( $config ); |
1839 |
$compsync++;
|
1840 |
} |
1841 |
elseif( 'BEGIN:VJOURNAL' == strtoupper( substr( $line, 0, 14 ))) { |
1842 |
$comp = new vjournal( $config ); |
1843 |
$compsync++;
|
1844 |
} |
1845 |
elseif( 'BEGIN:VTODO' == strtoupper( substr( $line, 0, 11 ))) { |
1846 |
$comp = new vtodo( $config ); |
1847 |
$compsync++;
|
1848 |
} |
1849 |
elseif( 'BEGIN:VTIMEZONE' == strtoupper( substr( $line, 0, 15 ))) { |
1850 |
$comp = new vtimezone( $config ); |
1851 |
$compsync++;
|
1852 |
} |
1853 |
else { /* update component with unparsed data */ |
1854 |
$comp->unparsed[] = $line; |
1855 |
} |
1856 |
} // end foreach( $rows as $line )
|
1857 |
unset( $config, $endtxt ); |
1858 |
/* parse data for calendar (this) object */
|
1859 |
if( isset( $this->unparsed ) && is_array( $this->unparsed ) && ( 0 < count( $this->unparsed ))) { |
1860 |
/* concatenate property values spread over several lines */
|
1861 |
$propnames = array( 'calscale','method','prodid','version','x-' ); |
1862 |
$proprows = array(); |
1863 |
for( $i = 0; $i < count( $this->unparsed ); $i++ ) { // concatenate lines |
1864 |
$line = rtrim( $this->unparsed[$i], $nl ); |
1865 |
while( isset( $this->unparsed[$i+1] ) && !empty( $this->unparsed[$i+1] ) && ( ' ' == $this->unparsed[$i+1]{0} )) |
1866 |
$line .= rtrim( substr( $this->unparsed[++$i], 1 ), $nl ); |
1867 |
$proprows[] = $line; |
1868 |
} |
1869 |
foreach( $proprows as $line ) { |
1870 |
if( '\n' == substr( $line, -2 )) |
1871 |
$line = substr( $line, 0, -2 ); |
1872 |
/* get property name */
|
1873 |
$propname = ''; |
1874 |
$cix = 0; |
1875 |
while( FALSE !== ( $char = substr( $line, $cix, 1 ))) { |
1876 |
if( in_array( $char, array( ':', ';' ))) |
1877 |
break;
|
1878 |
else
|
1879 |
$propname .= $char; |
1880 |
$cix++;
|
1881 |
} |
1882 |
/* skip non standard property names */
|
1883 |
if(( 'x-' != strtolower( substr( $propname, 0, 2 ))) && !in_array( strtolower( $propname ), $propnames )) |
1884 |
continue;
|
1885 |
/* ignore version/prodid properties */
|
1886 |
if( in_array( strtolower( $propname ), array( 'version', 'prodid' ))) |
1887 |
continue;
|
1888 |
/* rest of the line is opt.params and value */
|
1889 |
$line = substr( $line, $cix); |
1890 |
/* separate attributes from value */
|
1891 |
iCalUtilityFunctions::_splitContent( $line, $propAttr ); |
1892 |
/* update Property */
|
1893 |
if( FALSE !== strpos( $line, ',' )) { |
1894 |
$content = array( 0 => '' ); |
1895 |
$cix = $lix = 0; |
1896 |
while( FALSE !== substr( $line, $lix, 1 )) { |
1897 |
if(( 0 < $lix ) && ( ',' == $line[$lix] ) && ( "\\" != $line[( $lix - 1 )])) { |
1898 |
$cix++;
|
1899 |
$content[$cix] = ''; |
1900 |
} |
1901 |
else
|
1902 |
$content[$cix] .= $line[$lix]; |
1903 |
$lix++;
|
1904 |
} |
1905 |
if( 1 < count( $content )) { |
1906 |
foreach( $content as $cix => $contentPart ) |
1907 |
$content[$cix] = iCalUtilityFunctions::_strunrep( $contentPart ); |
1908 |
$this->setProperty( $propname, $content, $propAttr ); |
1909 |
continue;
|
1910 |
} |
1911 |
else
|
1912 |
$line = reset( $content ); |
1913 |
$line = iCalUtilityFunctions::_strunrep( $line ); |
1914 |
} |
1915 |
$this->setProperty( $propname, rtrim( $line, "\x00..\x1F" ), $propAttr ); |
1916 |
} // end - foreach( $this->unparsed.. .
|
1917 |
} // end - if( is_array( $this->unparsed.. .
|
1918 |
unset( $unparsedtext, $rows, $this->unparsed, $proprows ); |
1919 |
/* parse Components */
|
1920 |
if( is_array( $this->components ) && ( 0 < count( $this->components ))) { |
1921 |
$ckeys = array_keys( $this->components ); |
1922 |
foreach( $ckeys as $ckey ) { |
1923 |
if( !empty( $this->components[$ckey] ) && !empty( $this->components[$ckey]->unparsed )) { |
1924 |
$this->components[$ckey]->parse(); |
1925 |
} |
1926 |
} |
1927 |
} |
1928 |
else
|
1929 |
return FALSE; /* err 91 or something.. . */ |
1930 |
return TRUE; |
1931 |
} |
1932 |
/*********************************************************************************/
|
1933 |
/**
|
1934 |
* creates formatted output for calendar object instance
|
1935 |
*
|
1936 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
1937 |
* @since 2.21.07 - 2015-03-31
|
1938 |
* @uses vcalendar::$format
|
1939 |
* @uses vcalendar::$nl
|
1940 |
* @uses vcalendar::createVersion()
|
1941 |
* @uses vcalendar::createProdid()
|
1942 |
* @uses vcalendar::createCalscale()
|
1943 |
* @uses vcalendar::createMethod()
|
1944 |
* @uses vcalendar::createXprop()
|
1945 |
* @uses vcalendar::$components
|
1946 |
* @uses calendarComponent::setConfig()
|
1947 |
* @uses vcalendar::getConfig()
|
1948 |
* @uses calendarComponent::createComponent()
|
1949 |
* @uses vcalendar::$xcaldecl
|
1950 |
* @return string
|
1951 |
*/
|
1952 |
function createCalendar() { |
1953 |
parent::_createFormat();
|
1954 |
$calendarInit = $calendarxCaldecl = $calendarStart = $calendar = ''; |
1955 |
switch( $this->format ) { |
1956 |
case 'xcal': |
1957 |
$calendarInit = '<?xml version="1.0" encoding="UTF-8"?>'.$this->nl. |
1958 |
'<!DOCTYPE vcalendar PUBLIC "-//IETF//DTD XCAL/iCalendar XML//EN"'.$this->nl. |
1959 |
'"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"';
|
1960 |
$calendarStart = '>'.$this->nl.'<vcalendar'; |
1961 |
break;
|
1962 |
default:
|
1963 |
$calendarStart = 'BEGIN:VCALENDAR'.$this->nl; |
1964 |
break;
|
1965 |
} |
1966 |
$calendarStart .= $this->createVersion(); |
1967 |
$calendarStart .= $this->createProdid(); |
1968 |
$calendarStart .= $this->createCalscale(); |
1969 |
$calendarStart .= $this->createMethod(); |
1970 |
if( 'xcal' == $this->format ) |
1971 |
$calendarStart .= '>'.$this->nl; |
1972 |
$calendar .= $this->createXprop(); |
1973 |
foreach( $this->components as $component ) { |
1974 |
if( empty( $component )) continue; |
1975 |
$component->setConfig( $this->getConfig(), FALSE, TRUE ); |
1976 |
$calendar .= $component->createComponent( $this->xcaldecl ); |
1977 |
} |
1978 |
if(( 'xcal' == $this->format ) && ( 0 < count( $this->xcaldecl ))) { // xCal only |
1979 |
$calendarInit .= ' ['; |
1980 |
$old_xcaldecl = array(); |
1981 |
foreach( $this->xcaldecl as $declix => $declPart ) { |
1982 |
if(( 0 < count( $old_xcaldecl)) && |
1983 |
isset( $declPart['uri'] ) && isset( $declPart['external'] ) && |
1984 |
isset( $old_xcaldecl['uri'] ) && isset( $old_xcaldecl['external'] ) && |
1985 |
( in_array( $declPart['uri'], $old_xcaldecl['uri'] )) && |
1986 |
( in_array( $declPart['external'], $old_xcaldecl['external'] ))) |
1987 |
continue; // no duplicate uri and ext. references |
1988 |
if(( 0 < count( $old_xcaldecl)) && |
1989 |
!isset( $declPart['uri'] ) && !isset( $declPart['uri'] ) && |
1990 |
isset( $declPart['ref'] ) && isset( $old_xcaldecl['ref'] ) && |
1991 |
( in_array( $declPart['ref'], $old_xcaldecl['ref'] ))) |
1992 |
continue; // no duplicate element declarations |
1993 |
$calendarxCaldecl .= $this->nl.'<!'; |
1994 |
foreach( $declPart as $declKey => $declValue ) { |
1995 |
switch( $declKey ) { // index |
1996 |
case 'xmldecl': // no 1 |
1997 |
$calendarxCaldecl .= $declValue.' '; |
1998 |
break;
|
1999 |
case 'uri': // no 2 |
2000 |
$calendarxCaldecl .= $declValue.' '; |
2001 |
$old_xcaldecl['uri'][] = $declValue; |
2002 |
break;
|
2003 |
case 'ref': // no 3 |
2004 |
$calendarxCaldecl .= $declValue.' '; |
2005 |
$old_xcaldecl['ref'][] = $declValue; |
2006 |
break;
|
2007 |
case 'external': // no 4 |
2008 |
$calendarxCaldecl .= '"'.$declValue.'" '; |
2009 |
$old_xcaldecl['external'][] = $declValue; |
2010 |
break;
|
2011 |
case 'type': // no 5 |
2012 |
$calendarxCaldecl .= $declValue.' '; |
2013 |
break;
|
2014 |
case 'type2': // no 6 |
2015 |
$calendarxCaldecl .= $declValue; |
2016 |
break;
|
2017 |
} |
2018 |
} |
2019 |
$calendarxCaldecl .= '>'; |
2020 |
} |
2021 |
$calendarxCaldecl .= $this->nl.']'; |
2022 |
} // end if(( 'xcal'...
|
2023 |
switch( $this->format ) { |
2024 |
case 'xcal': |
2025 |
$calendar .= '</vcalendar>'.$this->nl; |
2026 |
break;
|
2027 |
default:
|
2028 |
$calendar .= 'END:VCALENDAR'.$this->nl; |
2029 |
break;
|
2030 |
} |
2031 |
return $calendarInit.$calendarxCaldecl.$calendarStart.$calendar; |
2032 |
} |
2033 |
/**
|
2034 |
* a HTTP redirect header is sent with created, updated and/or parsed calendar
|
2035 |
*
|
2036 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2037 |
* @since 2.21.5 - 2015-03-29
|
2038 |
* @param bool $utf8Encode
|
2039 |
* @param bool $gzip
|
2040 |
* @param bool $cdType TRUE : Content-Disposition: attachment... (default), FALSE : ...inline...
|
2041 |
* @uses vcalendar::getConfig()
|
2042 |
* @uses vcalendar::createCalendar()
|
2043 |
* @uses vcalendar::$headers
|
2044 |
* @uses vcalendar::$format
|
2045 |
* @return bool TRUE on success, FALSE on error
|
2046 |
*/
|
2047 |
function returnCalendar( $utf8Encode=FALSE, $gzip=FALSE, $cdType=TRUE ) { |
2048 |
$filename = $this->getConfig( 'filename' ); |
2049 |
$output = $this->createCalendar(); |
2050 |
if( $utf8Encode ) |
2051 |
$output = utf8_encode( $output ); |
2052 |
$fsize = null; |
2053 |
if( $gzip ) { |
2054 |
$output = gzencode( $output, 9 ); |
2055 |
$fsize = strlen( $output ); |
2056 |
header( self::$headers[0] ); |
2057 |
header( self::$headers[1] ); |
2058 |
} |
2059 |
else {
|
2060 |
if( FALSE !== ( $temp = tempnam( sys_get_temp_dir(), 'iCr' ))) { |
2061 |
if( FALSE !== file_put_contents( $temp, $output )) |
2062 |
$fsize = @filesize( $temp ); |
2063 |
unlink( $temp ); |
2064 |
} |
2065 |
} |
2066 |
if( ! empty( $fsize )) |
2067 |
header( sprintf( self::$headers[2], $fsize )); |
2068 |
if( 'xcal' == $this->format ) |
2069 |
header( self::$headers[3] ); |
2070 |
else
|
2071 |
header( self::$headers[4] ); |
2072 |
$cdType = ( $cdType ) ? 5 : 6; |
2073 |
header( sprintf( self::$headers[$cdType], $filename )); |
2074 |
header( self::$headers[7] ); |
2075 |
echo $output; |
2076 |
return TRUE; |
2077 |
} |
2078 |
/**
|
2079 |
* save content in a file
|
2080 |
*
|
2081 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2082 |
* @since 2.21.5 - 2015-03-29
|
2083 |
* @uses vcalendar::createComponent()
|
2084 |
* @uses vcalendar::getConfig()
|
2085 |
* @return bool TRUE on success, FALSE on error
|
2086 |
*/
|
2087 |
function saveCalendar() { |
2088 |
$output = $this->createCalendar(); |
2089 |
if( FALSE === ( $dirfile = $this->getConfig( 'url' ))) |
2090 |
$dirfile = $this->getConfig( 'dirfile' ); |
2091 |
return ( FALSE === file_put_contents( $dirfile, $output, LOCK_EX )) ? FALSE : TRUE; |
2092 |
} |
2093 |
/**
|
2094 |
* if recent version of calendar file exists (default one hour), an HTTP redirect header is sent
|
2095 |
* else FALSE is returned
|
2096 |
*
|
2097 |
* @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
|
2098 |
* @since 2.21.5 - 2015-03-29
|
2099 |
* @param int $timeout default 3600 sec
|
2100 |
* @param bool $cdType TRUE : Content-Disposition: attachment... (default), FALSE : ...inline...
|
2101 |
* @uses vcalendar::getConfig()
|
2102 |
* @uses vcalendar::$headers
|
2103 |
* @uses vcalendar::$format
|
2104 |
* @return bool TRUE on success, FALSE on error
|
2105 |
*/
|
2106 |
function useCachedCalendar( $timeout=3600, $cdType=TRUE ) { |
2107 |
if( FALSE === ( $dirfile = $this->getConfig( 'url' ))) |
2108 |
$dirfile = $this->getConfig( 'dirfile' ); |
2109 |
if( ! is_file( $dirfile ) || ! is_readable( $dirfile )) |
2110 |
return FALSE; |
2111 |
if( time() - filemtime( $dirfile ) > $timeout ) |
2112 |
return FALSE; |
2113 |
clearstatcache();
|
2114 |
$dirfile = $this->getConfig( 'dirfile' ); |
2115 |
$fsize = @filesize( $dirfile ); |
2116 |
$filename = $this->getConfig( 'filename' ); |
2117 |
if( 'xcal' == $this->format ) |
2118 |
header( self::$headers[3] ); |
2119 |
else
|
2120 |
header( self::$headers[4] ); |
2121 |
if( ! empty( $fsize )) |
2122 |
header( sprintf( self::$headers[2], $fsize )); |
2123 |
$cdType = ( $cdType ) ? 5 : 6; |
2124 |
header( sprintf( self::$headers[$cdType], $filename )); |
2125 |
header( self::$headers[7] ); |
2126 |
if( FALSE === ( $fp = @fopen( $dirfile, 'r' ))) |
2127 |
return FALSE; |
2128 |
fpassthru( $fp ); |
2129 |
fclose( $fp ); |
2130 |
return TRUE; |
2131 |
} |
2132 |
} |