ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
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 
24 include_once('./Services/Calendar/classes/iCal/class.ilICalUtils.php');
25 include_once('./Services/Calendar/classes/class.ilDateTime.php');
26 include_once('./Services/Calendar/classes/class.ilCalendarEntry.php');
27 include_once('./Services/Calendar/classes/class.ilTimeZone.php');
28 include_once('./Services/Calendar/classes/class.ilTimeZoneException.php');
29 
30 include_once('./Services/Calendar/classes/iCal/class.ilICalComponent.php');
31 include_once('./Services/Calendar/classes/iCal/class.ilICalProperty.php');
32 include_once('./Services/Calendar/classes/iCal/class.ilICalParameter.php');
33 include_once('./Services/Calendar/classes/iCal/class.ilICalValue.php');
34 
35 include_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['cal_err_no_input']);
82  }
83  #$GLOBALS['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');
212  $this->pushContainer($container);
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  continue;
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 }
$params
Definition: disable.php:11
Model for a calendar entry.
This class offers methods for timezone handling.
splitLine($a_line)
parse parameters
const IL_CAL_DATETIME
$type
switchTZ()
Switch timezone to given timezone.
storeItems($a_param_part, $a_value_part)
store items
restoreTZ()
restore time
setCategoryId($a_id)
set category id
$end
Definition: saml1-acs.php:18
$GLOBALS['loaded']
Global hash that tracks already loaded includes.
switchTZ(ilTimeZone $timezone)
Switch timezone.
Stores calendar categories.
writeEvent()
write a new event
Represents a ical property.
Used for storage og multiple values E.g RRULE:FREQ=WEEKLY;COUNT=20;INTERVAL=2;BYDAY=TU.
$counter
$a_type
Definition: workflow.php:92
const IL_CAL_DAY
tokenize($a_string, $a_tokenizer)
tokenize string
Class for single dates.
Class for TimeZone exceptions.
Date and time handling
Reload workbook from saved file
static stripSlashes($a_str, $a_strip_html=true, $a_allow="")
strip slashes if magic qoutes is enabled
increment($a_type, $a_count=1)
increment
Create styles array
The data for the language used.
Represents a ical component.
static _getInstance($a_tz='')
get instance by timezone
const IL_CAL_DATE
This class represents a ical parameter E.g VALUE=DATETIME.
getContainer()
get container
$i
Definition: disco.tpl.php:19
__construct($a_ical, $a_type)
Constructor.
setContainer($a_container)
set container
pushContainer($a_container)
push container
getTZ($a_timezone)
get timezone
parseLine($line)
parse a line
purgeString($a_string)
purge string
parse()
Parse input.
Abstract base class for all ical items (Component, Parameter and Value)