dolibarr  16.0.5
ical.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2006 Roman Ozana <ozana@omdesign.cz>
3  * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
4  * Copyright (C) 2013-2014 Laurent Destailleur <eldy@users.sourceforge.net>
5  * Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
6  * Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (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, see <https://www.gnu.org/licenses/>.
20  */
21 
27 require_once DOL_DOCUMENT_ROOT.'/core/lib/xcal.lib.php';
28 require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
29 
30 
34 class ICal
35 {
36  // Text in file
37  public $file_text;
38  public $cal; // Array to save iCalendar parse data
39  public $event_count; // Number of Events
40  public $todo_count; // Number of Todos
41  public $freebusy_count; // Number of Freebusy
42  public $last_key; //Help variable save last key (multiline string)
43  public $error;
44 
45 
49  public function __construct()
50  {
51  }
52 
53  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
60  public function read_file($file)
61  {
62  // phpcs:enable
63  $this->file = $file;
64  $file_text = '';
65 
66  $tmpresult = getURLContent($file, 'GET');
67  if ($tmpresult['http_code'] != 200) {
68  $file_text = '';
69  $this->error = 'Error: '.$tmpresult['http_code'].' '.$tmpresult['content'];
70  } else {
71  $file_text = preg_replace("/[\r\n]{1,} /", "", $tmpresult['content']);
72  }
73  //var_dump($tmpresult);
74 
75  return $file_text; // return all text
76  }
77 
78  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
84  public function get_event_count()
85  {
86  // phpcs:enable
87  return $this->event_count;
88  }
89 
90  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
96  public function get_todo_count()
97  {
98  // phpcs:enable
99  return $this->todo_count;
100  }
101 
108  public function parse($uri)
109  {
110  $this->cal = array(); // new empty array
111 
112  $this->event_count = -1;
113 
114  // read FILE text
115  $this->file_text = $this->read_file($uri);
116 
117  $this->file_text = preg_split("[\n]", $this->file_text);
118 
119  // is this text vcalendar standard text ? on line 1 is BEGIN:VCALENDAR
120  if (!stristr($this->file_text[0], 'BEGIN:VCALENDAR')) {
121  return 'error not VCALENDAR';
122  }
123 
124  $insidealarm = 0;
125  $tmpkey = ''; $tmpvalue = ''; $type = '';
126  foreach ($this->file_text as $text) {
127  $text = trim($text); // trim one line
128  if (!empty($text)) {
129  // get Key and Value VCALENDAR:Begin -> Key = VCALENDAR, Value = begin
130  list($key, $value) = $this->retun_key_value($text);
131  //var_dump($text.' -> '.$key.' - '.$value);
132 
133  switch ($text) { // search special string
134  case "BEGIN:VTODO":
135  $this->todo_count = $this->todo_count + 1; // new to do begin
136  $type = "VTODO";
137  break;
138 
139  case "BEGIN:VEVENT":
140  $this->event_count = $this->event_count + 1; // new event begin
141  $type = "VEVENT";
142  break;
143 
144  case "BEGIN:VFREEBUSY":
145  $this->freebusy_count = $this->freebusy_count + 1; // new event begin
146  $type = "VFREEBUSY";
147  break;
148 
149  case "BEGIN:VCALENDAR": // all other special string
150  case "BEGIN:DAYLIGHT":
151  case "BEGIN:VTIMEZONE":
152  case "BEGIN:STANDARD":
153  $type = $value; // save array under value key
154  break;
155 
156  case "END:VTODO": // end special text - goto VCALENDAR key
157  case "END:VEVENT":
158  case "END:VFREEBUSY":
159  case "END:VCALENDAR":
160  case "END:DAYLIGHT":
161  case "END:VTIMEZONE":
162  case "END:STANDARD":
163  $type = "VCALENDAR";
164  break;
165 
166  // Manage VALARM that are inside a VEVENT to avoid fields of VALARM to overwrites fields of VEVENT
167  case "BEGIN:VALARM":
168  $insidealarm = 1;
169  break;
170  case "END:VALARM":
171  $insidealarm = 0;
172  break;
173 
174  default: // no special string (SUMMARY, DESCRIPTION, ...)
175  if ($tmpvalue) {
176  $tmpvalue .= $text;
177  if (!preg_match('/=$/', $text)) { // No more lines
178  $key = $tmpkey;
179  $value = quotedPrintDecode(preg_replace('/^ENCODING=QUOTED-PRINTABLE:/i', '', $tmpvalue));
180  $tmpkey = '';
181  $tmpvalue = '';
182  }
183  } elseif (preg_match('/^ENCODING=QUOTED-PRINTABLE:/i', $value)) {
184  if (preg_match('/=$/', $value)) {
185  $tmpkey = $key;
186  $tmpvalue = $tmpvalue.preg_replace('/=$/', "", $value); // We must wait to have next line to have complete message
187  } else {
188  $value = quotedPrintDecode(preg_replace('/^ENCODING=QUOTED-PRINTABLE:/i', '', $tmpvalue.$value));
189  }
190  } //$value=quotedPrintDecode($tmpvalue.$value);
191  if (!$insidealarm && !$tmpkey) {
192  $this->add_to_array($type, $key, $value); // add to array
193  }
194  break;
195  }
196  }
197  }
198 
199  //var_dump($this->cal);
200  return $this->cal;
201  }
202 
203  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
212  public function add_to_array($type, $key, $value)
213  {
214  // phpcs:enable
215 
216  //print 'type='.$type.' key='.$key.' value='.$value.'<br>'."\n";
217 
218  if (empty($key)) {
219  $key = $this->last_key;
220  switch ($type) {
221  case 'VEVENT':
222  $value = $this->cal[$type][$this->event_count][$key].$value;
223  break;
224  case 'VFREEBUSY':
225  $value = $this->cal[$type][$this->freebusy_count][$key].$value;
226  break;
227  case 'VTODO':
228  $value = $this->cal[$type][$this->todo_count][$key].$value;
229  break;
230  }
231  }
232 
233  if (($key == "DTSTAMP") || ($key == "LAST-MODIFIED") || ($key == "CREATED")) {
234  $value = $this->ical_date_to_unix($value);
235  }
236  //if ($key == "RRULE" ) $value = $this->ical_rrule($value);
237 
238  if (stristr($key, "DTSTART") || stristr($key, "DTEND") || stristr($key, "DTSTART;VALUE=DATE") || stristr($key, "DTEND;VALUE=DATE")) {
239  if (stristr($key, "DTSTART;VALUE=DATE") || stristr($key, "DTEND;VALUE=DATE")) {
240  list($key, $value) = array($key, $value);
241  } else {
242  list($key, $value) = $this->ical_dt_date($key, $value);
243  }
244  }
245 
246  switch ($type) {
247  case "VTODO":
248  $this->cal[$type][$this->todo_count][$key] = $value;
249  break;
250 
251  case "VEVENT":
252  $this->cal[$type][$this->event_count][$key] = $value;
253  break;
254 
255  case "VFREEBUSY":
256  $this->cal[$type][$this->freebusy_count][$key] = $value;
257  break;
258 
259  default:
260  $this->cal[$type][$key] = $value;
261  break;
262  }
263  $this->last_key = $key;
264  }
265 
266  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
273  public function retun_key_value($text)
274  {
275  // phpcs:enable
276  /*
277  preg_match("/([^:]+)[:]([\w\W]+)/", $text, $matches);
278 
279  if (empty($matches))
280  {
281  return array(false,$text);
282  }
283  else
284  {
285  $matches = array_splice($matches, 1, 2);
286  return $matches;
287  }*/
288  return explode(':', $text, 2);
289  }
290 
291  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
298  public function ical_rrule($value)
299  {
300  // phpcs:enable
301  $result = array();
302  $rrule = explode(';', $value);
303  foreach ($rrule as $line) {
304  $rcontent = explode('=', $line);
305  $result[$rcontent[0]] = $rcontent[1];
306  }
307  return $result;
308  }
309 
310  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
317  public function ical_date_to_unix($ical_date)
318  {
319  // phpcs:enable
320  $ical_date = str_replace('T', '', $ical_date);
321  $ical_date = str_replace('Z', '', $ical_date);
322 
323  $ntime = 0;
324  // TIME LIMITED EVENT
325  if (preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})([0-9]{0,2})/', $ical_date, $date)) {
326  $ntime = dol_mktime($date[4], $date[5], $date[6], $date[2], $date[3], $date[1], true);
327  }
328 
329  //if (empty($date[4])) print 'Error bad date: '.$ical_date.' - date1='.$date[1];
330  //print dol_print_date($ntime,'dayhour');exit;
331  return $ntime; // ntime is a GTM time
332  }
333 
334  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
342  public function ical_dt_date($key, $value)
343  {
344  // phpcs:enable
345  $return_value = array();
346  $value = $this->ical_date_to_unix($value);
347 
348  // Analyse TZID
349  $temp = explode(";", $key);
350 
351  if (empty($temp[1])) { // not TZID
352  $value = str_replace('T', '', $value);
353  return array($key, $value);
354  }
355 
356  $key = $temp[0];
357  $temp = explode("=", $temp[1]);
358  $return_value[$temp[0]] = $temp[1];
359  $return_value['unixtime'] = $value;
360 
361  return array($key, $return_value);
362  }
363 
364  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
370  public function get_sort_event_list()
371  {
372  // phpcs:enable
373  $temp = $this->get_event_list();
374  if (!empty($temp)) {
375  usort($temp, array(&$this, "ical_dtstart_compare"));
376  return $temp;
377  } else {
378  return false;
379  }
380  }
381 
382  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
390  public function ical_dtstart_compare($a, $b)
391  {
392  // phpcs:enable
393  return strnatcasecmp($a['DTSTART']['unixtime'], $b['DTSTART']['unixtime']);
394  }
395 
396  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
402  public function get_event_list()
403  {
404  // phpcs:enable
405  return (empty($this->cal['VEVENT']) ? '' : $this->cal['VEVENT']);
406  }
407 
408  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
414  public function get_freebusy_list()
415  {
416  // phpcs:enable
417  return (empty($this->cal['VFREEBUSY']) ? '' : $this->cal['VFREEBUSY']);
418  }
419 
420  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
426  public function get_todo_list()
427  {
428  // phpcs:enable
429  return $this->cal['VTODO'];
430  }
431 
432  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
438  public function get_calender_data()
439  {
440  // phpcs:enable
441  return $this->cal['VCALENDAR'];
442  }
443 
444  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
450  public function get_all_data()
451  {
452  // phpcs:enable
453  return $this->cal;
454  }
455 }
ICal\get_freebusy_list
get_freebusy_list()
Return freebusy array (not sort eventlist array)
Definition: ical.class.php:414
ICal\add_to_array
add_to_array($type, $key, $value)
Add to $this->ical array one value and key.
Definition: ical.class.php:212
ICal\get_event_list
get_event_list()
Return eventlist array (not sorted eventlist array)
Definition: ical.class.php:402
ICal\get_todo_count
get_todo_count()
Returns the number of to do.
Definition: ical.class.php:96
ICal\get_event_count
get_event_count()
Returns the number of calendar events.
Definition: ical.class.php:84
ICal\ical_rrule
ical_rrule($value)
Parse RRULE return array.
Definition: ical.class.php:298
getURLContent
getURLContent($url, $postorget='GET', $param='', $followlocation=1, $addheaders=array(), $allowedschemes=array('http', 'https'), $localurl=0, $ssl_verifypeer=-1)
Function to get a content from an URL (use proxy if proxy defined).
Definition: geturl.lib.php:41
ICal\parse
parse($uri)
Translate Calendar.
Definition: ical.class.php:108
ICal\get_calender_data
get_calender_data()
Return base calendar data.
Definition: ical.class.php:438
ICal\get_all_data
get_all_data()
Return array with all data.
Definition: ical.class.php:450
ICal\ical_dt_date
ical_dt_date($key, $value)
Return unix date from iCal date format.
Definition: ical.class.php:342
ICal\read_file
read_file($file)
Read text file, icalender text file.
Definition: ical.class.php:60
ICal\get_todo_list
get_todo_list()
Return to do array (not sorted todo array)
Definition: ical.class.php:426
ICal
Class to read/parse ICal calendars.
Definition: ical.class.php:34
quotedPrintDecode
quotedPrintDecode($str)
Decode vcal format.
Definition: xcal.lib.php:571
ICal\ical_dtstart_compare
ical_dtstart_compare($a, $b)
Compare two unix timestamp.
Definition: ical.class.php:390
ICal\ical_date_to_unix
ical_date_to_unix($ical_date)
Return Unix time from ical date time fomrat (YYYYMMDD[T]HHMMSS[Z] or YYYYMMDD[T]HHMMSS)
Definition: ical.class.php:317
dol_mktime
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed informations (by default a local PHP server timestamp) Re...
Definition: functions.lib.php:2757
ICal\retun_key_value
retun_key_value($text)
Parse text "XXXX:value text some with : " and return array($key = "XXXX", $value="value");.
Definition: ical.class.php:273
ICal\__construct
__construct()
Constructor.
Definition: ical.class.php:49
ICal\get_sort_event_list
get_sort_event_list()
Return sorted eventlist as array or false if calendar is empty.
Definition: ical.class.php:370