ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilICalParser.php
Go to the documentation of this file.
1<?php
2/*
3 +-----------------------------------------------------------------------------+
4 | ILIAS open source |
5 +-----------------------------------------------------------------------------+
6 | Copyright (c) 1998-2006 ILIAS open source, University of Cologne |
7 | |
8 | This program is free software; you can redistribute it and/or |
9 | modify it under the terms of the GNU General Public License |
10 | as published by the Free Software Foundation; either version 2 |
11 | of the License, or (at your option) any later version. |
12 | |
13 | This program is distributed in the hope that it will be useful, |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | GNU General Public License for more details. |
17 | |
18 | You should have received a copy of the GNU General Public License |
19 | along with this program; if not, write to the Free Software |
20 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
21 +-----------------------------------------------------------------------------+
22*/
23
24include_once('./Services/Calendar/classes/iCal/class.ilICalUtils.php');
25include_once('./Services/Calendar/classes/class.ilDateTime.php');
26include_once('./Services/Calendar/classes/class.ilCalendarEntry.php');
27include_once('./Services/Calendar/classes/class.ilTimeZone.php');
28include_once('./Services/Calendar/classes/class.ilTimeZoneException.php');
29
30include_once('./Services/Calendar/classes/iCal/class.ilICalComponent.php');
31include_once('./Services/Calendar/classes/iCal/class.ilICalProperty.php');
32include_once('./Services/Calendar/classes/iCal/class.ilICalParameter.php');
33include_once('./Services/Calendar/classes/iCal/class.ilICalValue.php');
34
35include_once './Services/Calendar/exceptions/class.ilICalParserException.php';
36
46{
47 const INPUT_STRING = 1;
48 const INPUT_FILE = 2;
49
53 protected $log = null;
54
55 protected $category = null;
56
57 protected $ical = '';
58 protected $file = '';
59 protected $default_timezone = null;
60
61 protected $container = array();
62
72 public function __construct($a_ical, $a_type)
73 {
74 if ($a_type == self::INPUT_STRING) {
75 $this->ical = $a_ical;
76 } elseif ($a_type == self::INPUT_FILE) {
77 $this->file = $a_ical;
78 $this->ical = file_get_contents($a_ical);
79
80 if (!strlen($this->ical)) {
81 throw new ilICalParserException($GLOBALS['DIC']['cal_err_no_input']);
82 }
83 #$GLOBALS['DIC']['ilLog']->write(__METHOD__.': Ical content: '. $this->ical);
84 }
85 $this->log = $GLOBALS['DIC']->logger()->cal();
86 }
87
95 public function setCategoryId($a_id)
96 {
97 include_once('./Services/Calendar/classes/class.ilCalendarCategory.php');
98 $this->category = new ilCalendarCategory($a_id);
99 }
100
107 public function parse()
108 {
109 $this->default_timezone = ilTimeZone::_getInstance();
110
111 $lines = $this->tokenize($this->ical, ilICalUtils::ICAL_EOL);
112
113 if (count($lines) == 1) {
114 $lines = $this->tokenize($this->ical, ilICalUtils::ICAL_EOL_FB);
115 }
116
117 for ($i = 0; $i < count($lines); $i++) {
118 $line = $lines[$i];
119
120 // Check for next multilines (they start with a space)
121 $offset = 1;
122 while (isset($lines[$i + $offset]) and
123 (strpos($lines[$i + $offset], ilICalUtils::ICAL_SPACE) === 0) or
124 (strpos($lines[$i + $offset], ilICalUtils::ICAL_TAB) === 0)) {
125 $lines[$i + $offset] = str_replace(ilICalUtils::ICAL_EOL, '', $lines[$i + $offset]);
126 $line = $line . substr($lines[$i + $offset], 1);
127 $offset++;
128 }
129 $i += ($offset - 1);
130
131 // Parse this line
132 $this->parseLine($line);
133 }
134 }
135
141 protected function getContainer()
142 {
143 return $this->container[count($this->container) - 1];
144 }
145
152 protected function setContainer($a_container)
153 {
154 $this->container = array($a_container);
155 }
156
162 protected function dropContainer()
163 {
164 return array_pop($this->container);
165 }
166
173 protected function pushContainer($a_container)
174 {
175 $this->container[] = $a_container;
176 }
177
178
184 protected function parseLine($line)
185 {
186 switch (trim($line)) {
187 case 'BEGIN:VCALENDAR':
188 $this->log->debug('BEGIN VCALENDAR');
189 $this->setContainer(new ilICalComponent('VCALENDAR'));
190 break;
191
192 case 'END:VCALENDAR':
193 $this->log->debug('END VCALENDAR');
194 break;
195
196 case 'BEGIN:VEVENT':
197 $this->log->debug('BEGIN VEVENT');
198 $this->pushContainer(new ilICalComponent('VEVENT'));
199 break;
200
201 case 'END:VEVENT':
202 $this->log->debug('END VEVENT');
203
204 $this->writeEvent();
205
206 $this->dropContainer();
207 break;
208
209 case 'BEGIN:VTIMEZONE':
210 $this->log->debug('BEGIN VTIMEZONE');
211 $container = new ilICalComponent('VTIMEZONE');
213 break;
214
215 case 'END:VTIMEZONE':
216 $this->log->debug('END VTIMEZONE');
217
218 if ($tzid = $this->getContainer()->getItemsByName('TZID')) {
219 $this->default_timezone = $this->getTZ($tzid[0]->getValue());
220 }
221 $this->dropContainer();
222 break;
223
224 default:
225 if (strpos(trim($line), 'BEGIN') === 0) {
226 $this->log->info('Do not handling line:' . $line);
227 break;
228 }
229 if (strpos(trim($line), 'X-WR-TIMEZONE') === 0) {
230 list($param, $value) = $this->splitLine($line);
231 $this->default_timezone = $this->getTZ($value);
232 } else {
233 list($params, $values) = $this->splitLine($line);
234 $this->storeItems($params, $values);
235 }
236 break;
237 }
238 }
239
245 protected function storeItems($a_param_part, $a_value_part)
246 {
247 // Check for a semicolon in param part and split it.
248
249 $items = array();
250 if ($splitted_param = explode(';', $a_param_part)) {
251 $counter = 0;
252 foreach ($splitted_param as $param) {
253 if (!$counter) {
254 $items[$counter]['param'] = $param;
255 $items[$counter]['value'] = $a_value_part;
256 } else {
257 // Split by '='
258 if ($splitted_param_values = explode('=', $param)) {
259 $items[$counter]['param'] = $splitted_param_values[0];
260 $items[$counter]['value'] = $splitted_param_values[1];
261 }
262 }
263 ++$counter;
264 }
265 }
266
267 // Split value part
268 $substituted_values = str_replace('\;', '', $a_value_part);
269
270 $values = array();
271 if ($splitted_values = explode(';', $substituted_values)) {
272 $counter = 0;
273 foreach ($splitted_values as $value) {
274 // Split by '='
275 if ($splitted_value_values = explode('=', $value)) {
276 $values[$counter]['param'] = $splitted_value_values[0];
277 $values[$counter]['value'] = $splitted_value_values[1];
278 }
279 ++$counter;
280 }
281 }
282
283 // Return if there are no values
284 if (!count($items)) {
285 $this->log->write(__METHOD__ . ': Cannot parse parameter: ' . $a_param_part . ', value: ' . $a_value_part);
286 return false;
287 }
288
289
290 $counter = 0;
291 foreach ($items as $item) {
292 if (!$counter) {
293 // First is ical-Parameter
294 $parameter = new ilICalProperty($item['param'], $item['value']);
295
296 if (!$this->getContainer() instanceof ilICalItem) {
297 continue;
298 }
299
300 $this->getContainer()->addItem($parameter);
301 $this->pushContainer($parameter);
302
303 if (count($values) > 1) {
304 foreach ($values as $value) {
305 $value = new ilICalValue($value['param'], $value['value']);
306 $this->getContainer()->addItem($value);
307 }
308 }
309 } else {
310 $value = new ilICalParameter($item['param'], $item['value']);
311 $this->getContainer()->addItem($value);
312 }
313 ++$counter;
314 }
315 $this->dropContainer();
316 }
317
318
325 protected function splitLine($a_line)
326 {
327 $matches = array();
328
329 if (preg_match('/([^:]+):(.*)/', $a_line, $matches)) {
330 return array($matches[1],$matches[2]);
331 } else {
332 $this->log->write(__METHOD__ . ': Found invalid parameter: ' . $a_line);
333 }
334
335 return array('','');
336 }
337
343 protected function tokenize($a_string, $a_tokenizer)
344 {
345 return explode($a_tokenizer, $a_string);
346 }
347
353 protected function getTZ($a_timezone)
354 {
355 $parts = explode('/', $a_timezone);
356 $tz = array_pop($parts);
357 $continent = array_pop($parts);
358
359 if (isset($continent) and $continent) {
360 $timezone = $continent . '/' . $tz;
361 } else {
362 $timezone = $a_timezone;
363 }
364
365 try {
366 if ($this->default_timezone->getIdentifier() == $timezone) {
368 } else {
369 $this->log->write(__METHOD__ . ': Found new timezone: ' . $timezone);
370 return ilTimeZone::_getInstance(trim($timezone));
371 }
372 } catch (ilTimeZoneException $e) {
373 $this->log->write(__METHOD__ . ': Found invalid timezone: ' . $timezone);
375 }
376 }
377
383 protected function switchTZ(ilTimeZone $timezone)
384 {
385 try {
386 $timezone->switchTZ();
387 } catch (ilTimeZoneException $e) {
388 $this->log->write(__METHOD__ . ': Found invalid timezone: ' . $timezone);
389 return false;
390 }
391 }
392
398 protected function restoreTZ()
399 {
400 $this->default_timezone->restoreTZ();
401 }
402
408 protected function writeEvent()
409 {
410 $entry = new ilCalendarEntry();
411
412 // Search for summary
413 foreach ($this->getContainer()->getItemsByName('SUMMARY', false) as $item) {
414 if (is_a($item, 'ilICalProperty')) {
415 $entry->setTitle($this->purgeString($item->getValue()));
416 break;
417 }
418 }
419 // Search description
420 foreach ($this->getContainer()->getItemsByName('DESCRIPTION', false) as $item) {
421 if (is_a($item, 'ilICalProperty')) {
422 $entry->setDescription($this->purgeString($item->getValue()));
423 break;
424 }
425 }
426
427 // Search location
428 foreach ($this->getContainer()->getItemsByName('LOCATION', false) as $item) {
429 if (is_a($item, 'ilICalProperty')) {
430 $entry->setLocation($this->purgeString($item->getValue()));
431 break;
432 }
433 }
434
435 foreach ($this->getContainer()->getItemsByName('DTSTART') as $start) {
436 $fullday = false;
437 foreach ($start->getItemsByName('VALUE') as $type) {
438 if ($type->getValue() == 'DATE') {
439 $fullday = true;
440 }
441 }
442 $start_tz = $this->default_timezone;
443 foreach ($start->getItemsByName('TZID') as $param) {
444 $start_tz = $this->getTZ($param->getValue());
445 }
446 if ($fullday) {
447 $start = new ilDate(
448 $start->getValue(),
450 );
451 } else {
452 $start = new ilDateTime(
453 $start->getValue(),
455 $start_tz->getIdentifier()
456 );
457 }
458 $entry->setStart($start);
459 $entry->setFullday($fullday);
460 }
461
462 foreach ($this->getContainer()->getItemsByName('DTEND') as $end) {
463 $fullday = false;
464 foreach ($end->getItemsByName('VALUE') as $type) {
465 if ($type->getValue() == 'DATE') {
466 $fullday = true;
467 }
468 }
469 $end_tz = $this->default_timezone;
470 foreach ($end->getItemsByName('TZID') as $param) {
471 $end_tz = $this->getTZ($param->getValue());
472 }
473 if ($fullday) {
474 $end = new ilDate(
475 $end->getValue(),
477 );
478 $end->increment(IL_CAL_DAY, -1);
479 } else {
480 $end = new ilDateTime(
481 $end->getValue(),
483 $end_tz->getIdentifier()
484 );
485 }
486 $entry->setEnd($end);
487 $entry->setFullday($fullday);
488 }
489
490 if (!$entry->getStart() instanceof ilDateTime) {
491 $this->log->warning('Cannot find start date. Event ignored.');
492 return false;
493 }
494
495 // check if end date is given otherwise replace with start
496 if (
497 !$entry->getEnd() instanceof ilDateTime &&
498 $entry->getStart() instanceof ilDateTime
499 ) {
500 $entry->setEnd($entry->getStart());
501 }
502
503
504 // save calendar event
505 if ($this->category->getLocationType() == ilCalendarCategory::LTYPE_REMOTE) {
506 $entry->setAutoGenerated(true);
507 }
508 $entry->save();
509
510 include_once('./Services/Calendar/classes/class.ilCalendarCategoryAssignments.php');
511 $ass = new ilCalendarCategoryAssignments($entry->getEntryId());
512 $ass->addAssignment($this->category->getCategoryID());
513
514
515 // Recurrences
516 foreach ($this->getContainer()->getItemsByName('RRULE') as $recurrence) {
517 #var_dump("<pre>",$recurrence,"</pre>");
518
519
520 include_once('./Services/Calendar/classes/class.ilCalendarRecurrence.php');
521 $rec = new ilCalendarRecurrence();
522 $rec->setEntryId($entry->getEntryId());
523
524 foreach ($recurrence->getItemsByName('FREQ') as $freq) {
525 switch ($freq->getValue()) {
526 case 'DAILY':
527 case 'WEEKLY':
528 case 'MONTHLY':
529 case 'YEARLY':
530 $rec->setFrequenceType((string) $freq->getValue());
531 break;
532
533 default:
534 $this->log->write(__METHOD__ . ': Cannot handle recurring event of type: ' . $freq->getValue());
535 break 3;
536 }
537 }
538
539 foreach ($recurrence->getItemsByName('COUNT') as $value) {
540 $rec->setFrequenceUntilCount((string) $value->getValue());
541 break;
542 }
543 foreach ($recurrence->getItemsByName('UNTIL') as $until) {
544 $rec->setFrequenceUntilDate(new ilDate($until->getValue(), IL_CAL_DATE));
545 break;
546 }
547 foreach ($recurrence->getItemsByName('INTERVAL') as $value) {
548 $rec->setInterval((string) $value->getValue());
549 break;
550 }
551 foreach ($recurrence->getItemsByName('BYDAY') as $value) {
552 $rec->setBYDAY((string) $value->getValue());
553 break;
554 }
555 foreach ($recurrence->getItemsByName('BYWEEKNO') as $value) {
556 $rec->setBYWEEKNO((string) $value->getValue());
557 break;
558 }
559 foreach ($recurrence->getItemsByName('BYMONTH') as $value) {
560 $rec->setBYMONTH((string) $value->getValue());
561 break;
562 }
563 foreach ($recurrence->getItemsByName('BYMONTHDAY') as $value) {
564 $rec->setBYMONTHDAY((string) $value->getValue());
565 break;
566 }
567 foreach ($recurrence->getItemsByName('BYYEARDAY') as $value) {
568 $rec->setBYYEARDAY((string) $value->getValue());
569 break;
570 }
571 foreach ($recurrence->getItemsByName('BYSETPOS') as $value) {
572 $rec->setBYSETPOS((string) $value->getValue());
573 break;
574 }
575 foreach ($recurrence->getItemsByName('WKST') as $value) {
576 $rec->setWeekstart((string) $value->getValue());
577 break;
578 }
579 $rec->save();
580 }
581 }
582
588 protected function purgeString($a_string)
589 {
590 $a_string = str_replace("\;", ";", $a_string);
591 $a_string = str_replace("\,", ",", $a_string);
592 $a_string = str_replace("\:", ":", $a_string);
593 return ilUtil::stripSlashes($a_string);
594 }
595}
An exception for terminatinating execution or to throw for unit testing.
const IL_CAL_DATE
const IL_CAL_DATETIME
const IL_CAL_DAY
Stores calendar categories.
Model for a calendar entry.
@classDescription Date and time handling
Class for single dates.
Represents a ical component.
Abstract base class for all ical items (Component, Parameter and Value)
This class represents a ical parameter E.g VALUE=DATETIME.
getContainer()
get container
parseLine($line)
parse a line
storeItems($a_param_part, $a_value_part)
store items
writeEvent()
write a new event
switchTZ(ilTimeZone $timezone)
Switch timezone.
splitLine($a_line)
parse parameters
setContainer($a_container)
set container
pushContainer($a_container)
push container
parse()
Parse input.
purgeString($a_string)
purge string
__construct($a_ical, $a_type)
Constructor.
setCategoryId($a_id)
set category id
restoreTZ()
restore time
tokenize($a_string, $a_tokenizer)
tokenize string
getTZ($a_timezone)
get timezone
Represents a ical property.
Used for storage og multiple values E.g RRULE:FREQ=WEEKLY;COUNT=20;INTERVAL=2;BYDAY=TU.
Class for TimeZone exceptions.
This class offers methods for timezone handling.
static _getInstance($a_tz='')
get instance by timezone
switchTZ()
Switch timezone to given timezone.
static stripSlashes($a_str, $a_strip_html=true, $a_allow="")
strip slashes if magic qoutes is enabled
$i
Definition: disco.tpl.php:19
$GLOBALS['JPEG_Segment_Names']
Global Variable: XMP_tag_captions.
$type
$values
$start
Definition: bench.php:8
$a_type
Definition: workflow.php:92