dolibarr 19.0.3
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
27require_once DOL_DOCUMENT_ROOT.'/core/lib/xcal.lib.php';
28require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
29
30
34class ICal
35{
39 public $file;
40
41 // Text in file
42 public $file_text;
43 public $cal; // Array to save iCalendar parse data
44 public $event_count; // Number of Events
45 public $todo_count; // Number of Todos
46 public $freebusy_count; // Number of Freebusy
47 public $last_key; //Help variable save last key (multiline string)
48 public $error;
49
50
54 public function __construct()
55 {
56 }
57
58 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
65 public function read_file($file)
66 {
67 // phpcs:enable
68 $this->file = $file;
69 $file_text = '';
70
71 $tmpresult = getURLContent($file, 'GET');
72 if ($tmpresult['http_code'] != 200) {
73 $file_text = null;
74 $this->error = 'Error: '.$tmpresult['http_code'].' '.$tmpresult['content'];
75 } else {
76 $file_text = preg_replace("/[\r\n]{1,} /", "", $tmpresult['content']);
77 }
78 //var_dump($tmpresult);
79
80 return $file_text; // return all text
81 }
82
83 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
89 public function get_event_count()
90 {
91 // phpcs:enable
92 return $this->event_count;
93 }
94
95 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
101 public function get_todo_count()
102 {
103 // phpcs:enable
104 return $this->todo_count;
105 }
106
115 public function parse($uri, $usecachefile = '', $delaycache = 3600)
116 {
117 $this->cal = array(); // new empty array
118
119 $this->event_count = -1;
120 $this->file_text = null;
121
122 // Save file into a cache
123 if ($usecachefile) {
124 include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
125 $datefile = dol_filemtime($usecachefile);
126 $now = dol_now('gmt');
127 //print $datefile.' '.$now.' ...';
128 if ($datefile && $datefile > ($now - $delaycache)) {
129 // We reuse the cache file
130 $this->file_text = file_get_contents($usecachefile);
131 }
132 }
133
134 // read FILE text
135 if (is_null($this->file_text)) {
136 $this->file_text = $this->read_file($uri);
137
138 if ($usecachefile && !is_null($this->file_text)) {
139 // Save the file content into cache file
140 file_put_contents($usecachefile, $this->file_text, LOCK_EX);
141 dolChmod($usecachefile);
142 }
143 }
144
145 $this->file_text = preg_split("[\n]", $this->file_text);
146
147 // is this text vcalendar standard text ? on line 1 is BEGIN:VCALENDAR
148 if (!stristr($this->file_text[0], 'BEGIN:VCALENDAR')) {
149 return 'error not VCALENDAR';
150 }
151
152 $insidealarm = 0;
153 $tmpkey = '';
154 $tmpvalue = '';
155 $type = '';
156 foreach ($this->file_text as $text) {
157 $text = trim($text); // trim one line
158 if (!empty($text)) {
159 // get Key and Value VCALENDAR:Begin -> Key = VCALENDAR, Value = begin
160 list($key, $value) = $this->retun_key_value($text);
161 //var_dump($text.' -> '.$key.' - '.$value);
162
163 switch ($text) { // search special string
164 case "BEGIN:VTODO":
165 $this->todo_count = $this->todo_count + 1; // new to do begin
166 $type = "VTODO";
167 break;
168
169 case "BEGIN:VEVENT":
170 $this->event_count = $this->event_count + 1; // new event begin
171 $type = "VEVENT";
172 break;
173
174 case "BEGIN:VFREEBUSY":
175 $this->freebusy_count = $this->freebusy_count + 1; // new event begin
176 $type = "VFREEBUSY";
177 break;
178
179 case "BEGIN:VCALENDAR": // all other special string
180 case "BEGIN:DAYLIGHT":
181 case "BEGIN:VTIMEZONE":
182 case "BEGIN:STANDARD":
183 $type = $value; // save array under value key
184 break;
185
186 case "END:VTODO": // end special text - goto VCALENDAR key
187 case "END:VEVENT":
188 case "END:VFREEBUSY":
189 case "END:VCALENDAR":
190 case "END:DAYLIGHT":
191 case "END:VTIMEZONE":
192 case "END:STANDARD":
193 $type = "VCALENDAR";
194 break;
195
196 // Manage VALARM that are inside a VEVENT to avoid fields of VALARM to overwrites fields of VEVENT
197 case "BEGIN:VALARM":
198 $insidealarm = 1;
199 break;
200 case "END:VALARM":
201 $insidealarm = 0;
202 break;
203
204 default: // no special string (SUMMARY, DESCRIPTION, ...)
205 if ($tmpvalue) {
206 $tmpvalue .= $text;
207 if (!preg_match('/=$/', $text)) { // No more lines
208 $key = $tmpkey;
209 $value = quotedPrintDecode(preg_replace('/^ENCODING=QUOTED-PRINTABLE:/i', '', $tmpvalue));
210 $tmpkey = '';
211 $tmpvalue = '';
212 }
213 } elseif (preg_match('/^ENCODING=QUOTED-PRINTABLE:/i', $value)) {
214 if (preg_match('/=$/', $value)) {
215 $tmpkey = $key;
216 $tmpvalue = $tmpvalue.preg_replace('/=$/', "", $value); // We must wait to have next line to have complete message
217 } else {
218 $value = quotedPrintDecode(preg_replace('/^ENCODING=QUOTED-PRINTABLE:/i', '', $tmpvalue.$value));
219 }
220 } //$value=quotedPrintDecode($tmpvalue.$value);
221 if (!$insidealarm && !$tmpkey) {
222 $this->add_to_array($type, $key, $value); // add to array
223 }
224 break;
225 }
226 }
227 }
228
229 //var_dump($this->cal);
230 return $this->cal;
231 }
232
233 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
242 public function add_to_array($type, $key, $value)
243 {
244 // phpcs:enable
245
246 //print 'type='.$type.' key='.$key.' value='.$value.'<br>'."\n";
247
248 if (empty($key)) {
249 $key = $this->last_key;
250 switch ($type) {
251 case 'VEVENT':
252 $value = $this->cal[$type][$this->event_count][$key].$value;
253 break;
254 case 'VFREEBUSY':
255 $value = $this->cal[$type][$this->freebusy_count][$key].$value;
256 break;
257 case 'VTODO':
258 $value = $this->cal[$type][$this->todo_count][$key].$value;
259 break;
260 }
261 }
262
263 if (($key == "DTSTAMP") || ($key == "LAST-MODIFIED") || ($key == "CREATED")) {
264 $value = $this->ical_date_to_unix($value);
265 }
266 //if ($key == "RRULE" ) $value = $this->ical_rrule($value);
267
268 if (stristr($key, "DTSTART") || stristr($key, "DTEND") || stristr($key, "DTSTART;VALUE=DATE") || stristr($key, "DTEND;VALUE=DATE")) {
269 if (stristr($key, "DTSTART;VALUE=DATE") || stristr($key, "DTEND;VALUE=DATE")) {
270 list($key, $value) = array($key, $value);
271 } else {
272 list($key, $value) = $this->ical_dt_date($key, $value);
273 }
274 }
275
276 switch ($type) {
277 case "VTODO":
278 $this->cal[$type][$this->todo_count][$key] = $value;
279 break;
280
281 case "VEVENT":
282 $this->cal[$type][$this->event_count][$key] = $value;
283 break;
284
285 case "VFREEBUSY":
286 $this->cal[$type][$this->freebusy_count][$key] = $value;
287 break;
288
289 default:
290 $this->cal[$type][$key] = $value;
291 break;
292 }
293 $this->last_key = $key;
294 }
295
296 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
303 public function retun_key_value($text)
304 {
305 // phpcs:enable
306 /*
307 preg_match("/([^:]+)[:]([\w\W]+)/", $text, $matches);
308
309 if (empty($matches))
310 {
311 return array(false,$text);
312 }
313 else
314 {
315 $matches = array_splice($matches, 1, 2);
316 return $matches;
317 }*/
318 return explode(':', $text, 2);
319 }
320
321 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
328 public function ical_rrule($value)
329 {
330 // phpcs:enable
331 $result = array();
332 $rrule = explode(';', $value);
333 foreach ($rrule as $line) {
334 $rcontent = explode('=', $line);
335 $result[$rcontent[0]] = $rcontent[1];
336 }
337 return $result;
338 }
339
340 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
347 public function ical_date_to_unix($ical_date)
348 {
349 // phpcs:enable
350 $ical_date = str_replace('T', '', $ical_date);
351 $ical_date = str_replace('Z', '', $ical_date);
352
353 $ntime = 0;
354 // TIME LIMITED EVENT
355 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)) {
356 $ntime = dol_mktime($date[4], $date[5], $date[6], $date[2], $date[3], $date[1], true);
357 }
358
359 //if (empty($date[4])) print 'Error bad date: '.$ical_date.' - date1='.$date[1];
360 //print dol_print_date($ntime,'dayhour');exit;
361 return $ntime; // ntime is a GTM time
362 }
363
364 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
372 public function ical_dt_date($key, $value)
373 {
374 // phpcs:enable
375 $return_value = array();
376 $value = $this->ical_date_to_unix($value);
377
378 // Analyse TZID
379 $temp = explode(";", $key);
380
381 if (empty($temp[1])) { // not TZID
382 $value = str_replace('T', '', $value);
383 return array($key, $value);
384 }
385
386 $key = $temp[0];
387 $temp = explode("=", $temp[1]);
388 $return_value[$temp[0]] = $temp[1];
389 $return_value['unixtime'] = $value;
390
391 return array($key, $return_value);
392 }
393
394 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
400 public function get_sort_event_list()
401 {
402 // phpcs:enable
403 $temp = $this->get_event_list();
404 if (!empty($temp)) {
405 usort($temp, array(&$this, "ical_dtstart_compare"));
406 return $temp;
407 } else {
408 return false;
409 }
410 }
411
412 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
420 public function ical_dtstart_compare($a, $b)
421 {
422 // phpcs:enable
423 return strnatcasecmp($a['DTSTART']['unixtime'], $b['DTSTART']['unixtime']);
424 }
425
426 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
432 public function get_event_list()
433 {
434 // phpcs:enable
435 return (empty($this->cal['VEVENT']) ? array() : $this->cal['VEVENT']);
436 }
437
438 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
444 public function get_freebusy_list()
445 {
446 // phpcs:enable
447 return (empty($this->cal['VFREEBUSY']) ? array() : $this->cal['VFREEBUSY']);
448 }
449
450 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
456 public function get_todo_list()
457 {
458 // phpcs:enable
459 return $this->cal['VTODO'];
460 }
461
462 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
468 public function get_calender_data()
469 {
470 // phpcs:enable
471 return $this->cal['VCALENDAR'];
472 }
473
474 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
480 public function get_all_data()
481 {
482 // phpcs:enable
483 return $this->cal;
484 }
485}
Class to read/parse ICal calendars.
get_all_data()
Return array with all data.
get_event_list()
Return eventlist array (not sorted eventlist array)
parse($uri, $usecachefile='', $delaycache=3600)
Translate Calendar.
ical_dt_date($key, $value)
Return unix date from iCal date format.
ical_rrule($value)
Parse RRULE return array.
retun_key_value($text)
Parse text "XXXX:value text some with : " and return array($key = "XXXX", $value="value");.
get_todo_count()
Returns the number of to do.
ical_dtstart_compare($a, $b)
Compare two unix timestamp.
get_event_count()
Returns the number of calendar events.
__construct()
Constructor.
add_to_array($type, $key, $value)
Add to $this->ical array one value and key.
read_file($file)
Read text file, icalender text file.
get_sort_event_list()
Return sorted eventlist as array or false if calendar is empty.
get_freebusy_list()
Return freebusy array (not sort eventlist array)
get_todo_list()
Return to do array (not sorted todo array)
get_calender_data()
Return base calendar data.
ical_date_to_unix($ical_date)
Return Unix time from ical date time fomrat (YYYYMMDD[T]HHMMSS[Z] or YYYYMMDD[T]HHMMSS)
dol_filemtime($pathoffile)
Return time of a file.
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...
dolChmod($filepath, $newmask='')
Change mod of a file.
dol_now($mode='auto')
Return date for now.
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).
quotedPrintDecode($str)
Decode vcal format.
Definition xcal.lib.php:591