dolibarr  13.0.2
xcal.lib.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 
35 function build_calfile($format, $title, $desc, $events_array, $outputfile)
36 {
37  global $conf, $langs;
38 
39  dol_syslog("xcal.lib.php::build_calfile Build cal file ".$outputfile." to format ".$format);
40 
41  if (empty($outputfile))
42  {
43  // -1 = error
44  return -1;
45  }
46 
47  // Note: A cal file is an UTF8 encoded file
48  $calfileh = fopen($outputfile, "w");
49 
50  if ($calfileh)
51  {
52  include_once DOL_DOCUMENT_ROOT."/core/lib/date.lib.php";
53 
54  $now = dol_now();
55  $encoding = "";
56 
57  if ($format === "vcal")
58  {
59  $encoding = "ENCODING=QUOTED-PRINTABLE:";
60  }
61 
62  // Print header
63  fwrite($calfileh, "BEGIN:VCALENDAR\n");
64 
65  // version is always "2.0"
66  fwrite($calfileh, "VERSION:2.0\n");
67 
68  fwrite($calfileh, "METHOD:PUBLISH\n");
69  fwrite($calfileh, "PRODID:-//DOLIBARR ".DOL_VERSION."\n");
70  fwrite($calfileh, "CALSCALE:GREGORIAN\n");
71  fwrite($calfileh, "X-WR-CALNAME:".$encoding.format_cal($format, $title)."\n");
72  fwrite($calfileh, "X-WR-CALDESC:".$encoding.format_cal($format, $desc)."\n");
73  //fwrite($calfileh,"X-WR-TIMEZONE:Europe/Paris\n");
74 
75  if (!empty($conf->global->MAIN_AGENDA_EXPORT_CACHE) && $conf->global->MAIN_AGENDA_EXPORT_CACHE > 60)
76  {
77  $hh = convertSecondToTime($conf->global->MAIN_AGENDA_EXPORT_CACHE, "hour");
78  $mm = convertSecondToTime($conf->global->MAIN_AGENDA_EXPORT_CACHE, "min");
79  $ss = convertSecondToTime($conf->global->MAIN_AGENDA_EXPORT_CACHE, "sec");
80 
81  fwrite($calfileh, "X-PUBLISHED-TTL: P".$hh."H".$mm."M".$ss."S\n");
82  }
83 
84  foreach ($events_array as $key => $event)
85  {
86  // See http://fr.wikipedia.org/wiki/ICalendar for format
87  // See http://www.ietf.org/rfc/rfc2445.txt for RFC
88 
89  // TODO: avoid use extra event array, use objects direct thahtwas created before
90 
91  $uid = $event["uid"];
92  $type = $event["type"];
93  $startdate = $event["startdate"];
94  $duration = $event["duration"];
95  $enddate = $event["enddate"];
96  $summary = $event["summary"];
97  $category = $event["category"];
98  $priority = $event["priority"];
99  $fulldayevent = $event["fulldayevent"];
100  $location = $event["location"];
101  $email = $event["email"];
102  $url = $event["url"];
103  $transparency = $event["transparency"];
104  $description = dol_string_nohtmltag(preg_replace("/<br[\s\/]?>/i", "\n", $event["desc"]), 0);
105  $created = $event["created"];
106  $modified = $event["modified"];
107  $assignedUsers = $event["assignedUsers"];
108 
109  // Format
110  $summary = format_cal($format, $summary);
111  $description = format_cal($format, $description);
112  $category = format_cal($format, $category);
113  $location = format_cal($format, $location);
114 
115  // Output the vCard/iCal VEVENT object
116  /*
117  Example from Google ical export for a 1 hour event:
118  BEGIN:VEVENT
119  DTSTART:20101103T120000Z
120  DTEND:20101103T130000Z
121  DTSTAMP:20101121T144902Z
122  UID:4eilllcsq8r1p87ncg7vc8dbpk@google.com
123  CREATED:20101121T144657Z
124  DESCRIPTION:
125  LAST-MODIFIED:20101121T144707Z
126  LOCATION:
127  SEQUENCE:0
128  STATUS:CONFIRMED
129  SUMMARY:Tâche 1 heure
130  TRANSP:OPAQUE
131  END:VEVENT
132 
133  Example from Google ical export for a 1 day event:
134  BEGIN:VEVENT
135  DTSTART;VALUE=DATE:20101102
136  DTEND;VALUE=DATE:20101103
137  DTSTAMP:20101121T144902Z
138  UID:d09t43kcf1qgapu9efsmmo1m6k@google.com
139  CREATED:20101121T144607Z
140  DESCRIPTION:
141  LAST-MODIFIED:20101121T144607Z
142  LOCATION:
143  SEQUENCE:0
144  STATUS:CONFIRMED
145  SUMMARY:Tâche 1 jour
146  TRANSP:TRANSPARENT
147  END:VEVENT
148  */
149 
150  if ($type === "event")
151  {
152  fwrite($calfileh, "BEGIN:VEVENT\n");
153  fwrite($calfileh, "UID:".$uid."\n");
154 
155  if (!empty($email))
156  {
157  fwrite($calfileh, "ORGANIZER:MAILTO:".$email."\n");
158  fwrite($calfileh, "CONTACT:MAILTO:".$email."\n");
159  }
160 
161  if (!empty($url))
162  {
163  fwrite($calfileh, "URL:".$url."\n");
164  }
165 
166  if (is_array($assignedUsers))
167  {
168  foreach ($assignedUsers as $assignedUser)
169  {
170  if ($assignedUser->email === $email)
171  {
172  continue;
173  }
174 
175  fwrite($calfileh, "ATTENDEE;RSVP=TRUE:mailto:".$assignedUser->email."\n");
176  }
177  }
178 
179  if ($created)
180  {
181  fwrite($calfileh, "CREATED:".dol_print_date($created, "dayhourxcard", true)."\n");
182  }
183 
184  if ($modified)
185  {
186  fwrite($calfileh, "LAST-MODIFIED:".dol_print_date($modified, "dayhourxcard", true)."\n");
187  }
188 
189  fwrite($calfileh, "SUMMARY:".$encoding.$summary."\n");
190  fwrite($calfileh, "DESCRIPTION:".$encoding.$description."\n");
191 
192  if (!empty($location))
193  {
194  fwrite($calfileh, "LOCATION:".$encoding.$location."\n");
195  }
196 
197  if ($fulldayevent)
198  {
199  fwrite($calfileh, "X-FUNAMBOL-ALLDAY:1\n");
200  }
201 
202  // see https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxcical/0f262da6-c5fd-459e-9f18-145eba86b5d2
203  if ($fulldayevent)
204  {
205  fwrite($calfileh, "X-MICROSOFT-CDO-ALLDAYEVENT:TRUE\n");
206  }
207 
208  // Date must be GMT dates
209  // Current date
210  fwrite($calfileh, "DTSTAMP:".dol_print_date($now, "dayhourxcard", true)."\n");
211 
212  // Start date
213  $prefix = "";
214  $startdatef = dol_print_date($startdate, "dayhourxcard", true);
215 
216  if ($fulldayevent)
217  {
218  // Local time
219  $prefix = ";VALUE=DATE";
220  $startdatef = dol_print_date($startdate, "dayxcard", false);
221  }
222 
223  fwrite($calfileh, "DTSTART".$prefix.":".$startdatef."\n");
224 
225  // End date
226  if ($fulldayevent)
227  {
228  if (empty($enddate))
229  {
230  $enddate = dol_time_plus_duree($startdate, 1, "d");
231  }
232  } else {
233  if (empty($enddate))
234  {
235  $enddate = $startdate + $duration;
236  }
237  }
238 
239  $prefix = "";
240  $enddatef = dol_print_date($enddate, "dayhourxcard", true);
241 
242  if ($fulldayevent)
243  {
244  $prefix = ";VALUE=DATE";
245  $enddatef = dol_print_date($enddate + 1, "dayxcard", false);
246 
247  // Local time
248  //$enddatef .= dol_print_date($enddate+1,"dayhourxcard",false);
249  }
250 
251  fwrite($calfileh, "DTEND".$prefix.":".$enddatef."\n");
252  fwrite($calfileh, "STATUS:CONFIRMED\n");
253 
254  if (!empty($transparency))
255  {
256  fwrite($calfileh, "TRANSP:".$transparency."\n");
257  }
258 
259  if (!empty($category))
260  {
261  fwrite($calfileh, "CATEGORIES:".$encoding.$category."\n");
262  }
263 
264  fwrite($calfileh, "END:VEVENT\n");
265  }
266 
267  // Output the vCard/iCal VJOURNAL object
268  if ($type === "journal")
269  {
270  fwrite($calfileh, "BEGIN:VJOURNAL\n");
271  fwrite($calfileh, "UID:".$uid."\n");
272 
273  if (!empty($email))
274  {
275  fwrite($calfileh, "ORGANIZER:MAILTO:".$email."\n");
276  fwrite($calfileh, "CONTACT:MAILTO:".$email."\n");
277  }
278 
279  if (!empty($url))
280  {
281  fwrite($calfileh, "URL:".$url."\n");
282  }
283 
284  if ($created)
285  {
286  fwrite($calfileh, "CREATED:".dol_print_date($created, "dayhourxcard", true)."\n");
287  }
288 
289  if ($modified)
290  {
291  fwrite($calfileh, "LAST-MODIFIED:".dol_print_date($modified, "dayhourxcard", true)."\n");
292  }
293 
294  fwrite($calfileh, "SUMMARY:".$encoding.$summary."\n");
295  fwrite($calfileh, "DESCRIPTION:".$encoding.$description."\n");
296  fwrite($calfileh, "STATUS:CONFIRMED\n");
297  fwrite($calfileh, "CATEGORIES:".$category."\n");
298  fwrite($calfileh, "LOCATION:".$location."\n");
299  fwrite($calfileh, "TRANSP:OPAQUE\n");
300  fwrite($calfileh, "CLASS:CONFIDENTIAL\n");
301  fwrite($calfileh, "DTSTAMP:".dol_print_date($startdatef, "dayhourxcard", true)."\n");
302 
303  fwrite($calfileh, "END:VJOURNAL\n");
304  }
305  }
306 
307  // Footer
308  fwrite($calfileh, "END:VCALENDAR");
309 
310  fclose($calfileh);
311 
312  if (!empty($conf->global->MAIN_UMASK))
313  {
314  @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
315  }
316  } else {
317  dol_syslog("xcal.lib.php::build_calfile Failed to open file ".$outputfile." for writing");
318  return -2;
319  }
320 }
321 
336 function build_rssfile($format, $title, $desc, $events_array, $outputfile, $filter = '', $url = '', $langcode = '')
337 {
338  global $user, $conf, $langs;
339  global $dolibarr_main_url_root;
340 
341  dol_syslog("xcal.lib.php::build_rssfile Build rss file ".$outputfile." to format ".$format);
342 
343  if (empty($outputfile))
344  {
345  // -1 = error
346  return -1;
347  }
348 
349  $fichier = fopen($outputfile, "w");
350 
351  if ($fichier)
352  {
353  $date = date("r");
354 
355  // Print header
356  fwrite($fichier, '<?xml version="1.0" encoding="'.$langs->charset_output.'"?>');
357  fwrite($fichier, "\n");
358 
359  fwrite($fichier, '<rss version="2.0">');
360  fwrite($fichier, "\n");
361 
362  fwrite($fichier, "<channel>\n");
363  fwrite($fichier, "<title>".$title."</title>\n");
364  if ($langcode) fwrite($fichier, "<language>".$langcode."</language>\n");
365 
366  /*
367  fwrite($fichier, "<description><![CDATA[".$desc.".]]></description>"."\n".
368  // "<language>fr</language>"."\n".
369  "<copyright>Dolibarr</copyright>"."\n".
370  "<lastBuildDate>".$date."</lastBuildDate>"."\n".
371  "<generator>Dolibarr</generator>"."\n");
372  */
373 
374  if (empty($url)) {
375  // Define $urlwithroot
376  $urlwithouturlroot = preg_replace("/".preg_quote(DOL_URL_ROOT, "/")."$/i", "", trim($dolibarr_main_url_root));
377  $urlwithroot = $urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file
378  //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current
379 
380  $url = $urlwithroot."/public/agenda/agendaexport.php?format=rss&exportkey=".urlencode($conf->global->MAIN_AGENDA_XCAL_EXPORTKEY);
381  }
382 
383  fwrite($fichier, "<link><![CDATA[".$url."]]></link>\n");
384 
385  foreach ($events_array as $key => $event)
386  {
387  $eventqualified = true;
388 
389  if ($filter)
390  {
391  // TODO Add a filter
392 
393  $eventqualified = false;
394  }
395 
396  if ($eventqualified)
397  {
398  if (is_object($event) && get_class($event) == 'WebsitePage') {
399  // Convert object into an array
400  $tmpevent = array();
401  $tmpevent['uid'] = $event->id;
402  $tmpevent['startdate'] = $event->date_creation;
403  $tmpevent['summary'] = $event->title;
404  $tmpevent['url'] = $event->fullpageurl ? $event->fullpageurl : $event->pageurl.'.php';
405  $tmpevent['author'] = $event->author_alias ? $event->author_alias : 'unknown';
406  //$tmpevent['category'] = '';
407  $tmpevent['desc'] = $event->description;
408 
409  $event = $tmpevent;
410  }
411 
412  $uid = $event["uid"];
413  $startdate = $event["startdate"];
414  $summary = $event["summary"];
415  $url = $event["url"];
416  $author = $event["author"];
417  $category = $event["category"];
418 
419  /* No place inside a RSS
420  $priority = $event["priority"];
421  $fulldayevent = $event["fulldayevent"];
422  $location = $event["location"];
423  $email = $event["email"];
424  */
425 
426  $description = dol_string_nohtmltag(preg_replace("/<br[\s\/]?>/i", "\n", $event["desc"]), 0);
427 
428  fwrite($fichier, "<item>\n");
429  fwrite($fichier, "<title><![CDATA[".$summary."]]></title>\n");
430  fwrite($fichier, "<link><![CDATA[".$url."]]></link>\n");
431  fwrite($fichier, "<author><![CDATA[".$author."]]></author>\n");
432  fwrite($fichier, "<category><![CDATA[".$category."]]></category>\n");
433  fwrite($fichier, "<description><![CDATA[");
434 
435  if ($description)
436  fwrite($fichier, $description);
437  // else
438  // fwrite($fichier, "NoDesc");
439 
440  fwrite($fichier, "]]></description>\n");
441  fwrite($fichier, "<pubDate>".date("r", $startdate)."</pubDate>\n");
442  fwrite($fichier, "<guid isPermaLink=\"true\"><![CDATA[".$uid."]]></guid>\n");
443  fwrite($fichier, "<source><![CDATA[Dolibarr]]></source>\n");
444  fwrite($fichier, "</item>\n");
445  }
446  }
447 
448  fwrite($fichier, "</channel>");
449  fwrite($fichier, "\n");
450  fwrite($fichier, "</rss>");
451 
452  fclose($fichier);
453 
454  if (!empty($conf->global->MAIN_UMASK))
455  {
456  @chmod($outputfile, octdec($conf->global->MAIN_UMASK));
457  }
458  }
459 }
460 
468 function format_cal($format, $string)
469 {
470  global $conf;
471 
472  $newstring = $string;
473 
474  if ($format === "vcal")
475  {
476  $newstring = quotedPrintEncode($newstring);
477  }
478 
479  if ($format === "ical")
480  {
481  // Replace new lines chars by "\n"
482  $newstring = preg_replace("/\r\n/i", "\\n", $newstring);
483  $newstring = preg_replace("/\n\r/i", "\\n", $newstring);
484  $newstring = preg_replace("/\n/i", "\\n", $newstring);
485 
486  // Must not exceed 75 char. Cut with "\r\n"+Space
487  $newstring = calEncode($newstring);
488  }
489 
490  return $newstring;
491 }
492 
500 function calEncode($line)
501 {
502  $out = "";
503  $newpara = "";
504 
505  // If mb_ functions exists, it"s better to use them
506  if (function_exists("mb_strlen"))
507  {
508  $strlength = mb_strlen($line, "UTF-8");
509 
510  for ($j = 0; $j < $strlength; $j++)
511  {
512  // Take char at position $j
513  $char = mb_substr($line, $j, 1, "UTF-8");
514 
515  if ((mb_strlen($newpara, "UTF-8") + mb_strlen($char, "UTF-8")) >= 75)
516  {
517  // CRLF + Space for cal
518  $out .= $newpara."\r\n ";
519 
520  $newpara = "";
521  }
522 
523  $newpara .= $char;
524  }
525 
526  $out .= $newpara;
527  } else {
528  $strlength = dol_strlen($line);
529 
530  for ($j = 0; $j < $strlength; $j++)
531  {
532  // Take char at position $j
533  $char = substr($line, $j, 1);
534 
535  if ((dol_strlen($newpara) + dol_strlen($char)) >= 75)
536  {
537  // CRLF + Space for cal
538  $out .= $newpara."\r\n ";
539 
540  $newpara = "";
541  }
542 
543  $newpara .= $char;
544  }
545 
546  $out .= $newpara;
547  }
548 
549  return trim($out);
550 }
551 
552 
560 function quotedPrintEncode($str, $forcal = 0)
561 {
562  $lines = preg_split("/\r\n/", $str);
563  $out = "";
564 
565  foreach ($lines as $line)
566  {
567  $newpara = "";
568 
569  // Do not use dol_strlen here, we need number of bytes
570  $strlength = strlen($line);
571 
572  for ($j = 0; $j < $strlength; $j++)
573  {
574  $char = substr($line, $j, 1);
575  $ascii = ord($char);
576 
577  if ($ascii < 32 || $ascii === 61 || $ascii > 126)
578  {
579  $char = "=".strtoupper(sprintf("%02X", $ascii));
580  }
581 
582  // Do not use dol_strlen here, we need number of bytes
583  if ((strlen($newpara) + strlen($char)) >= 76)
584  {
585  // New line with carray-return (CR) and line-feed (LF)
586  $out .= $newpara."=\r\n";
587 
588  // extra space for cal
589  if ($forcal)
590  $out .= " ";
591 
592  $newpara = "";
593  }
594 
595  $newpara .= $char;
596  }
597 
598  $out .= $newpara;
599  }
600  return trim($out);
601 }
602 
609 function quotedPrintDecode($str)
610 {
611  return trim(quoted_printable_decode(preg_replace("/=\r?\n/", "", $str)));
612 }
dol_string_nohtmltag($stringtoclean, $removelinefeed=1, $pagecodeto= 'UTF-8', $strip_tags=0, $removedoublespaces=1)
Clean a string from all HTML tags and entities.
quotedPrintEncode($str, $forcal=0)
Encode into vcal format.
Definition: xcal.lib.php:560
dol_now($mode= 'auto')
Return date for now.
build_calfile($format, $title, $desc, $events_array, $outputfile)
Build a file from an array of events All input params and data must be encoded in $conf-&gt;charset_outp...
Definition: xcal.lib.php:35
quotedPrintDecode($str)
Decode vcal format.
Definition: xcal.lib.php:609
build_rssfile($format, $title, $desc, $events_array, $outputfile, $filter= '', $url= '', $langcode= '')
Build a file from an array of events.
Definition: xcal.lib.php:336
dol_strlen($string, $stringencoding= 'UTF-8')
Make a strlen call.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
calEncode($line)
Cut string after 75 chars.
Definition: xcal.lib.php:500
dol_print_date($time, $format= '', $tzoutput= 'auto', $outputlangs= '', $encodetooutput=false)
Output date in a string format according to outputlangs (or langs if not defined).
format_cal($format, $string)
Encode for cal export.
Definition: xcal.lib.php:468
dol_time_plus_duree($time, $duration_value, $duration_unit)
Add a delay to a date.
Definition: date.lib.php:114
convertSecondToTime($iSecond, $format= 'all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition: date.lib.php:180