forked from Wavyzz/dolibarr
* Qual: Spelling fixes that newly appeared. # Qual: Fix spelling erros that appeared since the bulk updates. These issues mostly appeared since the bulk updates (a few ones were postponed to make sure no real spelling errors were missed.) * Update modulebuilder.lib.php * Update pdf_standard.modules.php --------- Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
486 lines
13 KiB
PHP
486 lines
13 KiB
PHP
<?php
|
|
/* Copyright (C) 2006 Roman Ozana <ozana@omdesign.cz>
|
|
* Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
|
|
* Copyright (C) 2013-2014 Laurent Destailleur <eldy@users.sourceforge.net>
|
|
* Copyright (C) 2012 Regis Houssin <regis.houssin@inodbox.com>
|
|
* Copyright (C) 2019 Frédéric France <frederic.france@netlogic.fr>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* \file htdocs/comm/action/class/ical.class.php
|
|
* \ingroup agenda
|
|
* \brief File of class to parse ical calendars
|
|
*/
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/xcal.lib.php';
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
|
|
|
|
|
|
/**
|
|
* Class to read/parse ICal calendars
|
|
*/
|
|
class ICal
|
|
{
|
|
/**
|
|
* @var string Name of remote HTTP file to read
|
|
*/
|
|
public $file;
|
|
|
|
// Text in file
|
|
public $file_text;
|
|
public $cal; // Array to save iCalendar parse data
|
|
public $event_count; // Number of Events
|
|
public $todo_count; // Number of Todos
|
|
public $freebusy_count; // Number of Freebusy
|
|
public $last_key; //Help variable save last key (multiline string)
|
|
public $error;
|
|
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct()
|
|
{
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Read text file, icalender text file
|
|
*
|
|
* @param string $file File
|
|
* @return string|null Content of remote file read or null if error
|
|
*/
|
|
public function read_file($file)
|
|
{
|
|
// phpcs:enable
|
|
$this->file = $file;
|
|
$file_text = '';
|
|
|
|
$tmpresult = getURLContent($file, 'GET');
|
|
if ($tmpresult['http_code'] != 200) {
|
|
$file_text = null;
|
|
$this->error = 'Error: '.$tmpresult['http_code'].' '.$tmpresult['content'];
|
|
} else {
|
|
$file_text = preg_replace("/[\r\n]{1,} /", "", $tmpresult['content']);
|
|
}
|
|
//var_dump($tmpresult);
|
|
|
|
return $file_text; // return all text
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Returns the number of calendar events
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_event_count()
|
|
{
|
|
// phpcs:enable
|
|
return $this->event_count;
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Returns the number of to do
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_todo_count()
|
|
{
|
|
// phpcs:enable
|
|
return $this->todo_count;
|
|
}
|
|
|
|
/**
|
|
* Translate Calendar
|
|
*
|
|
* @param string $uri Url
|
|
* @param string $usecachefile Full path of a cache file to use a cache file
|
|
* @param int $delaycache Delay in seconds for cache (by default 3600 secondes)
|
|
* @return array|string
|
|
*/
|
|
public function parse($uri, $usecachefile = '', $delaycache = 3600)
|
|
{
|
|
$this->cal = array(); // new empty array
|
|
|
|
$this->event_count = -1;
|
|
$this->file_text = null;
|
|
|
|
// Save file into a cache
|
|
if ($usecachefile) {
|
|
include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php';
|
|
$datefile = dol_filemtime($usecachefile);
|
|
$now = dol_now('gmt');
|
|
//print $datefile.' '.$now.' ...';
|
|
if ($datefile && $datefile > ($now - $delaycache)) {
|
|
// We reuse the cache file
|
|
$this->file_text = file_get_contents($usecachefile);
|
|
}
|
|
}
|
|
|
|
// read FILE text
|
|
if (is_null($this->file_text)) {
|
|
$this->file_text = $this->read_file($uri);
|
|
|
|
if ($usecachefile && !is_null($this->file_text)) {
|
|
// Save the file content into cache file
|
|
file_put_contents($usecachefile, $this->file_text, LOCK_EX);
|
|
dolChmod($usecachefile);
|
|
}
|
|
}
|
|
|
|
$this->file_text = preg_split("[\n]", $this->file_text);
|
|
|
|
// is this text vcalendar standard text ? on line 1 is BEGIN:VCALENDAR
|
|
if (!stristr($this->file_text[0], 'BEGIN:VCALENDAR')) {
|
|
return 'error not VCALENDAR';
|
|
}
|
|
|
|
$insidealarm = 0;
|
|
$tmpkey = '';
|
|
$tmpvalue = '';
|
|
$type = '';
|
|
foreach ($this->file_text as $text) {
|
|
$text = trim($text); // trim one line
|
|
if (!empty($text)) {
|
|
// get Key and Value VCALENDAR:Begin -> Key = VCALENDAR, Value = begin
|
|
list($key, $value) = $this->retun_key_value($text);
|
|
//var_dump($text.' -> '.$key.' - '.$value);
|
|
|
|
switch ($text) { // search special string
|
|
case "BEGIN:VTODO":
|
|
$this->todo_count = $this->todo_count + 1; // new to do begin
|
|
$type = "VTODO";
|
|
break;
|
|
|
|
case "BEGIN:VEVENT":
|
|
$this->event_count = $this->event_count + 1; // new event begin
|
|
$type = "VEVENT";
|
|
break;
|
|
|
|
case "BEGIN:VFREEBUSY":
|
|
$this->freebusy_count = $this->freebusy_count + 1; // new event begin
|
|
$type = "VFREEBUSY";
|
|
break;
|
|
|
|
case "BEGIN:VCALENDAR": // all other special string
|
|
case "BEGIN:DAYLIGHT":
|
|
case "BEGIN:VTIMEZONE":
|
|
case "BEGIN:STANDARD":
|
|
$type = $value; // save array under value key
|
|
break;
|
|
|
|
case "END:VTODO": // end special text - goto VCALENDAR key
|
|
case "END:VEVENT":
|
|
case "END:VFREEBUSY":
|
|
case "END:VCALENDAR":
|
|
case "END:DAYLIGHT":
|
|
case "END:VTIMEZONE":
|
|
case "END:STANDARD":
|
|
$type = "VCALENDAR";
|
|
break;
|
|
|
|
// Manage VALARM that are inside a VEVENT to avoid fields of VALARM to overwrites fields of VEVENT
|
|
case "BEGIN:VALARM":
|
|
$insidealarm = 1;
|
|
break;
|
|
case "END:VALARM":
|
|
$insidealarm = 0;
|
|
break;
|
|
|
|
default: // no special string (SUMMARY, DESCRIPTION, ...)
|
|
if ($tmpvalue) {
|
|
$tmpvalue .= $text;
|
|
if (!preg_match('/=$/', $text)) { // No more lines
|
|
$key = $tmpkey;
|
|
$value = quotedPrintDecode(preg_replace('/^ENCODING=QUOTED-PRINTABLE:/i', '', $tmpvalue));
|
|
$tmpkey = '';
|
|
$tmpvalue = '';
|
|
}
|
|
} elseif (preg_match('/^ENCODING=QUOTED-PRINTABLE:/i', $value)) {
|
|
if (preg_match('/=$/', $value)) {
|
|
$tmpkey = $key;
|
|
$tmpvalue = $tmpvalue.preg_replace('/=$/', "", $value); // We must wait to have next line to have complete message
|
|
} else {
|
|
$value = quotedPrintDecode(preg_replace('/^ENCODING=QUOTED-PRINTABLE:/i', '', $tmpvalue.$value));
|
|
}
|
|
} //$value=quotedPrintDecode($tmpvalue.$value);
|
|
if (!$insidealarm && !$tmpkey) {
|
|
$this->add_to_array($type, $key, $value); // add to array
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//var_dump($this->cal);
|
|
return $this->cal;
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Add to $this->ical array one value and key.
|
|
*
|
|
* @param string $type Type ('VTODO', 'VEVENT', 'VFREEBUSY', 'VCALENDAR'...)
|
|
* @param string $key Key ('DTSTART', ...). Note: Field is never 'DTSTART;TZID=...' because ';...' was before removed and added as another property
|
|
* @param string $value Value
|
|
* @return void
|
|
*/
|
|
public function add_to_array($type, $key, $value)
|
|
{
|
|
// phpcs:enable
|
|
|
|
//print 'type='.$type.' key='.$key.' value='.$value.'<br>'."\n";
|
|
|
|
if (empty($key)) {
|
|
$key = $this->last_key;
|
|
switch ($type) {
|
|
case 'VEVENT':
|
|
$value = $this->cal[$type][$this->event_count][$key].$value;
|
|
break;
|
|
case 'VFREEBUSY':
|
|
$value = $this->cal[$type][$this->freebusy_count][$key].$value;
|
|
break;
|
|
case 'VTODO':
|
|
$value = $this->cal[$type][$this->todo_count][$key].$value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (($key == "DTSTAMP") || ($key == "LAST-MODIFIED") || ($key == "CREATED")) {
|
|
$value = $this->ical_date_to_unix($value);
|
|
}
|
|
//if ($key == "RRULE" ) $value = $this->ical_rrule($value);
|
|
|
|
if (stristr($key, "DTSTART") || stristr($key, "DTEND") || stristr($key, "DTSTART;VALUE=DATE") || stristr($key, "DTEND;VALUE=DATE")) {
|
|
if (stristr($key, "DTSTART;VALUE=DATE") || stristr($key, "DTEND;VALUE=DATE")) {
|
|
list($key, $value) = array($key, $value);
|
|
} else {
|
|
list($key, $value) = $this->ical_dt_date($key, $value);
|
|
}
|
|
}
|
|
|
|
switch ($type) {
|
|
case "VTODO":
|
|
$this->cal[$type][$this->todo_count][$key] = $value;
|
|
break;
|
|
|
|
case "VEVENT":
|
|
$this->cal[$type][$this->event_count][$key] = $value;
|
|
break;
|
|
|
|
case "VFREEBUSY":
|
|
$this->cal[$type][$this->freebusy_count][$key] = $value;
|
|
break;
|
|
|
|
default:
|
|
$this->cal[$type][$key] = $value;
|
|
break;
|
|
}
|
|
$this->last_key = $key;
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Parse text "XXXX:value text some with : " and return array($key = "XXXX", $value="value");
|
|
*
|
|
* @param string $text Text
|
|
* @return array
|
|
*/
|
|
public function retun_key_value($text)
|
|
{
|
|
// phpcs:enable
|
|
/*
|
|
preg_match("/([^:]+)[:]([\w\W]+)/", $text, $matches);
|
|
|
|
if (empty($matches))
|
|
{
|
|
return array(false,$text);
|
|
}
|
|
else
|
|
{
|
|
$matches = array_splice($matches, 1, 2);
|
|
return $matches;
|
|
}*/
|
|
return explode(':', $text, 2);
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Parse RRULE return array
|
|
*
|
|
* @param string $value string
|
|
* @return array
|
|
*/
|
|
public function ical_rrule($value)
|
|
{
|
|
// phpcs:enable
|
|
$result = array();
|
|
$rrule = explode(';', $value);
|
|
foreach ($rrule as $line) {
|
|
$rcontent = explode('=', $line);
|
|
$result[$rcontent[0]] = $rcontent[1];
|
|
}
|
|
return $result;
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Return Unix time from ical date time format (YYYYMMDD[T]HHMMSS[Z] or YYYYMMDD[T]HHMMSS)
|
|
*
|
|
* @param string $ical_date String date
|
|
* @return int
|
|
*/
|
|
public function ical_date_to_unix($ical_date)
|
|
{
|
|
// phpcs:enable
|
|
$ical_date = str_replace('T', '', $ical_date);
|
|
$ical_date = str_replace('Z', '', $ical_date);
|
|
|
|
$ntime = 0;
|
|
// TIME LIMITED EVENT
|
|
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)) {
|
|
$ntime = dol_mktime($date[4], $date[5], $date[6], $date[2], $date[3], $date[1], true);
|
|
}
|
|
|
|
//if (empty($date[4])) print 'Error bad date: '.$ical_date.' - date1='.$date[1];
|
|
//print dol_print_date($ntime,'dayhour');exit;
|
|
return $ntime; // ntime is a GTM time
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Return unix date from iCal date format
|
|
*
|
|
* @param string $key Key
|
|
* @param string $value Value
|
|
* @return array
|
|
*/
|
|
public function ical_dt_date($key, $value)
|
|
{
|
|
// phpcs:enable
|
|
$return_value = array();
|
|
$value = $this->ical_date_to_unix($value);
|
|
|
|
// Analyse TZID
|
|
$temp = explode(";", $key);
|
|
|
|
if (empty($temp[1])) { // not TZID
|
|
$value = str_replace('T', '', $value);
|
|
return array($key, $value);
|
|
}
|
|
|
|
$key = $temp[0];
|
|
$temp = explode("=", $temp[1]);
|
|
$return_value[$temp[0]] = $temp[1];
|
|
$return_value['unixtime'] = $value;
|
|
|
|
return array($key, $return_value);
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Return sorted eventlist as array or false if calendar is empty
|
|
*
|
|
* @return array|false
|
|
*/
|
|
public function get_sort_event_list()
|
|
{
|
|
// phpcs:enable
|
|
$temp = $this->get_event_list();
|
|
if (!empty($temp)) {
|
|
usort($temp, array(&$this, "ical_dtstart_compare"));
|
|
return $temp;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Compare two unix timestamp
|
|
*
|
|
* @param array $a Operand a
|
|
* @param array $b Operand b
|
|
* @return integer
|
|
*/
|
|
public function ical_dtstart_compare($a, $b)
|
|
{
|
|
// phpcs:enable
|
|
return strnatcasecmp($a['DTSTART']['unixtime'], $b['DTSTART']['unixtime']);
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Return eventlist array (not sorted eventlist array)
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_event_list()
|
|
{
|
|
// phpcs:enable
|
|
return (empty($this->cal['VEVENT']) ? array() : $this->cal['VEVENT']);
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Return freebusy array (not sort eventlist array)
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_freebusy_list()
|
|
{
|
|
// phpcs:enable
|
|
return (empty($this->cal['VFREEBUSY']) ? array() : $this->cal['VFREEBUSY']);
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Return to do array (not sorted todo array)
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_todo_list()
|
|
{
|
|
// phpcs:enable
|
|
return $this->cal['VTODO'];
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Return base calendar data
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_calender_data()
|
|
{
|
|
// phpcs:enable
|
|
return $this->cal['VCALENDAR'];
|
|
}
|
|
|
|
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
|
|
/**
|
|
* Return array with all data
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_all_data()
|
|
{
|
|
// phpcs:enable
|
|
return $this->cal;
|
|
}
|
|
}
|