ILIAS  release_4-3 Revision
 All Data Structures Namespaces Files Functions Variables Groups Pages
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 
50  protected $log = null;
51 
52  protected $category = null;
53 
54  protected $ical = '';
55  protected $file = '';
56  protected $default_timezone = null;
57 
58  protected $container = array();
59 
69  public function __construct($a_ical,$a_type)
70  {
71  global $ilLog;
72 
73  if($a_type == self::INPUT_STRING)
74  {
75  $this->ical = $a_ical;
76  }
77  elseif($a_type == self::INPUT_FILE)
78  {
79  $this->file = $a_ical;
80  $this->ical = file_get_contents($a_ical);
81 
82  if(!strlen($this->ical))
83  {
84  throw new ilICalParserException($GLOBALS['cal_err_no_input']);
85  }
86  #$GLOBALS['ilLog']->write(__METHOD__.': Ical content: '. $this->ical);
87  }
88  $this->log = $ilLog;
89  }
90 
98  public function setCategoryId($a_id)
99  {
100  include_once('./Services/Calendar/classes/class.ilCalendarCategory.php');
101  $this->category = new ilCalendarCategory($a_id);
102  }
103 
110  public function parse()
111  {
112  $this->default_timezone = ilTimeZone::_getInstance();
113 
114  $lines = $this->tokenize($this->ical,ilICalUtils::ICAL_EOL);
115 
116  if(count(lines) == 1)
117  {
118  $lines = $this->tokenize($this->ical, ilICalUtils::ICAL_EOL_FB);
119  }
120 
121  for($i = 0; $i < count($lines); $i++)
122  {
123  $line = $lines[$i];
124 
125  // Check for next multilines (they start with a space)
126  $offset = 1;
127  while(isset($lines[$i + $offset]) and
128  (strpos($lines[$i + $offset],ilICalUtils::ICAL_SPACE) === 0) or
129  (strpos($lines[$i + $offset],ilICalUtils::ICAL_TAB) === 0))
130  {
131  $lines[$i + $offset] = str_replace(ilICalUtils::ICAL_EOL,'',$lines[$i + $offset]);
132  $line = $line.substr($lines[$i + $offset],1);
133  $offset++;
134  }
135  $i += ($offset - 1);
136 
137  // Parse this line
138  $this->parseLine($line);
139  }
140  }
141 
147  protected function getContainer()
148  {
149  return $this->container[count($this->container) - 1];
150  }
151 
158  protected function setContainer($a_container)
159  {
160  $this->container = array($a_container);
161  }
162 
168  protected function dropContainer()
169  {
170  return array_pop($this->container);
171  }
172 
179  protected function pushContainer($a_container)
180  {
181  $this->container[] = $a_container;
182  }
183 
184 
190  protected function parseLine($line)
191  {
192  switch(trim($line))
193  {
194  case 'BEGIN:VCALENDAR':
195  $this->log->write(__METHOD__.': BEGIN VCALENDAR');
196  $this->setContainer(new ilICalComponent('VCALENDAR'));
197  break;
198 
199  case 'END:VCALENDAR':
200  $this->log->write(__METHOD__.': END VCALENDAR');
201  break;
202 
203  case 'BEGIN:VEVENT':
204  $this->log->write(__METHOD__.': BEGIN VEVENT');
205  $this->pushContainer(new ilICalComponent('VEVENT'));
206  break;
207 
208  case 'END:VEVENT':
209  $this->log->write(__METHOD__.': END VEVENT');
210 
211  $this->writeEvent();
212 
213  $this->dropContainer();
214  break;
215 
216  case 'BEGIN:VTIMEZONE':
217  $this->log->write(__METHOD__.': BEGIN VTIMEZONE');
218  $container = new ilICalComponent('VTIMEZONE');
219  $this->pushContainer($container);
220  break;
221 
222  case 'END:VTIMEZONE':
223  $this->log->write(__METHOD__.': END VTIMEZONE');
224 
225  if($tzid = $this->getContainer()->getItemsByName('TZID'))
226  {
227  $this->default_timezone = $this->getTZ($tzid[0]->getValue());
228  }
229  $this->dropContainer();
230  break;
231 
232  default:
233  if(strpos(trim($line),'BEGIN') === 0)
234  {
235  $this->log->write(__METHOD__.': Do not handling line:'.$line);
236  continue;
237  }
238  if(strpos(trim($line),'X-WR-TIMEZONE') === 0)
239  {
240  list($param,$value) = $this->splitLine($line);
241  $this->default_timezone = $this->getTZ($value);
242  }
243  else
244  {
245  list($params,$values) = $this->splitLine($line);
246  $this->storeItems($params,$values);
247  }
248  break;
249  }
250 
251  }
252 
258  protected function storeItems($a_param_part,$a_value_part)
259  {
260  // Check for a semicolon in param part and split it.
261 
262  $items = array();
263  if($splitted_param = explode(';',$a_param_part))
264  {
265  $counter = 0;
266  foreach($splitted_param as $param)
267  {
268  if(!$counter)
269  {
270  $items[$counter]['param'] = $param;
271  $items[$counter]['value'] = $a_value_part;
272  }
273  else
274  {
275  // Split by '='
276  if($splitted_param_values = explode('=',$param))
277  {
278  $items[$counter]['param'] = $splitted_param_values[0];
279  $items[$counter]['value'] = $splitted_param_values[1];
280  }
281  }
282  ++$counter;
283  }
284  }
285 
286  // Split value part
287  $substituted_values = str_replace('\;','',$a_value_part);
288 
289  $values = array();
290  if($splitted_values = explode(';',$substituted_values))
291  {
292  $counter = 0;
293  foreach($splitted_values as $value)
294  {
295  // Split by '='
296  if($splitted_value_values = explode('=',$value))
297  {
298  $values[$counter]['param'] = $splitted_value_values[0];
299  $values[$counter]['value'] = $splitted_value_values[1];
300  }
301  ++$counter;
302  }
303  }
304 
305  // Return if there are no values
306  if(!count($items))
307  {
308  $this->log->write(__METHOD__.': Cannot parse parameter: '.$a_param_part.', value: '.$a_value_part);
309  return false;
310  }
311 
312 
313  $counter = 0;
314  foreach($items as $item)
315  {
316  if(!$counter)
317  {
318  // First is ical-Parameter
319  $parameter = new ilICalProperty($item['param'],$item['value']);
320 
321  if(!$this->getContainer() instanceof ilICalItem)
322  {
323  continue;
324  }
325 
326  $this->getContainer()->addItem($parameter);
327  $this->pushContainer($parameter);
328 
329  if(count($values) > 1)
330  {
331  foreach($values as $value)
332  {
333  $value = new ilICalValue($value['param'],$value['value']);
334  $this->getContainer()->addItem($value);
335  }
336  }
337  }
338  else
339  {
340  $value = new ilICalParameter($item['param'],$item['value']);
341  $this->getContainer()->addItem($value);
342  }
343  ++$counter;
344  }
345  $this->dropContainer();
346  }
347 
348 
355  protected function splitLine($a_line)
356  {
357  $matches = array();
358 
359  if(preg_match('/([^:]+):(.*)/',$a_line,$matches))
360  {
361  return array($matches[1],$matches[2]);
362  }
363  else
364  {
365  $this->log->write(__METHOD__.': Found invalid parameter: '.$a_line);
366  }
367 
368  return array('','');
369  }
370 
376  protected function tokenize($a_string,$a_tokenizer)
377  {
378  return explode($a_tokenizer,$a_string);
379  }
380 
386  protected function getTZ($a_timezone)
387  {
388  $parts = explode('/',$a_timezone);
389  $tz = array_pop($parts);
390  $continent = array_pop($parts);
391 
392  if(isset($continent) and $continent)
393  {
394  $timezone = $continent.'/'.$tz;
395  }
396  else
397  {
398  $timezone = $a_timezone;
399  }
400 
401  try
402  {
403  if($this->default_timezone->getIdentifier() == $timezone)
404  {
406  }
407  else
408  {
409  $this->log->write(__METHOD__.': Found new timezone: '.$timezone);
410  return ilTimeZone::_getInstance(trim($timezone));
411  }
412  }
413  catch(ilTimeZoneException $e)
414  {
415  $this->log->write(__METHOD__.': Found invalid timezone: '.$timezone);
417  }
418 
419  }
420 
426  protected function switchTZ(ilTimeZone $timezone)
427  {
428  try
429  {
430  $timezone->switchTZ();
431  }
432  catch(ilTimeZoneException $e)
433  {
434  $this->log->write(__METHOD__.': Found invalid timezone: '.$timezone);
435  return false;
436  }
437  }
438 
444  protected function restoreTZ()
445  {
446  $this->default_timezone->restoreTZ();
447  }
448 
454  protected function writeEvent()
455  {
456  $entry = new ilCalendarEntry();
457 
458  // Search for summary
459  foreach($this->getContainer()->getItemsByName('SUMMARY',false) as $item)
460  {
461  if(is_a($item,'ilICalProperty'))
462  {
463  $entry->setTitle($this->purgeString($item->getValue()));
464  break;
465  }
466  }
467  // Search description
468  foreach($this->getContainer()->getItemsByName('DESCRIPTION',false) as $item)
469  {
470  if(is_a($item,'ilICalProperty'))
471  {
472  $entry->setDescription($this->purgeString($item->getValue()));
473  break;
474  }
475  }
476 
477  // Search location
478  foreach($this->getContainer()->getItemsByName('LOCATION',false) as $item)
479  {
480  if(is_a($item,'ilICalProperty'))
481  {
482  $entry->setLocation($this->purgeString($item->getValue()));
483  break;
484  }
485  }
486 
487  foreach($this->getContainer()->getItemsByName('DTSTART') as $start)
488  {
489  $fullday = false;
490  foreach($start->getItemsByName('VALUE') as $type)
491  {
492  if($type->getValue() == 'DATE')
493  {
494  $fullday = true;
495  }
496  }
497  $start_tz = $this->default_timezone;
498  foreach($start->getItemsByName('TZID') as $param)
499  {
500  $start_tz = $this->getTZ($param->getValue());
501  }
502  if($fullday)
503  {
504  $start = new ilDate($start->getValue(),
505  IL_CAL_DATE);
506  }
507  else
508  {
509  $start = new ilDateTime($start->getValue(),
511  $start_tz->getIdentifier());
512  }
513  $entry->setStart($start);
514  $entry->setFullday($fullday);
515  }
516 
517  foreach($this->getContainer()->getItemsByName('DTEND') as $end)
518  {
519  $fullday = false;
520  foreach($end->getItemsByName('VALUE') as $type)
521  {
522  if($type->getValue() == 'DATE')
523  {
524  $fullday = true;
525  }
526  }
527  $end_tz = $this->default_timezone;
528  foreach($end->getItemsByName('TZID') as $param)
529  {
530  $end_tz = $this->getTZ($param->getValue());
531  }
532  if($fullday)
533  {
534  $end = new ilDate($end->getValue(),
535  IL_CAL_DATE);
536  $end->increment(IL_CAL_DAY,-1);
537  }
538  else
539  {
540  $end = new ilDateTime($end->getValue(),
542  $end_tz->getIdentifier());
543  }
544  $entry->setEnd($end);
545  $entry->setFullday($fullday);
546  }
547  // save calendar event
548  if($this->category->getLocationType() == ilCalendarCategory::LTYPE_REMOTE)
549  {
550  $entry->setAutoGenerated(true);
551  }
552  $entry->save();
553 
554  include_once('./Services/Calendar/classes/class.ilCalendarCategoryAssignments.php');
555  $ass = new ilCalendarCategoryAssignments($entry->getEntryId());
556  $ass->addAssignment($this->category->getCategoryID());
557 
558 
559  // Recurrences
560  foreach($this->getContainer()->getItemsByName('RRULE') as $recurrence)
561  {
562  #var_dump("<pre>",$recurrence,"</pre>");
563 
564 
565  include_once('./Services/Calendar/classes/class.ilCalendarRecurrence.php');
566  $rec = new ilCalendarRecurrence();
567  $rec->setEntryId($entry->getEntryId());
568 
569  foreach($recurrence->getItemsByName('FREQ') as $freq)
570  {
571  switch($freq->getValue())
572  {
573  case 'DAILY':
574  case 'WEEKLY':
575  case 'MONTHLY':
576  case 'YEARLY':
577  $rec->setFrequenceType((string) $freq->getValue());
578  break;
579 
580  default:
581  $this->log->write(__METHOD__.': Cannot handle recurring event of type: '.$freq->getValue());
582  break 3;
583  }
584  }
585 
586  foreach($recurrence->getItemsByName('COUNT') as $value)
587  {
588  $rec->setFrequenceUntilCount((string) $value->getValue());
589  break;
590  }
591  foreach($recurrence->getItemsByName('UNTIL') as $until)
592  {
593  $rec->setFrequenceUntilDate(new ilDate($until->getValue(),IL_CAL_DATE));
594  break;
595  }
596  foreach($recurrence->getItemsByName('INTERVAL') as $value)
597  {
598  $rec->setInterval((string) $value->getValue());
599  break;
600  }
601  foreach($recurrence->getItemsByName('BYDAY') as $value)
602  {
603  $rec->setBYDAY((string) $value->getValue());
604  break;
605  }
606  foreach($recurrence->getItemsByName('BYWEEKNO') as $value)
607  {
608  $rec->setBYWEEKNO((string) $value->getValue());
609  break;
610  }
611  foreach($recurrence->getItemsByName('BYMONTH') as $value)
612  {
613  $rec->setBYMONTH((string) $value->getValue());
614  break;
615  }
616  foreach($recurrence->getItemsByName('BYMONTHDAY') as $value)
617  {
618  $rec->setBYMONTHDAY((string) $value->getValue());
619  break;
620  }
621  foreach($recurrence->getItemsByName('BYYEARDAY') as $value)
622  {
623  $rec->setBYYEARDAY((string) $value->getValue());
624  break;
625  }
626  foreach($recurrence->getItemsByName('BYSETPOS') as $value)
627  {
628  $rec->setBYSETPOS((string) $value->getValue());
629  break;
630  }
631  foreach($recurrence->getItemsByName('WKST') as $value)
632  {
633  $rec->setWeekstart((string) $value->getValue());
634  break;
635  }
636  $rec->save();
637  }
638  }
639 
645  protected function purgeString($a_string)
646  {
647  $a_string = str_replace("\;",";",$a_string);
648  $a_string = str_replace("\,",",",$a_string);
649  $a_string = str_replace("\:",":",$a_string);
650  return ilUtil::stripSlashes($a_string);
651 
652  }
653 }
654 ?>