<?php /*********************************************************************************/ /** * iCalcreator class v2.6 * copyright (c) 2007-2008 Kjell-Inge Gustafsson kigkonsult * www.kigkonsult.se/iCalcreator/index.php * ical@kigkonsult.se * * Description: * This file is a PHP implementation of RFC 2445. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /*********************************************************************************/ /*********************************************************************************/ /* A little setup */ /*********************************************************************************/ /* your local language code */ // define( 'ICAL_LANG', 'sv' ); // alt. autosetting /* $langstr = $_SERVER['HTTP_ACCEPT_LANGUAGE']; $pos = strpos( $langstr, ';' ); if ($pos !== false) { $langstr = substr( $langstr, 0, $pos ); $pos = strpos( $langstr, ',' ); if ($pos !== false) { $pos = strpos( $langstr, ',' ); $langstr = substr( $langstr, 0, $pos ); } define( 'ICAL_LANG', $langstr ); } */ /* only for phpversion 5.x, date management, default timezone setting */ if (substr(phpversion(), 0, 1) >= '5') // && ( 'UTC' == date_default_timezone_get() )) { date_default_timezone_set('Europe/Stockholm'); /* version string, do NOT remove!! */ define('ICALCREATOR_VERSION', 'iCalcreator 2.6'); /*********************************************************************************/ /*********************************************************************************/ /** * vcalendar class * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.13 - 2007-12-30 */ class vcalendar { // calendar property variables var $calscale; var $method; var $prodid; var $version; var $xprop; // container for calendar components var $components; // component config variables var $allowEmpty; var $unique_id; var $language; var $directory; var $filename; var $url; var $delimiter; var $nl; var $format; // component internal variables var $attributeDelimiter; var $valueInit; // component xCal declaration container var $xcaldecl; /* * constructor for calendar object * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.13 - 2007-12-30 * @return void */ function vcalendar() { $this->_makeVersion(); $this->calscale = null; $this->method = null; $this->_makeUnique_id(); $this->prodid = null; $this->xprop = array(); /** * language = <Text identifying a language, as defined in [RFC 1766]> */ if (defined('ICAL_LANG')) $this->setConfig('language', ICAL_LANG); $this->setConfig('allowEmpty', TRUE); $this->setConfig('nl', "\n"); $this->setConfig('format', 'iCal'); $this->directory = null; $this->filename = null; $this->url = null; $this->setConfig('delimiter', DIRECTORY_SEPARATOR); $this->xcaldecl = array(); $this->components = array(); } /*********************************************************************************/ /** * Property Name: CALSCALE */ /** * creates formatted output for calendar property calscale * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createCalscale() { if (empty($this->calscale)) return FALSE; switch ($this->format) { case 'xcal': return ' calscale="' . $this->calscale . '"' . $this->nl; break; default: return 'CALSCALE:' . $this->calscale . $this->nl; break; } } /** * set calendar property calscale * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @param string $value * @return void */ function setCalscale($value) { if (empty($value)) return FALSE; $this->calscale = $value; } /*********************************************************************************/ /** * Property Name: METHOD */ /** * creates formatted output for calendar property method * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.7 - 2006-11-20 * @return string */ function createMethod() { if (empty($this->method)) return FALSE; switch ($this->format) { case 'xcal': return ' method="' . $this->method . '"' . $this->nl; break; default: return 'METHOD:' . $this->method . $this->nl; break; } } /** * set calendar property method * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-20-23 * @param string $value * @return bool */ function setMethod($value) { if (empty($value)) return FALSE; $this->method = $value; return TRUE; } /*********************************************************************************/ /** * Property Name: PRODID * * The identifier is RECOMMENDED to be the identical syntax to the * [RFC 822] addr-spec. A good method to assure uniqueness is to put the * domain name or a domain literal IP address of the host on which.. . */ /** * creates formatted output for calendar property prodid * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.7 - 2006-11-20 * @return string */ function createProdid() { if (!isset($this->prodid)) $this->_makeProdid(); switch ($this->format) { case 'xcal': return ' prodid="' . $this->prodid . '"' . $this->nl; break; default: return 'PRODID:' . $this->prodid . $this->nl; break; } } /** * make default value for calendar prodid * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.3.0 - 2006-08-10 * @return void */ function _makeProdid() { $this->prodid = '-//' . $this->unique_id . '//NONSGML ' . ICALCREATOR_VERSION . '//' . strtoupper($this->language); } /** * Conformance: The property MUST be specified once in an iCalendar object. * Description: The vendor of the implementation SHOULD assure that this * is a globally unique identifier; using some technique such as an FPI * value, as defined in [ISO 9070]. */ /** * make default unique_id for calendar prodid * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.3.0 - 2006-08-10 * @return void */ function _makeUnique_id() { $this->unique_id = (isset($_SERVER['SERVER_NAME'])) ? gethostbyname($_SERVER['SERVER_NAME']) : 'localhost'; } /*********************************************************************************/ /** * Property Name: VERSION * * Description: A value of "2.0" corresponds to this memo. */ /** * creates formatted output for calendar property version * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.7 - 2006-11-20 * @return string */ function createVersion() { if (empty($this->version)) $this->_makeVersion(); switch ($this->format) { case 'xcal': return ' version="' . $this->version . '"' . $this->nl; break; default: return 'VERSION:' . $this->version . $this->nl; break; } } /** * set default calendar version * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.3.0 - 2006-08-10 * @return void */ function _makeVersion() { $this->version = '2.0'; } /** * set calendar version * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @param string $value * @return void */ function setVersion($value) { if (empty($value)) return FALSE; $this->version = $value; return TRUE; } /*********************************************************************************/ /** * Property Name: x-prop */ /** * creates formatted output for calendar property x-prop, iCal format only * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.11 - 2008-11-03 * @return string */ function createXprop() { if ('xcal' == $this->format) return false; if (0 >= count($this->xprop)) return; $output = null; $toolbox = new calendarComponent(); $toolbox->setConfig('language', $this->getConfig('language')); $toolbox->setConfig('nl', $this->getConfig('nl')); $toolbox->_createFormat($this->getConfig('format')); foreach ($this->xprop as $label => $xpropPart) { if (empty($xpropPart['value'])) { $output .= $toolbox->_createElement($label); continue; } $attributes = $toolbox->_createParams($xpropPart['params'], array('LANGUAGE')); if (is_array($xpropPart['value'])) { foreach ($xpropPart['value'] as $pix => $theXpart) $xpropPart['value'][$pix] = $toolbox->_strrep($theXpart); $xpropPart['value'] = implode(',', $xpropPart['value']); } else $xpropPart['value'] = $toolbox->_strrep($xpropPart['value']); $output .= $toolbox->_createElement($label, $attributes, $xpropPart['value']); } return $output; } /** * set calendar property x-prop * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.11 - 2008-11-04 * @param string $label * @param string $value * @param array $params optional * @return bool */ function setXprop($label, $value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; if (empty($label)) return FALSE; $xprop = array('value' => $value); $toolbox = new calendarComponent(); $xprop['params'] = $toolbox->_setParams($params); if (!is_array($this->xprop)) $this->xprop = array(); $this->xprop[strtoupper($label)] = $xprop; return TRUE; } /*********************************************************************************/ /** * delete calendar property value * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.5 - 2008-11-14 * @param mixed $propName , bool FALSE => X-property * @param int @propix, optional, if specific property is wanted in case of multiply occurences * @return bool, if successfull delete */ function deleteProperty($propName, $propix = FALSE) { $propName = ($propName) ? strtoupper($propName) : 'X-PROP'; if (!$propix) $propix = (isset($this->propdelix[$propName])) ? $this->propdelix[$propName] + 2 : 1; $this->propdelix[$propName] = --$propix; $return = FALSE; switch ($propName) { case 'CALSCALE': if (isset($this->calscale)) { $this->calscale = null; $return = TRUE; } break; case 'METHOD': if (isset($this->method)) { $this->method = null; $return = TRUE; } break; default: $reduced = array(); if ($propName != 'X-PROP') { if (!isset($this->xprop[$propName])) return FALSE; foreach ($this->xprop as $k => $a) { if (($k != $propName) && !empty($a)) $reduced[$k] = $a; } } else { if (count($this->xprop) <= $propix) return FALSE; $xpropno = 0; foreach ($this->xprop as $xpropkey => $xpropvalue) { if ($propix != $xpropno) $reduced[$xpropkey] = $xpropvalue; $xpropno++; } } $this->xprop = $reduced; return TRUE; } return $return; } /** * get calendar property value/params * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-02 * @param string $propName , optional * @param int @propix, optional, if specific property is wanted in case of multiply occurences * @param bool $inclParam =FALSE * @return mixed */ function getProperty($propName = FALSE, $propix = FALSE, $inclParam = FALSE) { $propName = ($propName) ? strtoupper($propName) : 'X-PROP'; if ('X-PROP' == $propName) { if (!$propix) $propix = (isset($this->propix[$propName])) ? $this->propix[$propName] + 2 : 1; $this->propix[$propName] = --$propix; } switch ($propName) { case 'CALSCALE': return (!empty($this->calscale)) ? $this->calscale : null; break; case 'METHOD': return (!empty($this->method)) ? $this->method : null; break; case 'PRODID': if (empty($this->prodid)) $this->_makeProdid(); return $this->prodid; break; case 'VERSION': return (!empty($this->version)) ? $this->version : null; break; default: if ($propName != 'X-PROP') { if (!isset($this->xprop[$propName])) return FALSE; return ($inclParam) ? array($propName, $this->xprop[$propName]) : array($propName, $this->xprop[$propName]['value']); } else { if (empty($this->xprop)) return FALSE; $xpropno = 0; foreach ($this->xprop as $xpropkey => $xpropvalue) { if ($propix == $xpropno) return ($inclParam) ? array($xpropkey, $this->xprop[$xpropkey]) : array($xpropkey, $this->xprop[$xpropkey]['value']); else $xpropno++; } return FALSE; // not found ?? } } return FALSE; } /** * general vcalendar property setting * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.13 - 2007-11-04 * @param mixed $args variable number of function arguments, * first argument is ALWAYS component name, * second ALWAYS component value! * @return bool */ function setProperty() { $numargs = func_num_args(); if (1 > $numargs) return FALSE; $arglist = func_get_args(); $arglist[0] = strtoupper($arglist[0]); switch ($arglist[0]) { case 'CALSCALE': return $this->setCalscale($arglist[1]); case 'METHOD': return $this->setMethod($arglist[1]); case 'VERSION': return $this->setVersion($arglist[1]); default: if (!isset($arglist[1])) $arglist[1] = null; if (!isset($arglist[2])) $arglist[2] = null; return $this->setXprop($arglist[0], $arglist[1], $arglist[2]); } return FALSE; } /*********************************************************************************/ /** * get vcalendar config values or * calendar components * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.10 - 2008-10-23 * @param string $config * @return value */ function getConfig($config) { switch (strtoupper($config)) { case 'ALLOWEMPTY': return $this->allowEmpty; break; case 'COMPSINFO': unset($this->compix); $info = array(); foreach ($this->components as $cix => $component) { if (empty($component)) continue; unset($component->propix); $info[$cix]['ordno'] = $cix + 1; $info[$cix]['type'] = $component->objName; $info[$cix]['uid'] = $component->getProperty('uid'); $info[$cix]['props'] = $component->getConfig('propinfo'); $info[$cix]['sub'] = $component->getConfig('compsinfo'); unset($component->propix); } return $info; break; case 'DELIMITER': return $this->delimiter; break; case 'DIRECTORY': if (empty($this->directory)) $this->directory = '.'; return $this->directory; break; case 'DIRFILE': return $this->getConfig('directory') . $this->getConfig('delimiter') . $this->getConfig('filename'); break; case 'FILEINFO': return array($this->getConfig('directory') , $this->getConfig('filename') , $this->getConfig('filesize')); break; case 'FILENAME': if (empty($this->filename)) { if ('xcal' == $this->format) $this->filename = date('YmdHis') . '.xml'; // recommended xcs.. . else $this->filename = date('YmdHis') . '.ics'; } return $this->filename; break; case 'FILESIZE': $size = 0; if (empty($this->url)) { $dirfile = $this->getConfig('dirfile'); if (FALSE === ($size = filesize($dirfile))) $size = 0; clearstatcache(); } return $size; break; case 'FORMAT': return $this->format; break; case 'LANGUAGE': /* get language for calendar component as defined in [RFC 1766] */ return $this->language; break; case 'NL': case 'NEWLINECHAR': return $this->nl; break; case 'UNIQUE_ID': return $this->unique_id; break; case 'URL': if (!empty($this->url)) return $this->url; else return FALSE; break; } } /** * general vcalendar config setting * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-24 * @param string $config * @param string $value * @return void */ function setConfig($config, $value) { $res = FALSE; switch (strtoupper($config)) { case 'ALLOWEMPTY': $this->allowEmpty = $value; $subcfg = array('ALLOWEMPTY' => $value); $res = TRUE; break; case 'DELIMITER': $this->delimiter = $value; return TRUE; break; case 'DIRECTORY': $value = trim($value); $nl = $this->getConfig('delimiter'); if ($nl == substr($value, (0 - strlen($nl)))) $value = substr($value, 0, (strlen($value) - strlen($nl))); if (is_dir($value)) { /* local directory */ clearstatcache(); $this->directory = $value; $this->url = null; return TRUE; } else return FALSE; break; case 'FILENAME': $value = trim($value); if (!empty($this->url)) { /* remote directory+file - URL */ $this->filename = $value; return TRUE; } $dirfile = $this->getConfig('directory') . $this->getConfig('delimiter') . $value; if (file_exists($dirfile)) { /* local existing file */ if (is_readable($dirfile) || is_writable($dirfile)) { clearstatcache(); $this->filename = $value; return TRUE; } else return FALSE; } elseif (FALSE !== touch($dirfile)) { /* new local file created */ $this->filename = $value; return TRUE; } else return FALSE; break; case 'FORMAT': $value = trim($value); if ('xcal' == strtolower($value)) { $this->format = 'xcal'; $this->attributeDelimiter = $this->nl; $this->valueInit = null; } else { $this->format = null; $this->attributeDelimiter = ';'; $this->valueInit = ':'; } $subcfg = array('FORMAT' => $value); $res = TRUE; break; case 'LANGUAGE': // set language for calendar component as defined in [RFC 1766] $value = trim($value); $this->language = $value; $subcfg = array('LANGUAGE' => $value); $res = TRUE; break; case 'NL': case 'NEWLINECHAR': $this->nl = $value; $subcfg = array('NL' => $value); $res = TRUE; break; case 'UNIQUE_ID': $value = trim($value); $this->unique_id = $value; $subcfg = array('UNIQUE_ID' => $value); $res = TRUE; break; case 'URL': /* remote file - URL */ $value = trim($value); $value = str_replace('HTTP://', 'http://', $value); $value = str_replace('WEBCAL://', 'http://', $value); $value = str_replace('webcal://', 'http://', $value); $this->url = $value; $this->directory = null; $parts = pathinfo($value); return $this->setConfig('filename', $parts['basename']); break; } if (!$res) return FALSE; if (isset($subcfg) && !empty($this->components)) { foreach ($subcfg as $cfgkey => $cfgvalue) { foreach ($this->components as $cix => $component) { $res = $component->setConfig($cfgkey, $cfgvalue); if (!$res) break 2; $this->components[$cix] = $component->copy(); // PHP4 compliant } } } return $res; } /*********************************************************************************/ /** * add calendar component to container * * alias to setComponent * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 1.x.x - 2007-04-24 * @param object $component calendar component * @return void */ function addComponent($component) { $this->setComponent($component); } /** * delete calendar component from container * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.10 - 2008-08-05 * @param mixed $arg1 ordno / component type / component uid * @param mixed $arg2 optional, ordno if arg1 = component type * @return void */ function deleteComponent($arg1, $arg2 = FALSE) { $argType = $index = null; if (ctype_digit((string)$arg1)) { $argType = 'INDEX'; $index = (int)$arg1 - 1; } elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@'))) { $argType = strtolower($arg1); $index = (!empty($arg2) && ctype_digit((string)$arg2)) ? (( int )$arg2 - 1) : 0; } $cix1dC = 0; foreach ($this->components as $cix => $component) { if (empty($component)) continue; unset($component->propix); if (('INDEX' == $argType) && ($index == $cix)) { unset($this->components[$cix]); return TRUE; } elseif ($argType == $component->objName) { if ($index == $cix1dC) { unset($this->components[$cix]); return TRUE; } $cix1dC++; } elseif (!$argType && ($arg1 == $component->getProperty('uid'))) { unset($this->components[$cix]); return TRUE; } } return FALSE; } /** * get calendar component from container * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.10 - 2008-08-06 * @param mixed $arg1 optional, ordno/component type/ component uid * @param mixed $arg2 optional, ordno if arg1 = component type * @return object */ function getComponent($arg1 = FALSE, $arg2 = FALSE) { $index = $argType = null; if (!$arg1) { $argType = 'INDEX'; $index = $this->compix['INDEX'] = (isset($this->compix['INDEX'])) ? $this->compix['INDEX'] + 1 : 1; } elseif (ctype_digit((string)$arg1)) { $argType = 'INDEX'; $index = (int)$arg1; unset($this->compix); } elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@'))) { unset($this->compix['INDEX']); $argType = strtolower($arg1); if (!$arg2) $index = $this->compix[$argType] = (isset($this->compix[$argType])) ? $this->compix[$argType] + 1 : 1; else $index = (int)$arg2; } $index -= 1; $ckeys = array_keys($this->components); if (!empty($index) && ($index > end($ckeys))) return FALSE; $cix1gC = 0; foreach ($this->components as $cix => $component) { if (empty($component)) continue; unset($component->propix); if (('INDEX' == $argType) && ($index == $cix)) return $component->copy(); elseif ($argType == $component->objName) { if ($index == $cix1gC) return $component->copy(); $cix1gC++; } elseif (!$argType && ($arg1 == $component->getProperty('uid'))) { unset($component->propix); return $component->copy(); } } /* not found.. . */ unset($this->compix); return FALSE; } /** * select components from calendar on date basis * * Ensure DTSTART is set for every component. * No date controls occurs. * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-18 * @param int $startY optional, start Year, default current Year * @param int $startM optional, start Month, default current Month * @param int $startD optional, start Day, default current Day * @param int $endY optional, end Year, default $startY * @param int $endY optional, end Month, default $startM * @param int $endY optional, end Day, default $startD * @param mixed $cType optional, calendar component type(-s), default FALSE=all else string/array type(-s) * @param bool $flat optional, FALSE (default) => output : array[Year][Month][Day][] * TRUE => output : array[] (ignores split) * @param bool $any optional, TRUE (default) - select component that take place within period * FALSE - only components that starts within period * @param bool $split optional, TRUE (default) - one component copy every day it take place during the * period (implies flat=FALSE) * FALSE - one occurance of component only in output array</tr> * @return array or FALSE */ function selectComponents($startY = FALSE, $startM = FALSE, $startD = FALSE, $endY = FALSE, $endM = FALSE, $endD = FALSE, $cType = FALSE, $flat = FALSE, $any = TRUE, $split = TRUE) { /* check if empty calendar */ if (0 >= count($this->components)) return FALSE; /* check default dates */ if (!$startY) $startY = date('Y'); if (!$startM) $startM = date('m'); if (!$startD) $startD = date('d'); $startDate = mktime(0, 0, 0, $startM, $startD, $startY); if (!$endY) $endY = $startY; if (!$endM) $endM = $startM; if (!$endD) $endD = $startD; $endDate = mktime(23, 59, 59, $endM, $endD, $endY); /* check component types */ $validTypes = array('vevent', 'vtodo', 'vjournal', 'vfreebusy'); if (is_array($cType)) { foreach ($cType as $cix => $theType) { $cType[$cix] = $theType = strtolower($theType); if (!in_array($theType, $validTypes)) $cType[$cix] = 'vevent'; } $cType = array_unique($cType); } elseif (!empty($cType)) { $cType = strtolower($cType); if (!in_array($cType, $validTypes)) $cType = array('vevent'); else $cType = array($cType); } else $cType = $validTypes; if (0 >= count($cType)) $cType = $validTypes; /* iterate components */ $result = array(); foreach ($this->components as $cix => $component) { if (empty($component)) continue; unset($component->propix, $start); /* deselect unvalid type components */ if (!in_array($component->objName, $cType)) continue; /* deselect components without dtstart set */ if (FALSE === ($start = $component->getProperty('dtstart'))) continue; $dtendExist = $dueExist = $durationExist = $endAllDayEvent = FALSE; unset($end, $startWdate, $endWdate, $rdurWsecs, $rdur, $exdatelist, $workstart, $workend); // clean up $startWdate = $component->_date2timestamp($start); $startDateFormat = (isset($start['hour'])) ? 'Y-m-d H:i:s' : 'Y-m-d'; /* get end date from dtend/due/duration properties */ $end = $component->getProperty('dtend'); if (!empty($end)) { $dtendExist = TRUE; $endDateFormat = (isset($end['hour'])) ? 'Y-m-d H:i:s' : 'Y-m-d'; } // if( !empty($end)) echo 'selectComp 1 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ### if (empty($end) && ($component->objName == 'vtodo')) { $end = $component->getProperty('due'); if (!empty($end)) { $dueExist = TRUE; $endDateFormat = (isset($end['hour'])) ? 'Y-m-d H:i:s' : 'Y-m-d'; } // if( !empty($end)) echo 'selectComp 2 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ### } if (!empty($end) && !isset($end['hour'])) { /* a DTEND without time part regards an event that ends the day before, for an all-day event DTSTART=20071201 DTEND=20071202 (taking place 20071201!!! */ $endAllDayEvent = TRUE; $endWdate = mktime(23, 59, 59, $end['month'], ($end['day'] - 1), $end['year']); $end['year'] = date('Y', $endWdate); $end['month'] = date('m', $endWdate); $end['day'] = date('d', $endWdate); $end['hour'] = 23; $end['min'] = $end['sec'] = 59; // if( !empty($end)) echo 'selectComp 3 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ### } if (empty($end)) { $end = $component->getProperty('duration', FALSE, FALSE, TRUE);// in dtend (array) format if (!empty($end)) $durationExist = TRUE; // if( !empty($end)) echo 'selectComp 4 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ### } if (empty($end)) { // assume one day duration if missing end date $end = array('year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59); // if( isset($end)) echo 'selectComp 5 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ### } $endWdate = $component->_date2timestamp($end); if ($endWdate < $startWdate) { // MUST be after start date!! $end = array('year' => $start['year'], 'month' => $start['month'], 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59); $endWdate = $component->_date2timestamp($end); } $rdurWsecs = $endWdate - $startWdate; // compute component duration in seconds $rdur = $component->_date2duration($start, $end); // compute component duration, array /* make a list of optional exclude dates for component occurence from exrule and exdate */ $exdatelist = array(); $workstart = $component->_timestamp2date(($startDate - $rdurWsecs), 6); $workend = $component->_timestamp2date(($endDate + $rdurWsecs), 6); while (FALSE !== ($exrule = $component->getProperty('exrule'))) // check exrule $component->_recur2date($exdatelist, $exrule, $start, $workstart, $workend); while (FALSE !== ($exdate = $component->getProperty('exdate'))) { // check exdate foreach ($exdate as $theExdate) { $exWdate = $component->_date2timestamp($theExdate); if ((($startDate - $rdurWsecs) <= $exWdate) && ($endDate >= $exWdate)) $exdatelist[$exWdate] = TRUE; } } /* if 'any' components, check repeating components, removing all excluding dates */ if (TRUE === $any) { /* make a list of optional repeating dates for component occurence, rrule, rdate */ $recurlist = array(); while (FALSE !== ($rrule = $component->getProperty('rrule'))) // check rrule $component->_recur2date($recurlist, $rrule, $start, $workstart, $workend); foreach ($recurlist as $recurkey => $recurvalue) // key=match date as timestamp $recurlist[$recurkey] = $rdurWsecs; // add duration in seconds while (FALSE !== ($rdate = $component->getProperty('rdate'))) { // check rdate foreach ($rdate as $theRdate) { if (is_array($theRdate) && (2 == count($theRdate)) && // all days within PERIOD array_key_exists('0', $theRdate) && array_key_exists('1', $theRdate) ) { $rstart = $component->_date2timestamp($theRdate[0]); if (($rstart < ($startDate - $rdurWsecs)) || ($rstart > $endDate)) continue; if (isset($theRdate[1]['year'])) // date-date period $rend = $component->_date2timestamp($theRdate[1]); else { // date-duration period $rend = $component->duration2date($theRdate[0], $theRdate[1]); $rend = $component->_date2timestamp($rend); } if ((($startDate - $rdurWsecs) <= $rstart) && ($endDate >= $rstart)) $recurlist[$rstart] = ($rstart - $rend); // set start date + rdate duration in seconds } // PERIOD end else { // single date $theRdate = $component->_date2timestamp($theRdate); if ((($startDate - $rdurWsecs) <= $theRdate) && ($endDate >= $theRdate)) $recurlist[$theRdate] = $rdurWsecs; // set start date + event duration in seconds } } } if (0 < count($recurlist)) { ksort($recurlist); foreach ($recurlist as $recurkey => $durvalue) { if ((($startDate - $rdurWsecs) > $recurkey) || ($endDate < $recurkey)) // not within period continue; if (isset($exdatelist[$recurkey])) // check excluded dates continue; if ($startWdate >= $recurkey) // exclude component start date continue; $component2 = $component->copy(); $rstart = $component2->_timestamp2date($recurkey, 6); $datevalue = $rstart['month'] . '/' . $rstart['day'] . '/' . $rstart['year']; if (isset($start['hour']) || isset($start['min']) || isset($start['sec'])) { $datevalue .= (isset($rstart['hour'])) ? ' ' . $rstart['hour'] : ' 00'; $datevalue .= (isset($rstart['min'])) ? ':' . $rstart['min'] : ':00'; $datevalue .= (isset($rstart['sec'])) ? ':' . $rstart['sec'] : ':00'; } $datestring = date($startDateFormat, strtotime($datevalue)); if (isset($start['tz'])) $datestring .= ' ' . $start['tz']; $component2->setProperty('X-CURRENT-DTSTART', $datestring); $rend = $component2->_timestamp2date(($recurkey + $durvalue), 6); if ($dtendExist || $dueExist) { if ($endAllDayEvent) { $rend2 = mktime(0, 0, 0, $rend['month'], ($rend['day'] + 1), $rend['year']); $datevalue = date('m', $rend2) . '/' . date('d', $rend2) . '/' . date('Y', $rend2); } else { $datevalue = $rend['month'] . '/' . $rend['day'] . '/' . $rend['year']; if (isset($end['hour']) || isset($end['min']) || isset($end['sec'])) { $datevalue .= (isset($rend['hour'])) ? ' ' . $rend['hour'] : ' 00'; $datevalue .= (isset($rend['min'])) ? ':' . $rend['min'] : ':00'; $datevalue .= (isset($rend['sec'])) ? ':' . $rend['sec'] : ':00'; } } $datestring = date($endDateFormat, strtotime($datevalue)); if (isset($end['tz'])) $datestring .= ' ' . $end['tz']; if ($dtendExist) $component2->setProperty('X-CURRENT-DTEND', $datestring); elseif ($dueExist) $component2->setProperty('X-CURRENT-DUE', $datestring); } $rend = $component2->_date2timestamp($rend); $rstart = $recurkey; /* add repeating components within valid dates to output array, only start date */ if ($flat) $result[] = $component2->copy(); // copy to output elseif ($split) { if ($rend > $endDate) $rend = $endDate; while ($rstart <= $rend) { // iterate $wd = getdate($rstart); if (($rstart > $startDate) && // date after dtstart !isset($exdatelist[$rstart]) ) // check exclude date $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component2->copy(); // copy to output $rstart += (24 * 60 * 60); // step one day } } elseif (($rstart >= $startDate) && // date within period !isset($exdatelist[$rstart]) ) { // check exclude date $wd = getdate($rstart); $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component2->copy(); // copy to output } } } /* deselect components with startdate/enddate not within period */ if (($endWdate < $startDate) || ($startWdate > $endDate)) continue; } /* deselect components with startdate not within period */ elseif (($startWdate < $startDate) || ($startWdate > $endDate)) continue; /* add selected components within valid dates to output array */ if ($flat) $result[] = $component->copy(); // copy to output; elseif ($split) { if ($endWdate > $endDate) $endWdate = $endDate; // use period end date if (!isset($exdatelist[$startWdate])) { // check excluded dates if ($startWdate < $startDate) $startWdate = $startDate; // use period start date while ($startWdate <= $endWdate) { // iterate $wd = getdate($startWdate); $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component->copy(); // copy to output $startWdate += (24 * 60 * 60); // step one day } } } // use component date elseif (!isset($exdatelist[$startWdate]) && // check excluded dates ($startWdate >= $startDate) ) { // within period $wd = getdate($startWdate); $result[$wd['year']][$wd['mon']][$wd['mday']][] = $component->copy(); // copy to output } } if (0 >= count($result)) return FALSE; elseif (!$flat) { foreach ($result as $y => $yeararr) { foreach ($yeararr as $m => $montharr) { ksort($result[$y][$m]); } ksort($result[$y]); } ksort($result); } return $result; } /** * add calendar component to container * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.10 - 2008-08-06 * @param object $component calendar component * @param mixed $arg1 optional, ordno/component type/ component uid * @param mixed $arg2 optional, ordno if arg1 = component type * @return void */ function setComponent($component, $arg1 = FALSE, $arg2 = FALSE) { if ('' >= $component->getConfig('language')) $component->setConfig('language', $this->getConfig('language')); $component->setConfig('allowEmpty', $this->getConfig('allowEmpty')); $component->setConfig('nl', $this->getConfig('nl')); $component->setConfig('unique_id', $this->getConfig('unique_id')); $component->setConfig('format', $this->getConfig('format')); if (!in_array($component->objName, array('valarm', 'vtimezone'))) { unset($component->propix); /* make sure dtstamp and uid is set */ $dummy1 = $component->getProperty('dtstamp'); $dummy2 = $component->getProperty('uid'); } if (!$arg1) { $this->components[] = $component->copy(); return TRUE; } $argType = $index = null; if (ctype_digit((string)$arg1)) { $argType = 'INDEX'; $index = (int)$arg1 - 1; } elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@'))) { $argType = strtolower($arg1); $index = (ctype_digit((string)$arg2)) ? ((int)$arg2) - 1 : 0; } $cix1sC = 0; foreach ($this->components as $cix => $component2) { if (empty($component2)) continue; unset($component2->propix); if (('INDEX' == $argType) && ($index == $cix)) { $this->components[$cix] = $component->copy(); return TRUE; } elseif ($argType == $component2->objName) { if ($index == $cix1sC) { $this->components[$cix] = $component->copy(); return TRUE; } $cix1sC++; } elseif (!$argType && ($arg1 == $component2->getProperty('uid'))) { $this->components[$cix] = $component->copy(); return TRUE; } } /* not found.. . insert last in chain anyway .. .*/ $this->components[] = $component->copy(); return TRUE; } /** * sort iCal compoments, only local date sort * * ascending sort on properties (if exist) x-current-dtstart, dtstart, * x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.10 - 2008-09-24 * @return sort param * */ function sort() { if (is_array($this->components)) { $this->_sortkeys = array('year', 'month', 'day', 'hour', 'min', 'sec'); usort($this->components, array($this, '_cmpfcn')); } } function _cmpfcn($a, $b) { if (empty($a)) return -1; if (empty($b)) return 1; if ('vtimezone' == $a->objName) return -1; if ('vtimezone' == $b->objName) return 1; $astart = (isset($a->xprop['X-CURRENT-DTSTART']['value'])) ? $a->_date_time_string($a->xprop['X-CURRENT-DTSTART']['value']) : null; if (empty($astart) && isset($a->dtstart['value'])) $astart = &$a->dtstart['value']; $bstart = (isset($b->xprop['X-CURRENT-DTSTART']['value'])) ? $b->_date_time_string($b->xprop['X-CURRENT-DTSTART']['value']) : null; if (empty($bstart) && isset($b->dtstart['value'])) $bstart = &$b->dtstart['value']; if (empty($astart)) return -1; elseif (empty($bstart)) return 1; foreach ($this->_sortkeys as $key) { if (empty($astart[$key])) return -1; elseif (empty($bstart[$key])) return 1; if ($astart[$key] == $bstart[$key]) continue; if (((int)$astart[$key]) < ((int)$bstart[$key])) return -1; elseif (((int)$astart[$key]) > ((int)$bstart[$key])) return 1; } $c = (isset($a->xprop['X-CURRENT-DTEND']['value'])) ? $a->_date_time_string($a->xprop['X-CURRENT-DTEND']['value']) : null; if (empty($c) && !empty($a->dtend['value'])) $c = &$a->dtend['value']; if (empty($c) && isset($a->xprop['X-CURRENT-DUE']['value'])) $c = $a->_date_time_string($a->xprop['X-CURRENT-DUE']['value']); if (empty($c) && !empty($a->due['value'])) $c = &$a->due['value']; if (empty($c) && !empty($a->duration['value'])) $c = $a->duration2date(); $d = (isset($b->xprop['X-CURRENT-DTEND']['value'])) ? $b->_date_time_string($b->xprop['X-CURRENT-DTEND']['value']) : null; if (empty($d) && !empty($b->dtend['value'])) $d = &$b->dtend['value']; if (empty($d) && isset($b->xprop['X-CURRENT-DUE']['value'])) $d = $b->_date_time_string($b->xprop['X-CURRENT-DUE']['value']); if (empty($d) && !empty($b->due['value'])) $d = &$b->due['value']; if (empty($d) && !empty($b->duration['value'])) $d = $b->duration2date(); if (empty($c)) return -1; elseif (empty($d)) return 1; foreach ($this->_sortkeys as $key) { if (!isset($c[$key])) return -1; elseif (!isset($d[$key])) return 1; if ($c[$key] == $d[$key]) continue; if (((int)$c[$key]) < ((int)$d[$key])) return -1; elseif (((int)$c[$key]) > ((int)$d[$key])) return 1; } if (isset($a->created['value'])) $e = &$a->created['value']; else $e = &$a->dtstamp['value']; if (isset($b->created['value'])) $f = &$b->created['value']; else $f = &$b->dtstamp['value']; foreach ($this->_sortkeys as $key) { if (!isset($e[$key])) return -1; elseif (!isset($f[$key])) return 1; if ($e[$key] == $f[$key]) continue; if (((int)$e[$key]) < ((int)$f[$key])) return -1; elseif (((int)$e[$key]) > ((int)$f[$key])) return 1; } if (($a->uid['value']) < ($b->uid['value']) ) return -1; elseif (($a->uid['value']) > ($b->uid['value']) ) return 1; return 0; } /** * parse iCal file into vcalendar, components, properties and parameters * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.10 - 2008-08-06 * @param string $filename optional filname (incl. opt. directory/path) or URL * @return bool FALSE if error occurs during parsing * */ function parse($filename = FALSE) { if (!$filename) { /* directory/filename previous set via setConfig directory+filename / url */ if (FALSE === ($filename = $this->getConfig('url'))) $filename = $this->getConfig('dirfile'); } elseif (('http://' == strtolower(substr($filename, 0, 7))) || ('webcal://' == strtolower(substr($filename, 0, 9))) ) { /* remote file - URL */ $this->setConfig('URL', $filename); if (!$filename = $this->getConfig('url')) return FALSE; /* err 2 */ } else { /* local directory/filename */ $parts = pathinfo($filename); if (!empty($parts['dirname']) && ('.' != $parts['dirname'])) { if (!$this->setConfig('directory', $parts['dirname'])) return FALSE; /* err 3 */ } if (!$this->setConfig('filename', $parts['basename'])) return FALSE; /* err 4 */ } if ('http://' != substr($filename, 0, 7)) { /* local file error tests */ if (!is_file($filename)) /* err 5 */ return FALSE; if (!is_readable($filename)) return FALSE; /* err 6 */ if (!filesize($filename)) return FALSE; /* err 7 */ clearstatcache(); } /* READ FILE */ if (FALSE === ($rows = file($filename))) return FALSE; /* err 1 */ /* identify BEGIN:VCALENDAR, MUST be first row */ if ('BEGIN:VCALENDAR' != strtoupper(trim($rows[0]))) return FALSE; /* err 8 */ /* remove empty trailing lines */ while ('' == trim($rows[count($rows) - 1])) { unset($rows[count($rows) - 1]); $rows = array_values($rows); } /* identify ending END:VCALENDAR row */ if ('END:VCALENDAR' != strtoupper(trim($rows[count($rows) - 1]))) { return FALSE; /* err 9 */ } if (3 > count($rows)) return FALSE; /* err 10 */ $comp = $subcomp = null; $actcomp = &$this; $nl = $this->getConfig('nl'); $calsync = 0; /* identify components and update unparsed data within component */ foreach ($rows as $line) { if ('' == trim($line)) continue; if ($nl == substr($line, 0 - strlen($nl))) $line = substr($line, 0, (strlen($line) - strlen($nl))) . '\n'; if ('BEGIN:VCALENDAR' == strtoupper(substr($line, 0, 15))) { $calsync++; continue; } elseif ('END:VCALENDAR' == strtoupper(substr($line, 0, 13))) { $calsync--; continue; } elseif (1 != $calsync) return FALSE; /* err 20 */ if ('END:' == strtoupper(substr($line, 0, 4))) { if (null != $subcomp) { $comp->setComponent($subcomp); $subcomp = null; } else { $this->setComponent($comp); $comp = null; } $actcomp = null; continue; } // end - if ( 'END:' ==.. . elseif ('BEGIN:' == strtoupper(substr($line, 0, 6))) { $line = str_replace('\n', '', $line); $compname = trim(strtoupper(substr($line, 6))); if (null != $comp) { if ('VALARM' == $compname) $subcomp = new valarm(); elseif ('STANDARD' == $compname) $subcomp = new vtimezone('STANDARD'); elseif ('DAYLIGHT' == $compname) $subcomp = new vtimezone('DAYLIGHT'); else return FALSE; /* err 6 */ $actcomp = &$subcomp; } else { switch ($compname) { case 'VALARM': $comp = new valarm(); break; case 'VEVENT': $comp = new vevent(); break; case 'VFREEBUSY'; $comp = new vfreebusy(); break; case 'VJOURNAL': $comp = new vjournal(); break; case 'VTODO': $comp = new vtodo(); break; case 'VTIMEZONE': $comp = new vtimezone(); break; default: return FALSE; // err 7 break; } // end - switch $actcomp = &$comp; } continue; } // end - elsif ( 'BEGIN:'.. . /* update selected component with unparsed data */ $actcomp->unparsed[] = $line; } // end - foreach( rows.. . /* parse data for calendar (this) object */ if (is_array($this->unparsed) && (0 < count($this->unparsed))) { /* concatenate property values spread over several lines */ $lastix = -1; $propnames = array('calscale', 'method', 'prodid', 'version', 'x-'); $proprows = array(); foreach ($this->unparsed as $line) { $newProp = FALSE; foreach ($propnames as $propname) { if ($propname == strtolower(substr($line, 0, strlen($propname)))) { $newProp = TRUE; break; } } if ($newProp) { $newProp = FALSE; $lastix++; $proprows[$lastix] = $line; } else { /* remove line breaks */ if (('\n' == substr($proprows[$lastix], -2)) && (' ' == substr($line, 0, 1)) ) { $proprows[$lastix] = substr($proprows[$lastix], 0, strlen($proprows[$lastix]) - 2); $line = substr($line, 1); } $proprows[$lastix] .= $line; } } $toolbox = new calendarComponent(); foreach ($proprows as $line) { if ('\n' == substr($line, -2)) $line = substr($line, 0, strlen($line) - 2); /* get propname */ $cix = $propname = null; for ($cix = 0; $cix < strlen($line); $cix++) { if (in_array($line{$cix}, array(':', ';'))) break; else $propname .= $line{$cix}; } /* ignore version/prodid properties */ if (in_array(strtoupper($propname), array('VERSION', 'PRODID'))) continue; $line = substr($line, $cix); /* separate attributes from value */ $attr = array(); $attrix = -1; $strlen = strlen($line); for ($cix = 0; $cix < $strlen; $cix++) { if ((':' == $line{$cix}) && ('://' != substr($line, $cix, 3)) && ('mailto:' != strtolower(substr($line, $cix - 6, 7))) ) { $attrEnd = TRUE; if (($cix < ($strlen - 4)) && ctype_digit(substr($line, $cix + 1, 4)) ) { // an URI with a (4pos) portnr?? for ($c2ix = $cix; 3 < $c2ix; $c2ix--) { if ('://' == substr($line, $c2ix - 2, 3)) { $attrEnd = FALSE; break; // an URI with a portnr!! } } } if ($attrEnd) { $line = substr($line, $cix + 1); break; } } if (';' == $line{$cix}) $attr[++$attrix] = null; else $attr[$attrix] .= $line{$cix}; } /* make attributes in array format */ $propattr = array(); foreach ($attr as $attribute) { $attrsplit = explode('=', $attribute, 2); if (1 < count($attrsplit)) $propattr[$attrsplit[0]] = $attrsplit[1]; else $propattr[] = $attribute; } /* update Property */ if (FALSE !== strpos($line, ',')) { $content = explode(',', $line); $clen = count($content); for ($cix = 0; $cix < $clen; $cix++) { if ("\\" == substr($content[$cix], -1)) { $content[$cix] .= ',' . $content[$cix + 1]; unset($content[$cix + 1]); $cix++; } } if (1 < count($content)) { foreach ($content as $cix => $contentPart) $content[$cix] = $toolbox->_strunrep($contentPart); $this->setProperty($propname, $content, $propattr); continue; } else $line = reset($content); $line = $toolbox->_strunrep($line); } $this->setProperty($propname, trim($line), $propattr); } // end - foreach( $this->unparsed.. . } // end - if( is_array( $this->unparsed.. . /* parse Components */ if (is_array($this->components) && (0 < count($this->components))) { for ($six = 0; $six < count($this->components); $six++) { if (!empty($this->components[$six])) $this->components[$six]->parse(); } } else return FALSE; /* err 91 or something.. . */ return TRUE; } /*********************************************************************************/ /** * creates formatted output for calendar object instance * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.10 - 2008-08-06 * @return string */ function createCalendar() { $calendarInit1 = $calendarInit2 = $calendarxCaldecl = $calendarStart = $calendar = null; switch ($this->format) { case 'xcal': $calendarInit1 = '<?xml version="1.0" encoding="UTF-8"?>' . $this->nl . '<!DOCTYPE iCalendar PUBLIC "-//IETF//DTD XCAL/iCalendar XML//EN"' . $this->nl . '"http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt"'; $calendarInit2 = '>' . $this->nl; $calendarStart = '<vcalendar'; break; default: $calendarStart = 'BEGIN:VCALENDAR' . $this->nl; break; } $calendarStart .= $this->createCalscale(); $calendarStart .= $this->createMethod(); $calendarStart .= $this->createProdid(); $calendarStart .= $this->createVersion(); switch ($this->format) { case 'xcal': $nlstrlen = strlen($this->nl); if ($this->nl == substr($calendarStart, (0 - $nlstrlen))) $calendarStart = substr($calendarStart, 0, (strlen($calendarStart) - $nlstrlen)); $calendarStart .= '>' . $this->nl; break; default: break; } $calendar .= $this->createXprop(); foreach ($this->components as $component) { if (empty($component)) continue; if ('' >= $component->getConfig('language')) $component->setConfig('language', $this->getConfig('language')); $component->setConfig('allowEmpty', $this->getConfig('allowEmpty')); $component->setConfig('nl', $this->getConfig('nl')); $component->setConfig('unique_id', $this->getConfig('unique_id')); $component->setConfig('format', $this->getConfig('format')); $calendar .= $component->createComponent($this->xcaldecl); } if ((0 < count($this->xcaldecl)) && ('xcal' == $this->format)) { // xCal only $calendarInit1 .= $this->nl . '[' . $this->nl; $old_xcaldecl = array(); foreach ($this->xcaldecl as $declix => $declPart) { if ((0 < count($old_xcaldecl)) && (in_array($declPart['uri'], $old_xcaldecl['uri'])) && (in_array($declPart['external'], $old_xcaldecl['external'])) ) continue; // no duplicate uri and ext. references $calendarxCaldecl .= '<!'; foreach ($declPart as $declKey => $declValue) { switch ($declKey) { // index case 'xmldecl': // no 1 $calendarxCaldecl .= $declValue . ' '; break; case 'uri': // no 2 $calendarxCaldecl .= $declValue . ' '; $old_xcaldecl['uri'][] = $declValue; break; case 'ref': // no 3 $calendarxCaldecl .= $declValue . ' '; break; case 'external': // no 4 $calendarxCaldecl .= '"' . $declValue . '" '; $old_xcaldecl['external'][] = $declValue; break; case 'type': // no 5 $calendarxCaldecl .= $declValue . ' '; break; case 'type2': // no 6 $calendarxCaldecl .= $declValue; break; } } $calendarxCaldecl .= '>' . $this->nl; } $calendarInit2 = ']' . $calendarInit2; } switch ($this->format) { case 'xcal': $calendar .= '</vcalendar>' . $this->nl; break; default: $calendar .= 'END:VCALENDAR' . $this->nl; break; } return $calendarInit1 . $calendarxCaldecl . $calendarInit2 . $calendarStart . $calendar; } /** * a HTTP redirect header is sent with created, updated and/or parsed calendar * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.12 - 2007-10-23 * @return redirect */ function returnCalendar() { $filename = $this->getConfig('filename'); $output = $this->createCalendar(); $filesize = strlen($output); // if( headers_sent( $filename, $linenum )) // die( "Headers already sent in $filename on line $linenum\n" ); if ('xcal' == $this->format) header('Content-Type: application/calendar+xml; charset=utf-8'); else header('Content-Type: text/calendar; charset=utf-8'); header('Content-Length: ' . $filesize); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Cache-Control: max-age=10'); echo $output; die(); } /** * save content in a file * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.12 - 2007-12-30 * @param string $directory optional * @param string $filename optional * @param string $delimiter optional * @return bool */ function saveCalendar($directory = FALSE, $filename = FALSE, $delimiter = FALSE) { if ($directory) $this->setConfig('directory', $directory); if ($filename) $this->setConfig('filename', $filename); if ($delimiter && ($delimiter != DIRECTORY_SEPARATOR)) $this->setConfig('delimiter', $delimiter); if (FALSE === ($dirfile = $this->getConfig('url'))) $dirfile = $this->getConfig('dirfile'); $iCalFile = @fopen($dirfile, 'w'); if ($iCalFile) { if (FALSE === fwrite($iCalFile, $this->createCalendar())) return FALSE; fclose($iCalFile); return TRUE; } else return FALSE; } /** * if recent version of calendar file exists (default one hour), an HTTP redirect header is sent * else FALSE is returned * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.12 - 2007-10-28 * @param string $directory optional alt. int timeout * @param string $filename optional * @param string $delimiter optional * @param int timeout optional, default 3600 sec * @return redirect/FALSE */ function useCachedCalendar($directory = FALSE, $filename = FALSE, $delimiter = FALSE, $timeout = 3600) { if ($directory && ctype_digit((string)$directory) && !$filename) { $timeout = (int)$directory; $directory = FALSE; } if ($directory) $this->setConfig('directory', $directory); if ($filename) $this->setConfig('filename', $filename); if ($delimiter && ($delimiter != DIRECTORY_SEPARATOR)) $this->setConfig('delimiter', $delimiter); $filesize = $this->getConfig('filesize'); if (0 >= $filesize) return FALSE; $dirfile = $this->getConfig('dirfile'); if (time() - filemtime($dirfile) < $timeout) { clearstatcache(); $dirfile = $this->getConfig('dirfile'); $filename = $this->getConfig('filename'); // if( headers_sent( $filename, $linenum )) // die( "Headers already sent in $filename on line $linenum\n" ); if ('xcal' == $this->format) header('Content-Type: application/calendar+xml; charset=utf-8'); else header('Content-Type: text/calendar; charset=utf-8'); header('Content-Length: ' . $filesize); header('Content-Disposition: attachment; filename="' . $filename . '"'); header('Cache-Control: max-age=10'); $fp = @$fopen($dirfile, 'r'); if ($fp) { fpassthru($fp); fclose($fp); } die(); } else return FALSE; } } /*********************************************************************************/ /*********************************************************************************/ /** * abstract class for calendar components * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.19 - 2008-10-12 */ class calendarComponent { // component property variables var $uid; var $dtstamp; // component config variables var $allowEmpty; var $language; var $nl; var $unique_id; var $format; var $objName; // created automatically at instance creation // component internal variables var $componentStart1; var $componentStart2; var $componentEnd1; var $componentEnd2; var $elementStart1; var $elementStart2; var $elementEnd1; var $elementEnd2; var $intAttrDelimiter; var $attributeDelimiter; var $valueInit; // component xCal declaration container var $xcaldecl; /** * constructor for calendar component object * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.19 - 2008-10-23 */ function calendarComponent() { $this->objName = (isset($this->timezonetype)) ? strtolower($this->timezonetype) : get_class($this); $this->uid = array(); $this->dtstamp = array(); $this->language = null; $this->nl = null; $this->unique_id = null; $this->format = null; $this->allowEmpty = TRUE; $this->xcaldecl = array(); $this->_createFormat(); $this->_makeDtstamp(); } /*********************************************************************************/ /** * Property Name: ACTION */ /** * creates formatted output for calendar component property action * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createAction() { if (empty($this->action)) return FALSE; if (empty($this->action['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('ACTION') : FALSE; $attributes = $this->_createParams($this->action['params']); return $this->_createElement('ACTION', $attributes, $this->action['value']); } /** * set calendar component property action * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE" * @param mixed $params * @return bool */ function setAction($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->action = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: ATTACH */ /** * creates formatted output for calendar component property attach * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.7 - 2006-11-23 * @return string */ function createAttach() { if (empty($this->attach)) return FALSE; $output = null; foreach ($this->attach as $attachPart) { if (!empty($attachPart['value'])) { $attributes = $this->_createParams($attachPart['params']); $output .= $this->_createElement('ATTACH', $attributes, $attachPart['value']); } elseif ($this->getConfig('allowEmpty')) $output .= $this->_createElement('ATTACH'); } return $output; } /** * set calendar component property attach * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-06 * @param string $value * @param array $params , optional * @param integer $index , optional * @return bool */ function setAttach($value, $params = FALSE, $index = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->_setMval($this->attach, $value, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: ATTENDEE */ /** * creates formatted output for calendar component property attendee * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-09-23 * @return string */ function createAttendee() { if (empty($this->attendee)) return FALSE; $output = null; foreach ($this->attendee as $attendeePart) { // start foreach 1 if (empty($attendeePart['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('ATTENDEE'); continue; } $attendee1 = $attendee2 = $attendeeLANG = $attendeeCN = null; foreach ($attendeePart as $paramlabel => $paramvalue) { // start foreach 2 if ('value' == $paramlabel) $attendee2 .= 'MAILTO:' . $paramvalue; elseif (('params' == $paramlabel) && (is_array($paramvalue))) { // start elseif foreach ($paramvalue as $optparamlabel => $optparamvalue) { // start foreach 3 $attendee11 = $attendee12 = null; if (is_int($optparamlabel)) { $attendee1 .= $this->intAttrDelimiter . $optparamvalue; continue; } switch ($optparamlabel) { // start switch case 'CUTYPE': case 'PARTSTAT': case 'ROLE': case 'RSVP': $attendee1 .= $this->intAttrDelimiter . $optparamlabel . '="' . $optparamvalue . '"'; break; case 'SENT-BY': $attendee1 .= $this->intAttrDelimiter . 'SENT-BY="MAILTO:' . $optparamvalue . '"'; break; case 'MEMBER': $attendee11 = $this->intAttrDelimiter . 'MEMBER='; case 'DELEGATED-TO': $attendee11 = (!$attendee11) ? $this->intAttrDelimiter . 'DELEGATED-TO=' : $attendee11; case 'DELEGATED-FROM': $attendee11 = (!$attendee11) ? $this->intAttrDelimiter . 'DELEGATED-FROM=' : $attendee11; foreach ($optparamvalue as $cix => $calUserAddress) { $attendee12 .= ($cix) ? ',' : null; $attendee12 .= '"MAILTO:' . $calUserAddress . '"'; } $attendee1 .= $attendee11 . $attendee12; break; case 'CN': $attendeeCN .= $this->intAttrDelimiter . 'CN="' . $optparamvalue . '"'; break; case 'DIR': $attendee1 .= $this->intAttrDelimiter . 'DIR="' . $optparamvalue . '"'; break; case 'LANGUAGE': $attendeeLANG .= $this->intAttrDelimiter . 'LANGUAGE=' . $optparamvalue; break; default: $attendee1 .= $this->intAttrDelimiter . "$optparamlabel=$optparamvalue"; break; } // end switch } // end foreach 3 } // end elseif } // end foreach 2 $output .= $this->_createElement('ATTENDEE', $attendee1 . $attendeeLANG . $attendeeCN, $attendee2); } // end foreach 1 return $output; } /** * set calendar component property attach * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param string $value * @param array $params , optional * @param integer $index , optional * @return bool */ function setAttendee($value, $params = FALSE, $index = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $value = str_replace('MAILTO:', '', $value); $value = str_replace('mailto:', '', $value); $params2 = array(); if (is_array($params)) { $optarrays = array(); foreach ($params as $optparamlabel => $optparamvalue) { $optparamlabel = strtoupper($optparamlabel); switch ($optparamlabel) { case 'MEMBER': case 'DELEGATED-TO': case 'DELEGATED-FROM': if (is_array($optparamvalue)) { foreach ($optparamvalue as $part) { $part = str_replace('MAILTO:', '', $part); $part = str_replace('mailto:', '', $part); if (('"' == $part{0}) && ('"' == $part{strlen($part) - 1})) $part = substr($part, 1, (strlen($part) - 2)); $optarrays[$optparamlabel][] = $part; } } else { $part = str_replace('MAILTO:', '', $optparamvalue); $part = str_replace('mailto:', '', $part); if (('"' == $part{0}) && ('"' == $part{strlen($part) - 1})) $part = substr($part, 1, (strlen($part) - 2)); $optarrays[$optparamlabel][] = $part; } break; default: if ('SENT-BY' == $optparamlabel) { $optparamvalue = str_replace('MAILTO:', '', $optparamvalue); $optparamvalue = str_replace('mailto:', '', $optparamvalue); } if (('"' == substr($optparamvalue, 0, 1)) && ('"' == substr($optparamvalue, -1)) ) $optparamvalue = substr($optparamvalue, 1, (strlen($optparamvalue) - 2)); $params2[$optparamlabel] = $optparamvalue; break; } // end switch( $optparamlabel.. . } // end foreach( $optparam.. . foreach ($optarrays as $optparamlabel => $optparams) $params2[$optparamlabel] = $optparams; } // remove defaults $this->_existRem($params2, 'CUTYPE', 'INDIVIDUAL'); $this->_existRem($params2, 'PARTSTAT', 'NEEDS-ACTION'); $this->_existRem($params2, 'ROLE', 'REQ-PARTICIPANT'); $this->_existRem($params2, 'RSVP', 'FALSE'); // check language setting if (isset($params2['CN'])) { $lang = $this->getConfig('language'); if (!isset($params2['LANGUAGE']) && !empty($lang)) $params2['LANGUAGE'] = $lang; } $this->_setMval($this->attendee, $value, $params2, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: CATEGORIES */ /** * creates formatted output for calendar component property categories * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createCategories() { if (empty($this->categories)) return FALSE; $output = null; foreach ($this->categories as $category) { if (empty($category['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('CATEGORIES'); continue; } $attributes = $this->_createParams($category['params'], array('LANGUAGE')); if (is_array($category['value'])) { foreach ($category['value'] as $cix => $categoryPart) $category['value'][$cix] = $this->_strrep($categoryPart); $content = implode(',', $category['value']); } else $content = $this->_strrep($category['value']); $output .= $this->_createElement('CATEGORIES', $attributes, $content); } return $output; } /** * set calendar component property categories * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-06 * @param mixed $value * @param array $params , optional * @param integer $index , optional * @return bool */ function setCategories($value, $params = FALSE, $index = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->_setMval($this->categories, $value, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: CLASS */ /** * creates formatted output for calendar component property class * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.7 - 2006-11-20 * @return string */ function createClass() { if (empty($this->class)) return FALSE; if (empty($this->class['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('CLASS') : FALSE; $attributes = $this->_createParams($this->class['params']); return $this->_createElement('CLASS', $attributes, $this->class['value']); } /** * set calendar component property class * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name * @param array $params optional * @return bool */ function setClass($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->class = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: COMMENT */ /** * creates formatted output for calendar component property comment * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createComment() { if (empty($this->comment)) return FALSE; $output = null; foreach ($this->comment as $commentPart) { if (empty($commentPart['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('COMMENT'); continue; } $attributes = $this->_createParams($commentPart['params'], array('ALTREP', 'LANGUAGE')); $content = $this->_strrep($commentPart['value']); $output .= $this->_createElement('COMMENT', $attributes, $content); } return $output; } /** * set calendar component property comment * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-06 * @param string $value * @param array $params , optional * @param integer $index , optional * @return bool */ function setComment($value, $params = FALSE, $index = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->_setMval($this->comment, $value, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: COMPLETED */ /** * creates formatted output for calendar component property completed * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createCompleted() { if (empty($this->completed)) return FALSE; if (!isset($this->completed['value']['year']) && !isset($this->completed['value']['month']) && !isset($this->completed['value']['day']) && !isset($this->completed['value']['hour']) && !isset($this->completed['value']['min']) && !isset($this->completed['value']['sec']) ) if ($this->getConfig('allowEmpty')) return $this->_createElement('COMPLETED'); else return FALSE; $formatted = $this->_format_date_time($this->completed['value'], 7); $attributes = $this->_createParams($this->completed['params']); return $this->_createElement('COMPLETED', $attributes, $formatted); } /** * set calendar component property completed * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param array $params optional * @return bool */ function setCompleted($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE) { if (empty($year)) { if ($this->getConfig('allowEmpty')) { $this->completed = array('value' => null, 'params' => $this->_setParams($params)); return TRUE; } else return FALSE; } $this->completed = $this->_setDate2($year, $month, $day, $hour, $min, $sec, $params); return TRUE; } /*********************************************************************************/ /** * Property Name: CONTACT */ /** * creates formatted output for calendar component property contact * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @return string */ function createContact() { if (empty($this->contact)) return FALSE; $output = null; foreach ($this->contact as $contact) { if (!empty($contact['value'])) { $attributes = $this->_createParams($contact['params'], array('ALTREP', 'LANGUAGE')); $content = $this->_strrep($contact['value']); $output .= $this->_createElement('CONTACT', $attributes, $content); } elseif ($this->getConfig('allowEmpty')) $output .= $this->_createElement('CONTACT'); } return $output; } /** * set calendar component property contact * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param string $value * @param array $params , optional * @param integer $index , optional * @return bool */ function setContact($value, $params = FALSE, $index = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->_setMval($this->contact, $value, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: CREATED */ /** * creates formatted output for calendar component property created * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createCreated() { if (empty($this->created)) return FALSE; $formatted = $this->_format_date_time($this->created['value'], 7); $attributes = $this->_createParams($this->created['params']); return $this->_createElement('CREATED', $attributes, $formatted); } /** * set calendar component property created * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @param mixed $year optional * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param mixed $params optional * @return bool */ function setCreated($year = FALSE, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE) { if (!isset($year)) { $year = date('Ymd\THis', mktime(date('H'), date('i'), date('s') - date('Z'), date('m'), date('d'), date('Y'))); } $this->created = $this->_setDate2($year, $month, $day, $hour, $min, $sec, $params); return TRUE; } /*********************************************************************************/ /** * Property Name: DESCRIPTION */ /** * creates formatted output for calendar component property description * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createDescription() { if (empty($this->description)) return FALSE; $output = null; foreach ($this->description as $description) { if (!empty($description['value'])) { $attributes = $this->_createParams($description['params'], array('ALTREP', 'LANGUAGE')); $content = $this->_strrep($description['value']); $output .= $this->_createElement('DESCRIPTION', $attributes, $content); } elseif ($this->getConfig('allowEmpty')) $output .= $this->_createElement('DESCRIPTION'); } return $output; } /** * set calendar component property description * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param string $value * @param array $params , optional * @param integer $index , optional * @return bool */ function setDescription($value, $params = FALSE, $index = FALSE) { if (empty($value)) { if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; } $this->_setMval($this->description, $value, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: DTEND */ /** * creates formatted output for calendar component property dtend * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createDtend() { if (empty($this->dtend)) return FALSE; if (!isset($this->dtend['value']['year']) && !isset($this->dtend['value']['month']) && !isset($this->dtend['value']['day']) && !isset($this->dtend['value']['hour']) && !isset($this->dtend['value']['min']) && !isset($this->dtend['value']['sec']) ) if ($this->getConfig('allowEmpty')) return $this->_createElement('DTEND'); else return FALSE; $formatted = $this->_format_date_time($this->dtend['value']); $attributes = $this->_createParams($this->dtend['params']); return $this->_createElement('DTEND', $attributes, $formatted); } /** * set calendar component property dtend * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param string $tz optional * @param array params optional * @return bool */ function setDtend($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE) { if (empty($year)) { if ($this->getConfig('allowEmpty')) { $this->dtend = array('value' => null, 'params' => $this->_setParams($params)); return TRUE; } else return FALSE; } $this->dtend = $this->_setDate($year, $month, $day, $hour, $min, $sec, $tz, $params); return TRUE; } /*********************************************************************************/ /** * Property Name: DTSTAMP */ /** * creates formatted output for calendar component property dtstamp * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.4 - 2008-03-07 * @return string */ function createDtstamp() { if (!isset($this->dtstamp['value']['year']) && !isset($this->dtstamp['value']['month']) && !isset($this->dtstamp['value']['day']) && !isset($this->dtstamp['value']['hour']) && !isset($this->dtstamp['value']['min']) && !isset($this->dtstamp['value']['sec']) ) $this->_makeDtstamp(); $formatted = $this->_format_date_time($this->dtstamp['value'], 7); $attributes = $this->_createParams($this->dtstamp['params']); return $this->_createElement('DTSTAMP', $attributes, $formatted); } /** * computes datestamp for calendar component object instance dtstamp * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 1.x.x - 2007-05-13 * @return void */ function _makeDtstamp() { $this->dtstamp['value'] = array('year' => date('Y') , 'month' => date('m') , 'day' => date('d') , 'hour' => date('H') , 'min' => date('i') , 'sec' => date('s') - date('Z')); $this->dtstamp['params'] = null; } /** * set calendar component property dtstamp * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param array $params optional * @return TRUE */ function setDtstamp($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE) { if (empty($year)) $this->_makeDtstamp(); else $this->dtstamp = $this->_setDate2($year, $month, $day, $hour, $min, $sec, $params); return TRUE; } /*********************************************************************************/ /** * Property Name: DTSTART */ /** * creates formatted output for calendar component property dtstart * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-26 * @return string */ function createDtstart() { if (empty($this->dtstart)) return FALSE; if (!isset($this->dtstart['value']['year']) && !isset($this->dtstart['value']['month']) && !isset($this->dtstart['value']['day']) && !isset($this->dtstart['value']['hour']) && !isset($this->dtstart['value']['min']) && !isset($this->dtstart['value']['sec']) ) if ($this->getConfig('allowEmpty')) return $this->_createElement('DTSTART'); else return FALSE; if (in_array($this->objName, array('vtimezone', 'standard', 'daylight'))) unset($this->dtstart['value']['tz'], $this->dtstart['params']['TZID']); $formatted = $this->_format_date_time($this->dtstart['value']); $attributes = $this->_createParams($this->dtstart['params']); return $this->_createElement('DTSTART', $attributes, $formatted); } /** * set calendar component property dtstart * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-11-04 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param string $tz optional * @param array $params optional * @return bool */ function setDtstart($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE) { if (empty($year)) { if ($this->getConfig('allowEmpty')) { $this->dtstart = array('value' => null, 'params' => $this->_setParams($params)); return TRUE; } else return FALSE; } $this->dtstart = $this->_setDate($year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart'); return TRUE; } /*********************************************************************************/ /** * Property Name: DUE */ /** * creates formatted output for calendar component property due * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createDue() { if (empty($this->due)) return FALSE; if (!isset($this->due['value']['year']) && !isset($this->due['value']['month']) && !isset($this->due['value']['day']) && !isset($this->due['value']['hour']) && !isset($this->due['value']['min']) && !isset($this->due['value']['sec']) ) if ($this->getConfig('allowEmpty')) return $this->_createElement('DUE'); else return FALSE; $formatted = $this->_format_date_time($this->due['value']); $attributes = $this->_createParams($this->due['params']); return $this->_createElement('DUE', $attributes, $formatted); } /** * set calendar component property due * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param array $params optional * @return bool */ function setDue($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE) { if (empty($year)) { if ($this->getConfig('allowEmpty')) { $this->due = array('value' => null, 'params' => $this->_setParams($params)); return TRUE; } else return FALSE; } $this->due = $this->_setDate($year, $month, $day, $hour, $min, $sec, $tz, $params); return TRUE; } /*********************************************************************************/ /** * Property Name: DURATION */ /** * creates formatted output for calendar component property duration * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createDuration() { if (empty($this->duration)) return FALSE; if (!isset($this->duration['value']['week']) && !isset($this->duration['value']['day']) && !isset($this->duration['value']['hour']) && !isset($this->duration['value']['min']) && !isset($this->duration['value']['sec']) ) if ($this->getConfig('allowEmpty')) return $this->_createElement('DURATION', array(), null); else return FALSE; $attributes = $this->_createParams($this->duration['params']); return $this->_createElement('DURATION', $attributes, $this->_format_duration($this->duration['value'])); } /** * set calendar component property duration * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param mixed $week * @param mixed $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param array $params optional * @return bool */ function setDuration($week, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE) { if (empty($week)) if ($this->getConfig('allowEmpty')) $week = null; else return FALSE; if (is_array($week) && (1 <= count($week))) $this->duration = array('value' => $this->_duration_array($week), 'params' => $this->_setParams($day)); elseif (is_string($week) && (3 <= strlen(trim($week)))) { $week = trim($week); if (in_array(substr($week, 0, 1), array('+', '-'))) $week = substr($week, 1); $this->duration = array('value' => $this->_duration_string($week), 'params' => $this->_setParams($day)); } elseif (empty($week) && empty($day) && empty($hour) && empty($min) && empty($sec)) return FALSE; else $this->duration = array('value' => $this->_duration_array(array($week, $day, $hour, $min, $sec)), 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: EXDATE */ /** * creates formatted output for calendar component property exdate * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createExdate() { if (empty($this->exdate)) return FALSE; $output = null; foreach ($this->exdate as $ex => $theExdate) { if (empty($theExdate['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('EXDATE'); continue; } $content = $attributes = null; foreach ($theExdate['value'] as $eix => $exdatePart) { $parno = count($exdatePart); $formatted = $this->_format_date_time($exdatePart, $parno); if (isset($theExdate['params']['TZID'])) $formatted = str_replace('Z', '', $formatted); if (0 < $eix) { if (isset($theExdate['value'][0]['tz'])) { if (ctype_digit(substr($theExdate['value'][0]['tz'], -4)) || ('Z' == $theExdate['value'][0]['tz']) ) { if ('Z' != substr($formatted, -1)) $formatted .= 'Z'; } else $formatted = str_replace('Z', '', $formatted); } else $formatted = str_replace('Z', '', $formatted); } $content .= (0 < $eix) ? ',' . $formatted : $formatted; } $attributes .= $this->_createParams($theExdate['params']); $output .= $this->_createElement('EXDATE', $attributes, $content); } return $output; } /** * set calendar component property exdate * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param array exdates * @param array $params , optional * @param integer $index , optional * @return bool */ function setExdate($exdates, $params = FALSE, $index = FALSE) { if (empty($exdates)) { if ($this->getConfig('allowEmpty')) { $this->_setMval($this->exdate, null, $params, FALSE, $index); return TRUE; } else return FALSE; } $input = array('params' => $this->_setParams($params, array('VALUE' => 'DATE-TIME'))); /* ev. check 1:st date and save ev. timezone **/ $this->_chkdatecfg(reset($exdates), $parno, $input['params']); $this->_existRem($input['params'], 'VALUE', 'DATE-TIME'); // remove default parameter foreach ($exdates as $eix => $theExdate) { if ($this->_isArrayTimestampDate($theExdate)) $exdatea = $this->_timestamp2date($theExdate, $parno); elseif (is_array($theExdate)) $exdatea = $this->_date_time_array($theExdate, $parno); elseif (8 <= strlen(trim($theExdate))) // ex. 2006-08-03 10:12:18 $exdatea = $this->_date_time_string($theExdate, $parno); if (3 == $parno) unset($exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz']); elseif (isset($exdatea['tz'])) $exdatea['tz'] = (string)$exdatea['tz']; if (isset($input['params']['TZID']) || (isset($exdatea['tz']) && !$this->_isOffset($exdatea['tz'])) || (isset($input['value'][0]) && (!isset($input['value'][0]['tz']))) || (isset($input['value'][0]['tz']) && !$this->_isOffset($input['value'][0]['tz'])) ) unset($exdatea['tz']); $input['value'][] = $exdatea; } if (0 >= count($input['value'])) return FALSE; if (3 == $parno) { $input['params']['VALUE'] = 'DATE'; unset($input['params']['TZID']); } $this->_setMval($this->exdate, $input['value'], $input['params'], FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: EXRULE */ /** * creates formatted output for calendar component property exrule * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createExrule() { if (empty($this->exrule)) return FALSE; return $this->_format_recur('EXRULE', $this->exrule); } /** * set calendar component property exdate * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param array $exruleset * @param array $params , optional * @param integer $index , optional * @return bool */ function setExrule($exruleset, $params = FALSE, $index = FALSE) { if (empty($exruleset)) if ($this->getConfig('allowEmpty')) $exruleset = null; else return FALSE; $this->_setMval($this->exrule, $this->_setRexrule($exruleset), $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: FREEBUSY */ /** * creates formatted output for calendar component property freebusy * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createFreebusy() { if (empty($this->freebusy)) return FALSE; $output = null; foreach ($this->freebusy as $freebusyPart) { if (empty($freebusyPart['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('FREEBUSY'); continue; } $attributes = $content = null; if (isset($freebusyPart['value']['fbtype'])) { $attributes .= $this->intAttrDelimiter . 'FBTYPE=' . $freebusyPart['value']['fbtype']; unset($freebusyPart['value']['fbtype']); $freebusyPart['value'] = array_values($freebusyPart['value']); } else $attributes .= $this->intAttrDelimiter . 'FBTYPE=BUSY'; $attributes .= $this->_createParams($freebusyPart['params']); $fno = 1; $cnt = count($freebusyPart['value']); foreach ($freebusyPart['value'] as $periodix => $freebusyPeriod) { $formatted = $this->_format_date_time($freebusyPeriod[0]); $content .= $formatted; $content .= '/'; $cnt2 = count($freebusyPeriod[1]); if (array_key_exists('year', $freebusyPeriod[1])) // date-time $cnt2 = 7; elseif (array_key_exists('week', $freebusyPeriod[1])) // duration $cnt2 = 5; if ((7 == $cnt2) && // period= -> date-time isset($freebusyPeriod[1]['year']) && isset($freebusyPeriod[1]['month']) && isset($freebusyPeriod[1]['day']) ) { $content .= $this->_format_date_time($freebusyPeriod[1]); } else { // period= -> dur-time $content .= $this->_format_duration($freebusyPeriod[1]); } if ($fno < $cnt) $content .= ','; $fno++; } $output .= $this->_createElement('FREEBUSY', $attributes, $content); } return $output; } /** * set calendar component property freebusy * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param string $fbType * @param array $fbValues * @param array $params , optional * @param integer $index , optional * @return bool */ function setFreebusy($fbType, $fbValues, $params = FALSE, $index = FALSE) { if (empty($fbValues)) { if ($this->getConfig('allowEmpty')) { $this->_setMval($this->freebusy, null, $params, FALSE, $index); return TRUE; } else return FALSE; } $fbType = strtoupper($fbType); if ((!in_array($fbType, array('FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE'))) && ('X-' != substr($fbType, 0, 2)) ) $fbType = 'BUSY'; $input = array('fbtype' => $fbType); foreach ($fbValues as $fbPeriod) { // periods => period $freebusyPeriod = array(); foreach ($fbPeriod as $fbMember) { // pairs => singlepart $freebusyPairMember = array(); if (is_array($fbMember)) { if ($this->_isArrayDate($fbMember)) { // date-time value $freebusyPairMember = $this->_date_time_array($fbMember, 7); $freebusyPairMember['tz'] = 'Z'; } elseif ($this->_isArrayTimestampDate($fbMember)) { // timestamp value $freebusyPairMember = $this->_timestamp2date($fbMember['timestamp'], 7); $freebusyPairMember['tz'] = 'Z'; } else { // array format duration $freebusyPairMember = $this->_duration_array($fbMember); } } elseif ((3 <= strlen(trim($fbMember))) && // string format duration (in_array($fbMember{0}, array('P', '+', '-'))) ) { if ('P' != $fbMember{0}) $fbmember = substr($fbMember, 1); $freebusyPairMember = $this->_duration_string($fbMember); } elseif (8 <= strlen(trim($fbMember))) { // text date ex. 2006-08-03 10:12:18 $freebusyPairMember = $this->_date_time_string($fbMember, 7); $freebusyPairMember['tz'] = 'Z'; } $freebusyPeriod[] = $freebusyPairMember; } $input[] = $freebusyPeriod; } $this->_setMval($this->freebusy, $input, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: GEO */ /** * creates formatted output for calendar component property geo * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createGeo() { if (empty($this->geo)) return FALSE; if (empty($this->geo['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('GEO') : FALSE; $attributes = $this->_createParams($this->geo['params']); $content = null; $content .= number_format((float)$this->geo['value']['latitude'], 6, '.', ''); $content .= ';'; $content .= number_format((float)$this->geo['value']['longitude'], 6, '.', ''); return $this->_createElement('GEO', $attributes, $content); } /** * set calendar component property geo * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param float $latitude * @param float $longitude * @param array $params optional * @return bool */ function setGeo($latitude, $longitude, $params = FALSE) { if (!empty($latitude) && !empty($longitude)) { if (!is_array($this->geo)) $this->geo = array(); $this->geo['value']['latitude'] = $latitude; $this->geo['value']['longitude'] = $longitude; $this->geo['params'] = $this->_setParams($params); } elseif ($this->getConfig('allowEmpty')) $this->geo = array('value' => null, 'params' => $this->_setParams($params)); else return FALSE; return TRUE; } /*********************************************************************************/ /** * Property Name: LAST-MODIFIED */ /** * creates formatted output for calendar component property last-modified * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createLastModified() { if (empty($this->lastmodified)) return FALSE; $attributes = $this->_createParams($this->lastmodified['params']); $formatted = $this->_format_date_time($this->lastmodified['value'], 7); return $this->_createElement('LAST-MODIFIED', $attributes, $formatted); } /** * set calendar component property completed * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @param mixed $year optional * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param array $params optional * @return boll */ function setLastModified($year = FALSE, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE) { if (empty($year)) $year = date('Ymd\THis', mktime(date('H'), date('i'), date('s') - date('Z'), date('m'), date('d'), date('Y'))); $this->lastmodified = $this->_setDate2($year, $month, $day, $hour, $min, $sec, $params); return TRUE; } /*********************************************************************************/ /** * Property Name: LOCATION */ /** * creates formatted output for calendar component property location * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createLocation() { if (empty($this->location)) return FALSE; if (empty($this->location['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('LOCATION') : FALSE; $attributes = $this->_createParams($this->location['params'], array('ALTREP', 'LANGUAGE')); $content = $this->_strrep($this->location['value']); return $this->_createElement('LOCATION', $attributes, $content); } /** * set calendar component property location * ' * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param array params optional * @return bool */ function setLocation($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->location = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: ORGANIZER */ /** * creates formatted output for calendar component property organizer * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createOrganizer() { if (empty($this->organizer)) return FALSE; if (empty($this->organizer['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('ORGANIZER') : FALSE; $attributes = $this->_createParams($this->organizer['params'] , array('CN', 'DIR', 'LANGUAGE', 'SENT-BY')); $content = 'MAILTO:' . $this->organizer['value']; return $this->_createElement('ORGANIZER', $attributes, $content); } /** * set calendar component property organizer * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param array params optional * @return bool */ function setOrganizer($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $value = str_replace('MAILTO:', '', $value); $value = str_replace('mailto:', '', $value); $this->organizer = array('value' => $value, 'params' => $this->_setParams($params)); if (isset($this->organizer['params']['SENT-BY'])) { if ('MAILTO' == strtoupper(substr($this->organizer['params']['SENT-BY'], 0, 6))) $this->organizer['params']['SENT-BY'] = substr($this->organizer['params']['SENT-BY'], 7); } return TRUE; } /*********************************************************************************/ /** * Property Name: PERCENT-COMPLETE */ /** * creates formatted output for calendar component property percent-complete * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @return string */ function createPercentComplete() { if (empty($this->percentcomplete)) return FALSE; if (empty($this->percentcomplete['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('PERCENT-COMPLETE') : FALSE; $attributes = $this->_createParams($this->percentcomplete['params']); return $this->_createElement('PERCENT-COMPLETE', $attributes, $this->percentcomplete['value']); } /** * set calendar component property percent-complete * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param int $value * @param array $params optional * @return bool */ function setPercentComplete($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->percentcomplete = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: PRIORITY */ /** * creates formatted output for calendar component property priority * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createPriority() { if (empty($this->priority)) return FALSE; if (empty($this->priority['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('PRIORITY') : FALSE; $attributes = $this->_createParams($this->priority['params']); return $this->_createElement('PRIORITY', $attributes, $this->priority['value']); } /** * set calendar component property priority * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param int $value * @param array $params optional * @return bool */ function setPriority($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->priority = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: RDATE */ /** * creates formatted output for calendar component property rdate * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-26 * @return string */ function createRdate() { if (empty($this->rdate)) return FALSE; $utctime = (in_array($this->objName, array('vtimezone', 'standard', 'daylight'))) ? TRUE : FALSE; $output = null; if ($utctime) unset($this->rdate['params']['TZID']); foreach ($this->rdate as $theRdate) { if (empty($theRdate['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('RDATE'); continue; } if ($utctime) unset($theRdate['params']['TZID']); $attributes = $this->_createParams($theRdate['params']); $cnt = count($theRdate['value']); $content = null; $rno = 1; foreach ($theRdate['value'] as $rpix => $rdatePart) { $contentPart = null; if (is_array($rdatePart) && isset($theRdate['params']['VALUE']) && ('PERIOD' == $theRdate['params']['VALUE']) ) { // PERIOD if ($utctime) unset($rdatePart[0]['tz']); $formatted = $this->_format_date_time($rdatePart[0]); // PERIOD part 1 if ($utctime || !empty($theRdate['params']['TZID'])) $formatted = str_replace('Z', '', $formatted); if (0 < $rpix) { if (!empty($rdatePart[0]['tz']) && $this->_isOffset($rdatePart[0]['tz'])) { if ('Z' != substr($formatted, -1)) $formatted .= 'Z'; } else $formatted = str_replace('Z', '', $formatted); } $contentPart .= $formatted; $contentPart .= '/'; $cnt2 = count($rdatePart[1]); if (array_key_exists('year', $rdatePart[1])) { if (array_key_exists('hour', $rdatePart[1])) $cnt2 = 7; // date-time else $cnt2 = 3; // date } elseif (array_key_exists('week', $rdatePart[1])) // duration $cnt2 = 5; if ((7 == $cnt2) && // period= -> date-time isset($rdatePart[1]['year']) && isset($rdatePart[1]['month']) && isset($rdatePart[1]['day']) ) { if ($utctime) unset($rdatePart[1]['tz']); $formatted = $this->_format_date_time($rdatePart[1]); // PERIOD part 2 if ($utctime || !empty($theRdate['params']['TZID'])) $formatted = str_replace('Z', '', $formatted); if (!empty($rdatePart[0]['tz']) && $this->_isOffset($rdatePart[0]['tz'])) { if ('Z' != substr($formatted, -1)) $formatted .= 'Z'; } else $formatted = str_replace('Z', '', $formatted); $contentPart .= $formatted; } else { // period= -> dur-time $contentPart .= $this->_format_duration($rdatePart[1]); } } // PERIOD end else { // SINGLE date start if ($utctime) unset($rdatePart['tz']); $formatted = $this->_format_date_time($rdatePart); if ($utctime || !empty($theRdate['params']['TZID'])) $formatted = str_replace('Z', '', $formatted); if (!$utctime && (0 < $rpix)) { if (!empty($theRdate['value'][0]['tz']) && $this->_isOffset($theRdate['value'][0]['tz'])) { if ('Z' != substr($formatted, -1)) $formatted .= 'Z'; } else $formatted = str_replace('Z', '', $formatted); } $contentPart .= $formatted; } $content .= $contentPart; if ($rno < $cnt) $content .= ','; $rno++; } $output .= $this->_createElement('RDATE', $attributes, $content); } return $output; } /** * set calendar component property rdate * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-07 * @param array $rdates * @param array $params , optional * @param integer $index , optional * @return bool */ function setRdate($rdates, $params = FALSE, $index = FALSE) { if (empty($rdates)) { if ($this->getConfig('allowEmpty')) { $this->_setMval($this->rdate, null, $params, FALSE, $index); return TRUE; } else return FALSE; } $input = array('params' => $this->_setParams($params, array('VALUE' => 'DATE-TIME'))); if (in_array($this->objName, array('vtimezone', 'standard', 'daylight'))) { unset($input['params']['TZID']); $input['params']['VALUE'] = 'DATE-TIME'; } /* check if PERIOD, if not set */ if ((!isset($input['params']['VALUE']) || !in_array($input['params']['VALUE'], array('DATE', 'PERIOD'))) && isset($rdates[0]) && is_array($rdates[0]) && (2 == count($rdates[0])) && isset($rdates[0][0]) && isset($rdates[0][1]) && !isset($rdates[0]['timestamp']) && ((is_array($rdates[0][0]) && (isset($rdates[0][0]['timestamp']) || $this->_isArrayDate($rdates[0][0]))) || (is_string($rdates[0][0]) && (8 <= strlen(trim($rdates[0][0]))))) && (is_array($rdates[0][1]) || (is_string($rdates[0][1]) && (3 <= strlen(trim($rdates[0][1]))))) ) $input['params']['VALUE'] = 'PERIOD'; /* check 1:st date, upd. $parno (opt) and save ev. timezone **/ $date = reset($rdates); if (isset($input['params']['VALUE']) && ('PERIOD' == $input['params']['VALUE'])) // PERIOD $date = reset($date); $this->_chkdatecfg($date, $parno, $input['params']); if (in_array($this->objName, array('vtimezone', 'standard', 'daylight'))) unset($input['params']['TZID']); $this->_existRem($input['params'], 'VALUE', 'DATE-TIME'); // remove default foreach ($rdates as $rpix => $theRdate) { $inputa = null; if (is_array($theRdate)) { if (isset($input['params']['VALUE']) && ('PERIOD' == $input['params']['VALUE'])) { // PERIOD foreach ($theRdate as $rix => $rPeriod) { if (is_array($rPeriod)) { if ($this->_isArrayTimestampDate($rPeriod)) // timestamp $inputab = (isset($rPeriod['tz'])) ? $this->_timestamp2date($rPeriod, $parno) : $this->_timestamp2date($rPeriod, 6); elseif ($this->_isArrayDate($rPeriod)) $inputab = (3 < count($rPeriod)) ? $this->_date_time_array($rPeriod, $parno) : $this->_date_time_array($rPeriod, 6); elseif ((1 == count($rPeriod)) && (8 <= strlen(reset($rPeriod)))) // text-date $inputab = $this->_date_time_string(reset($rPeriod), $parno); else // array format duration $inputab = $this->_duration_array($rPeriod); } elseif ((3 <= strlen(trim($rPeriod))) && // string format duration (in_array($rPeriod{0}, array('P', '+', '-'))) ) { if ('P' != $rPeriod{0}) $rPeriod = substr($rPeriod, 1); $inputab = $this->_duration_string($rPeriod); } elseif (8 <= strlen(trim($rPeriod))) // text date ex. 2006-08-03 10:12:18 $inputab = $this->_date_time_string($rPeriod, $parno); if (isset($input['params']['TZID']) || (isset($inputab['tz']) && !$this->_isOffset($inputab['tz'])) || (isset($inputa[0]) && (!isset($inputa[0]['tz']))) || (isset($inputa[0]['tz']) && !$this->_isOffset($inputa[0]['tz'])) ) unset($inputab['tz']); $inputa[] = $inputab; } } // PERIOD end elseif ($this->_isArrayTimestampDate($theRdate)) // timestamp $inputa = $this->_timestamp2date($theRdate, $parno); else // date[-time] $inputa = $this->_date_time_array($theRdate, $parno); } elseif (8 <= strlen(trim($theRdate))) // text date ex. 2006-08-03 10:12:18 $inputa = $this->_date_time_string($theRdate, $parno); if (!isset($input['params']['VALUE']) || ('PERIOD' != $input['params']['VALUE'])) { // no PERIOD if (3 == $parno) unset($inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz']); elseif (isset($inputa['tz'])) $inputa['tz'] = (string)$inputa['tz']; if (isset($input['params']['TZID']) || (isset($inputa['tz']) && !$this->_isOffset($inputa['tz'])) || (isset($input['value'][0]) && (!isset($input['value'][0]['tz']))) || (isset($input['value'][0]['tz']) && !$this->_isOffset($input['value'][0]['tz'])) ) unset($inputa['tz']); } $input['value'][] = $inputa; } if (3 == $parno) { $input['params']['VALUE'] = 'DATE'; unset($input['params']['TZID']); } $this->_setMval($this->rdate, $input['value'], $input['params'], FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: RECURRENCE-ID */ /** * creates formatted output for calendar component property recurrence-id * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createRecurrenceid() { if (empty($this->recurrenceid)) return FALSE; if (empty($this->recurrenceid['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('RECURRENCE-ID') : FALSE; $formatted = $this->_format_date_time($this->recurrenceid['value']); $attributes = $this->_createParams($this->recurrenceid['params']); return $this->_createElement('RECURRENCE-ID', $attributes, $formatted); } /** * set calendar component property recurrence-id * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param array $params optional * @return bool */ function setRecurrenceid($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE) { if (empty($year)) { if ($this->getConfig('allowEmpty')) { $this->recurrenceid = array('value' => null, 'params' => null); return TRUE; } else return FALSE; } $this->recurrenceid = $this->_setDate($year, $month, $day, $hour, $min, $sec, $tz, $params); return TRUE; } /*********************************************************************************/ /** * Property Name: RELATED-TO */ /** * creates formatted output for calendar component property related-to * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @return string */ function createRelatedTo() { if (empty($this->relatedto)) return FALSE; $output = null; foreach ($this->relatedto as $relation) { if (empty($relation['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('RELATED-TO', $this->_createParams($relation['params'])); continue; } $attributes = $this->_createParams($relation['params']); $content = ('xcal' != $this->format) ? '<' : ''; $content .= $this->_strrep($relation['value']); $content .= ('xcal' != $this->format) ? '>' : ''; $output .= $this->_createElement('RELATED-TO', $attributes, $content); } return $output; } /** * set calendar component property related-to * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-07 * @param float $relid * @param array $params , optional * @param index $index , optional * @return bool */ function setRelatedTo($value, $params = FALSE, $index = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; if (('<' == substr($value, 0, 1)) && ('>' == substr($value, -1))) $value = substr($value, 1, (strlen($value) - 2)); $this->_existRem($params, 'RELTYPE', 'PARENT', TRUE); // remove default $this->_setMval($this->relatedto, $value, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: REPEAT */ /** * creates formatted output for calendar component property repeat * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createRepeat() { if (empty($this->repeat)) return FALSE; if (empty($this->repeat['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('REPEAT') : FALSE; $attributes = $this->_createParams($this->repeat['params']); return $this->_createElement('REPEAT', $attributes, $this->repeat['value']); } /** * set calendar component property transp * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param array $params optional * @return void */ function setRepeat($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->repeat = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: REQUEST-STATUS */ /** * creates formatted output for calendar component property request-status * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @return string */ function createRequestStatus() { if (empty($this->requeststatus)) return FALSE; $output = null; foreach ($this->requeststatus as $rstat) { if (empty($rstat['value']['statcode'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('REQUEST-STATUS'); continue; } $attributes = $this->_createParams($rstat['params'], array('LANGUAGE')); $content = number_format((float)$rstat['value']['statcode'], 2, '.', ''); $content .= ';' . $this->_strrep($rstat['value']['text']); if (isset($rstat['value']['extdata'])) $content .= ';' . $this->_strrep($rstat['value']['extdata']); $output .= $this->_createElement('REQUEST-STATUS', $attributes, $content); } return $output; } /** * set calendar component property request-status * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param float $statcode * @param string $text * @param string $extdata , optional * @param array $params , optional * @param integer $index , optional * @return bool */ function setRequestStatus($statcode, $text, $extdata = FALSE, $params = FALSE, $index = FALSE) { if (empty($statcode) || empty($text)) if ($this->getConfig('allowEmpty')) $statcode = $text = null; else return FALSE; $input = array('statcode' => $statcode, 'text' => $text); if ($extdata) $input['extdata'] = $extdata; $this->_setMval($this->requeststatus, $input, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: RESOURCES */ /** * creates formatted output for calendar component property resources * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @return string */ function createResources() { if (empty($this->resources)) return FALSE; $output = null; foreach ($this->resources as $resource) { if (empty($resource['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement('RESOURCES'); continue; } $attributes = $this->_createParams($resource['params'], array('ALTREP', 'LANGUAGE')); if (is_array($resource['value'])) { foreach ($resource['value'] as $rix => $resourcePart) $resource['value'][$rix] = $this->_strrep($resourcePart); $content = implode(',', $resource['value']); } else $content = $this->_strrep($resource['value']); $output .= $this->_createElement('RESOURCES', $attributes, $content); } return $output; } /** * set calendar component property recources * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param mixed $value * @param array $params , optional * @param integer $index , optional * @return bool */ function setResources($value, $params = FALSE, $index = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->_setMval($this->resources, $value, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: RRULE */ /** * creates formatted output for calendar component property rrule * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createRrule() { if (empty($this->rrule)) return FALSE; return $this->_format_recur('RRULE', $this->rrule); } /** * set calendar component property rrule * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param array $rruleset * @param array $params , optional * @param integer $index , optional * @return void */ function setRrule($rruleset, $params = FALSE, $index = FALSE) { if (empty($rruleset)) if ($this->getConfig('allowEmpty')) $rruleset = null; else return FALSE; $this->_setMval($this->rrule, $this->_setRexrule($rruleset), $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: SEQUENCE */ /** * creates formatted output for calendar component property sequence * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.7 - 2006-11-20 * @return string */ function createSequence() { if (empty($this->sequence)) return FALSE; if (empty($this->sequence['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('SEQUENCE') : FALSE; $attributes = $this->_createParams($this->sequence['params']); return $this->_createElement('SEQUENCE', $attributes, $this->sequence['value']); } /** * set calendar component property sequence * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param int $value optional * @param array $params optional * @return bool */ function setSequence($value = FALSE, $params = FALSE) { if (empty($value)) $value = (isset($this->sequence['value']) && (0 < $this->sequence['value'])) ? $this->sequence['value'] + 1 : 1; $this->sequence = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: STATUS */ /** * creates formatted output for calendar component property status * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createStatus() { if (empty($this->status)) return FALSE; if (empty($this->status['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('STATUS') : FALSE; $attributes = $this->_createParams($this->status['params']); return $this->_createElement('STATUS', $attributes, $this->status['value']); } /** * set calendar component property status * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param array $params optional * @return bool */ function setStatus($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->status = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: SUMMARY */ /** * creates formatted output for calendar component property summary * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createSummary() { if (empty($this->summary)) return FALSE; if (empty($this->summary['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('SUMMARY') : FALSE; $attributes = $this->_createParams($this->summary['params'], array('ALTREP', 'LANGUAGE')); $content = $this->_strrep($this->summary['value']); return $this->_createElement('SUMMARY', $attributes, $content); } /** * set calendar component property summary * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param string $params optional * @return bool */ function setSummary($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->summary = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: TRANSP */ /** * creates formatted output for calendar component property transp * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createTransp() { if (empty($this->transp)) return FALSE; if (empty($this->transp['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('TRANSP') : FALSE; $attributes = $this->_createParams($this->transp['params']); return $this->_createElement('TRANSP', $attributes, $this->transp['value']); } /** * set calendar component property transp * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param string $params optional * @return bool */ function setTransp($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->transp = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: TRIGGER */ /** * creates formatted output for calendar component property trigger * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-21 * @return string */ function createTrigger() { if (empty($this->trigger)) return FALSE; if (empty($this->trigger['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('TRIGGER') : FALSE; $content = $attributes = null; if (isset($this->trigger['value']['year']) && isset($this->trigger['value']['month']) && isset($this->trigger['value']['day']) ) $content .= $this->_format_date_time($this->trigger['value']); else { if (TRUE !== $this->trigger['value']['relatedStart']) $attributes .= $this->intAttrDelimiter . 'RELATED=END'; if ($this->trigger['value']['before']) $content .= '-'; $content .= $this->_format_duration($this->trigger['value']); } $attributes .= $this->_createParams($this->trigger['params']); return $this->_createElement('TRIGGER', $attributes, $content); } /** * set calendar component property trigger * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-11-04 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $week optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param bool $relatedStart optional * @param bool $before optional * @param array $params optional * @return bool */ function setTrigger($year, $month = null, $day = null, $week = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $relatedStart = TRUE, $before = TRUE, $params = FALSE) { if (empty($year) && empty($month) && empty($day) && empty($week) && empty($hour) && empty($min) && empty($sec)) if ($this->getConfig('allowEmpty')) { $this->trigger = array('value' => null, 'params' => $this->_setParams($params)); return TRUE; } else return FALSE; if ($this->_isArrayTimestampDate($year)) { // timestamp $params = $this->_setParams($month); $date = $this->_timestamp2date($year, 7); foreach ($date as $k => $v) $$k = $v; } elseif (is_array($year) && (is_array($month) || empty($month))) { $params = $this->_setParams($month); if (!(array_key_exists('year', $year) && // exclude date-time array_key_exists('month', $year) && array_key_exists('day', $year)) ) { // so this must be a duration if (isset($params['RELATED']) && ('END' == $params['RELATED'])) $relatedStart = FALSE; else $relatedStart = (array_key_exists('relatedStart', $year) && (TRUE !== $year['relatedStart'])) ? FALSE : TRUE; $before = (array_key_exists('before', $year) && (TRUE !== $year['before'])) ? FALSE : TRUE; } $SSYY = (array_key_exists('year', $year)) ? $year['year'] : null; $month = (array_key_exists('month', $year)) ? $year['month'] : null; $day = (array_key_exists('day', $year)) ? $year['day'] : null; $week = (array_key_exists('week', $year)) ? $year['week'] : null; $hour = (array_key_exists('hour', $year)) ? $year['hour'] : 0; //null; $min = (array_key_exists('min', $year)) ? $year['min'] : 0; //null; $sec = (array_key_exists('sec', $year)) ? $year['sec'] : 0; //null; $year = $SSYY; } elseif (is_string($year) && (is_array($month) || empty($month))) { // duration or date in a string $params = $this->_setParams($month); if (in_array($year{0}, array('P', '+', '-'))) { // duration $relatedStart = (isset($params['RELATED']) && ('END' == $params['RELATED'])) ? FALSE : TRUE; $before = ('-' == $year{0}) ? TRUE : FALSE; if ('P' != $year{0}) $year = substr($year, 1); $date = $this->_duration_string($year); } else // date $date = $this->_date_time_string($year, 7); unset($year, $month, $day); foreach ($date as $k => $v) $$k = $v; } else // single values in function input parameters $params = $this->_setParams($params); if (!empty($year) && !empty($month) && !empty($day)) { // date $params['VALUE'] = 'DATE-TIME'; $hour = ($hour) ? $hour : 0; $min = ($min) ? $min : 0; $sec = ($sec) ? $sec : 0; $this->trigger = array('params' => $params); $this->trigger['value'] = array('year' => $year , 'month' => $month , 'day' => $day , 'hour' => $hour , 'min' => $min , 'sec' => $sec , 'tz' => 'Z'); return TRUE; } elseif ((empty($year) && empty($month)) && // duration (!empty($week) || !empty($day) || !empty($hour) || !empty($min) || !empty($sec)) ) { unset($params['RELATED']); // set at output creation (END only) unset($params['VALUE']); // 'DURATION' default $this->trigger = array('params' => $params); $relatedStart = (FALSE !== $relatedStart) ? TRUE : FALSE; $before = (FALSE !== $before) ? TRUE : FALSE; $this->trigger['value'] = array('relatedStart' => $relatedStart , 'before' => $before); if (!empty($week)) $this->trigger['value']['week'] = $week; if (!empty($day)) $this->trigger['value']['day'] = $day; if (!empty($hour)) $this->trigger['value']['hour'] = $hour; if (!empty($min)) $this->trigger['value']['min'] = $min; if (!empty($sec)) $this->trigger['value']['sec'] = $sec; return TRUE; } return FALSE; } /*********************************************************************************/ /** * Property Name: TZID */ /** * creates formatted output for calendar component property tzid * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createTzid() { if (empty($this->tzid)) return FALSE; if (empty($this->tzid['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('TZID') : FALSE; $attributes = $this->_createParams($this->tzid['params']); return $this->_createElement('TZID', $attributes, $this->_strrep($this->tzid['value'])); } /** * set calendar component property tzid * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param array $params optional * @return bool */ function setTzid($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->tzid = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * .. . * Property Name: TZNAME */ /** * creates formatted output for calendar component property tzname * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createTzname() { if (empty($this->tzname)) return FALSE; $output = null; foreach ($this->tzname as $theName) { if (!empty($theName['value'])) { $attributes = $this->_createParams($theName['params'], array('LANGUAGE')); $output .= $this->_createElement('TZNAME', $attributes, $this->_strrep($theName['value'])); } elseif ($this->getConfig('allowEmpty')) $output .= $this->_createElement('TZNAME'); } return $output; } /** * set calendar component property tzname * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param string $value * @param string $params , optional * @param integer $index , optional * @return bool */ function setTzname($value, $params = FALSE, $index = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->_setMval($this->tzname, $value, $params, FALSE, $index); return TRUE; } /*********************************************************************************/ /** * Property Name: TZOFFSETFROM */ /** * creates formatted output for calendar component property tzoffsetfrom * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createTzoffsetfrom() { if (empty($this->tzoffsetfrom)) return FALSE; if (empty($this->tzoffsetfrom['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('TZOFFSETFROM') : FALSE; $attributes = $this->_createParams($this->tzoffsetfrom['params']); return $this->_createElement('TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value']); } /** * set calendar component property tzoffsetfrom * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param string $params optional * @return bool */ function setTzoffsetfrom($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->tzoffsetfrom = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: TZOFFSETTO */ /** * creates formatted output for calendar component property tzoffsetto * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createTzoffsetto() { if (empty($this->tzoffsetto)) return FALSE; if (empty($this->tzoffsetto['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('TZOFFSETTO') : FALSE; $attributes = $this->_createParams($this->tzoffsetto['params']); return $this->_createElement('TZOFFSETTO', $attributes, $this->tzoffsetto['value']); } /** * set calendar component property tzoffsetto * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param string $params optional * @return bool */ function setTzoffsetto($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->tzoffsetto = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: TZURL */ /** * creates formatted output for calendar component property tzurl * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createTzurl() { if (empty($this->tzurl)) return FALSE; if (empty($this->tzurl['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('TZURL') : FALSE; $attributes = $this->_createParams($this->tzurl['params']); return $this->_createElement('TZURL', $attributes, $this->tzurl['value']); } /** * set calendar component property tzurl * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param string $params optional * @return boll */ function setTzurl($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->tzurl = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: UID */ /** * creates formatted output for calendar component property uid * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.7 - 2006-11-20 * @return string */ function createUid() { if (0 >= count($this->uid)) $this->_makeuid(); $attributes = $this->_createParams($this->uid['params']); return $this->_createElement('UID', $attributes, $this->uid['value']); } /** * create an unique id for this calendar component object instance * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.7 - 2007-09-04 * @return void */ function _makeUid() { $date = date('Ymd\THisT'); $unique = substr(microtime(), 2, 4); $base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890'; $start = 0; $end = strlen($base) - 1; $length = 6; $str = null; for ($p = 0; $p < $length; $p++) $unique .= $base{mt_rand($start, $end)}; $this->uid = array('params' => null); $this->uid['value'] = $date . '-' . $unique . '@' . $this->getConfig('unique_id'); } /** * set calendar component property uid * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param string $params optional * @return bool */ function setUid($value, $params = FALSE) { if (empty($value)) return FALSE; // no allowEmpty check here !!!! $this->uid = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: URL */ /** * creates formatted output for calendar component property url * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-21 * @return string */ function createUrl() { if (empty($this->url)) return FALSE; if (empty($this->url['value'])) return ($this->getConfig('allowEmpty')) ? $this->_createElement('URL') : FALSE; $attributes = $this->_createParams($this->url['params']); return $this->_createElement('URL', $attributes, $this->url['value']); } /** * set calendar component property url * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-11-04 * @param string $value * @param string $params optional * @return bool */ function setUrl($value, $params = FALSE) { if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $this->url = array('value' => $value, 'params' => $this->_setParams($params)); return TRUE; } /*********************************************************************************/ /** * Property Name: x-prop */ /** * creates formatted output for calendar component property x-prop * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.11 - 2008-10-22 * @return string */ function createXprop() { if (empty($this->xprop)) return FALSE; $output = null; foreach ($this->xprop as $label => $xpropPart) { if (empty($xpropPart['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement($label); continue; } $attributes = $this->_createParams($xpropPart['params'], array('LANGUAGE')); if (is_array($xpropPart['value'])) { foreach ($xpropPart['value'] as $pix => $theXpart) $xpropPart['value'][$pix] = $this->_strrep($theXpart); $xpropPart['value'] = implode(',', $xpropPart['value']); } else $xpropPart['value'] = $this->_strrep($xpropPart['value']); $output .= $this->_createElement($label, $attributes, $xpropPart['value']); } return $output; } /** * set calendar component property x-prop * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.11 - 2008-11-04 * @param string $label * @param mixed $value * @param array $params optional * @return bool */ function setXprop($label, $value, $params = FALSE) { if (empty($label)) return; if (empty($value)) if ($this->getConfig('allowEmpty')) $value = null; else return FALSE; $xprop = array('value' => $value); $toolbox = new calendarComponent(); $xprop['params'] = $toolbox->_setParams($params); if (!is_array($this->xprop)) $this->xprop = array(); $this->xprop[strtoupper($label)] = $xprop; return TRUE; } /*********************************************************************************/ /*********************************************************************************/ /** * create element format parts * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.0.6 - 2006-06-20 * @return string */ function _createFormat() { $objectname = null; switch ($this->format) { case 'xcal': $objectname = (isset($this->timezonetype)) ? strtolower($this->timezonetype) : strtolower($this->objName); $this->componentStart1 = $this->elementStart1 = '<'; $this->componentStart2 = $this->elementStart2 = '>'; $this->componentEnd1 = $this->elementEnd1 = '</'; $this->componentEnd2 = $this->elementEnd2 = '>' . $this->nl; $this->intAttrDelimiter = '<!-- -->'; $this->attributeDelimiter = $this->nl; $this->valueInit = null; break; default: $objectname = (isset($this->timezonetype)) ? strtoupper($this->timezonetype) : strtoupper($this->objName); $this->componentStart1 = 'BEGIN:'; $this->componentStart2 = null; $this->componentEnd1 = 'END:'; $this->componentEnd2 = $this->nl; $this->elementStart1 = null; $this->elementStart2 = null; $this->elementEnd1 = null; $this->elementEnd2 = $this->nl; $this->intAttrDelimiter = '<!-- -->'; $this->attributeDelimiter = ';'; $this->valueInit = ':'; break; } return $objectname; } /** * creates formatted output for calendar component property * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-23 * @param string $label property name * @param string $attributes property attributes * @param string $content property content (optional) * @return string */ function _createElement($label, $attributes = null, $content = FALSE) { $label = $this->_formatPropertyName($label); $output = $this->elementStart1 . $label; $categoriesAttrLang = null; $attachInlineBinary = FALSE; $attachfmttype = null; if (!empty($attributes)) { $attributes = trim($attributes); if ('xcal' == $this->format) { $attributes2 = explode($this->intAttrDelimiter, $attributes); $attributes = null; foreach ($attributes2 as $attribute) { $attrKVarr = explode('=', $attribute); if (empty($attrKVarr[0])) continue; if (!isset($attrKVarr[1])) { $attrValue = $attrKVarr[0]; $attrKey = null; } elseif (2 == count($attrKVarr)) { $attrKey = strtolower($attrKVarr[0]); $attrValue = $attrKVarr[1]; } else { $attrKey = strtolower($attrKVarr[0]); unset($attrKVarr[0]); $attrValue = implode('=', $attrKVarr); } if (('attach' == $label) && (in_array($attrKey, array('fmttype', 'encoding', 'value')))) { $attachInlineBinary = TRUE; if ('fmttype' == $attrKey) $attachfmttype = $attrKey . '=' . $attrValue; continue; } elseif (('categories' == $label) && ('language' == $attrKey)) $categoriesAttrLang = $attrKey . '=' . $attrValue; else { $attributes .= (empty($attributes)) ? ' ' : $this->attributeDelimiter . ' '; $attributes .= (!empty($attrKey)) ? $attrKey . '=' : null; if (('"' == substr($attrValue, 0, 1)) && ('"' == substr($attrValue, -1))) { $attrValue = substr($attrValue, 1, (strlen($attrValue) - 2)); $attrValue = str_replace('"', '', $attrValue); } $attributes .= '"' . htmlspecialchars($attrValue) . '"'; } } } else { $attributes = str_replace($this->intAttrDelimiter, $this->attributeDelimiter, $attributes); } } if (((('attach' == $label) && !$attachInlineBinary) || (in_array($label, array('tzurl', 'url')))) && ('xcal' == $this->format) ) { $pos = strrpos($content, "/"); $docname = ($pos !== false) ? substr($content, (1 - strlen($content) + $pos)) : $content; $this->xcaldecl[] = array('xmldecl' => 'ENTITY' , 'uri' => $docname , 'ref' => 'SYSTEM' , 'external' => $content , 'type' => 'NDATA' , 'type2' => 'BINERY'); $attributes .= (empty($attributes)) ? ' ' : $this->attributeDelimiter . ' '; $attributes .= 'uri="' . $docname . '"'; $content = null; if ('attach' == $label) { $attributes = str_replace($this->attributeDelimiter, $this->intAttrDelimiter, $attributes); $content = $this->_createElement('extref', $attributes, null); $attributes = null; } } elseif (('attach' == $label) && $attachInlineBinary && ('xcal' == $this->format)) { $content = $this->nl . $this->_createElement('b64bin', $attachfmttype, $content); // max one attribute } $output .= $attributes; if (!$content) { switch ($this->format) { case 'xcal': $output .= ' /'; $output .= $this->elementStart2; return $output; break; default: $output .= $this->elementStart2 . $this->valueInit; return $this->_size75($output); break; } } $output .= $this->elementStart2; $output .= $this->valueInit . $content; switch ($this->format) { case 'xcal': return $output . $this->elementEnd1 . $label . $this->elementEnd2; break; default: return $this->_size75($output); break; } } /** * creates formatted output for calendar component property parameters * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.22 - 2007-04-10 * @param array $params optional * @param array $ctrKeys optional * @return string */ function _createParams($params = array(), $ctrKeys = array()) { $attrLANG = $attr1 = $attr2 = null; $CNattrKey = (in_array('CN', $ctrKeys)) ? TRUE : FALSE; $LANGattrKey = (in_array('LANGUAGE', $ctrKeys)) ? TRUE : FALSE; $CNattrExist = $LANGattrExist = FALSE; if (is_array($params)) { foreach ($params as $paramKey => $paramValue) { if (is_int($paramKey)) $attr2 .= $this->intAttrDelimiter . $paramValue; elseif (('LANGUAGE' == $paramKey) && $LANGattrKey) { $attrLANG .= $this->intAttrDelimiter . "LANGUAGE=$paramValue"; $LANGattrExist = TRUE; } elseif (('CN' == $paramKey) && $CNattrKey) { $attr1 = $this->intAttrDelimiter . 'CN="' . $paramValue . '"'; $CNattrExist = TRUE; } elseif (('ALTREP' == $paramKey) && in_array($paramKey, $ctrKeys)) $attr2 .= $this->intAttrDelimiter . 'ALTREP="' . $paramValue . '"'; elseif (('DIR' == $paramKey) && in_array($paramKey, $ctrKeys)) $attr2 .= $this->intAttrDelimiter . 'DIR="' . $paramValue . '"'; elseif (('SENT-BY' == $paramKey) && in_array($paramKey, $ctrKeys)) $attr2 .= $this->intAttrDelimiter . 'SENT-BY="MAILTO:' . $paramValue . '"'; else $attr2 .= $this->intAttrDelimiter . "$paramKey=$paramValue"; } } if (!$LANGattrExist) { $lang = $this->getConfig('language'); if (($CNattrExist || $LANGattrKey) && $lang) $attrLANG .= $this->intAttrDelimiter . 'LANGUAGE=' . $lang; } return $attrLANG . $attr1 . $attr2; } /** * check a date(-time) for an opt. timezone and if it is a DATE-TIME or DATE * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-25 * @param array $date , date to check * @param int $parno , no of date parts (i.e. year, month.. .) * @return array $params, property parameters */ function _chkdatecfg($theDate, & $parno, & $params) { if (isset($params['TZID'])) $parno = 6; elseif (isset($params['VALUE']) && ('DATE' == $params['VALUE'])) $parno = 3; else { if (isset($params['VALUE']) && ('PERIOD' == $params['VALUE'])) $parno = 7; if (is_array($theDate)) { if (isset($theDate['timestamp'])) $tzid = (isset($theDate['tz'])) ? $theDate['tz'] : null; else $tzid = (isset($theDate['tz'])) ? $theDate['tz'] : (7 == count($theDate)) ? end($theDate) : null; if (!empty($tzid)) { $parno = 7; if (!$this->_isOffset($tzid)) $params['TZID'] = $tzid; // save only timezone } elseif (!$parno && (3 == count($theDate)) && (isset($params['VALUE']) && ('DATE' == $params['VALUE'])) ) $parno = 3; else $parno = 6; } else { // string $date = trim($theDate); if ('Z' == substr($date, -1)) $parno = 7; // UTC DATE-TIME elseif (((8 == strlen($date) && ctype_digit($date)) || (11 >= strlen($date))) && (!isset($params['VALUE']) || !in_array($params['VALUE'], array('DATE-TIME', 'PERIOD'))) ) $parno = 3; // DATE $date = $this->_date_time_string($date, $parno); if (!empty($date['tz'])) { $parno = 7; if (!$this->_isOffset($date['tz'])) $params['TZID'] = $date['tz']; // save only timezone } elseif (empty($parno)) $parno = 6; } if (isset($params['TZID'])) $parno = 6; } } /** * convert local startdate/enddate (Ymd[His]) to duration * * uses this component dates if missing input dates * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.11 - 2007-11-03 * @param array $startdate , optional * @param array $duration , optional * @return array duration */ function _date2duration($startdate = FALSE, $enddate = FALSE) { if (!$startdate || !$enddate) { if (FALSE === ($startdate = $this->getProperty('dtstart'))) return null; if (FALSE === ($enddate = $this->getProperty('dtend'))) // vevent/vfreebusy if (FALSE === ($enddate = $this->getProperty('due'))) // vtodo return null; } if (!$startdate || !$enddate) return null; $startWdate = mktime(0, 0, 0, $startdate['month'], $startdate['day'], $startdate['year']); $endWdate = mktime(0, 0, 0, $enddate['month'], $enddate['day'], $enddate['year']); $wduration = $endWdate - $startWdate; $dur = array(); $dur['week'] = (int)floor($wduration / (7 * 24 * 60 * 60)); $wduration = $wduration % (7 * 24 * 60 * 60); $dur['day'] = (int)floor($wduration / (24 * 60 * 60)); $wduration = $wduration % (24 * 60 * 60); $dur['hour'] = (int)floor($wduration / (60 * 60)); $wduration = $wduration % (60 * 60); $dur['min'] = (int)floor($wduration / (60)); $dur['sec'] = (int)$wduration % (60); return $dur; } /** * convert date/datetime to timestamp * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-30 * @param array $datetime datetime/(date) * @param string $tz timezone * @return timestamp */ function _date2timestamp($datetime, $tz = null) { $output = null; if (!isset($datetime['hour'])) $datetime['hour'] = '0'; if (!isset($datetime['min'])) $datetime['min'] = '0'; if (!isset($datetime['sec'])) $datetime['sec'] = '0'; foreach ($datetime as $dkey => $dvalue) { if ('tz' != $dkey) $datetime[$dkey] = (integer)$dvalue; } if ($tz) $datetime['tz'] = $tz; $offset = (isset($datetime['tz']) && ('' < trim($datetime['tz']))) ? $this->_tz2offset($datetime['tz']) : 0; $output = mktime($datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year']); return $output; } /** * ensures internal date-time/date format for input date-time/date in array format * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.3.0 - 2006-08-15 * @param array $datetime * @param int $parno optional, default FALSE * @return array */ function _date_time_array($datetime, $parno = FALSE) { $output = array(); foreach ($datetime as $dateKey => $datePart) { switch ($dateKey) { case '0': case 'year': $output['year'] = $datePart; break; case '1': case 'month': $output['month'] = $datePart; break; case '2': case 'day': $output['day'] = $datePart; break; } if (3 != $parno) { switch ($dateKey) { case '0': case '1': case '2': break; case '3': case 'hour': $output['hour'] = $datePart; break; case '4': case 'min' : $output['min'] = $datePart; break; case '5': case 'sec' : $output['sec'] = $datePart; break; case '6': case 'tz' : $output['tz'] = $datePart; break; } } } if (3 != $parno) { if (!isset($output['hour'])) $output['hour'] = 0; if (!isset($output['min'])) $output['min'] = 0; if (!isset($output['sec'])) $output['sec'] = 0; } return $output; } /** * ensures internal date-time/date format for input date-time/date in string fromat * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.10 - 2007-10-19 * @param array $datetime * @param int $parno optional, default FALSE * @return array */ function _date_time_string($datetime, $parno = FALSE) { $datetime = (string)trim($datetime); $tz = null; $len = strlen($datetime) - 1; if ('Z' == substr($datetime, -1)) { $tz = 'Z'; $datetime = trim(substr($datetime, 0, $len)); } elseif ((ctype_digit(substr($datetime, -2, 2))) && // time or date ('-' == substr($datetime, -3, 1)) || (':' == substr($datetime, -3, 1)) || ('.' == substr($datetime, -3, 1)) ) { $continue = TRUE; } elseif ((ctype_digit(substr($datetime, -4, 4))) && // 4 pos offset (' +' == substr($datetime, -6, 2)) || (' -' == substr($datetime, -6, 2)) ) { $tz = substr($datetime, -5, 5); $datetime = substr($datetime, 0, ($len - 5)); } elseif ((ctype_digit(substr($datetime, -6, 6))) && // 6 pos offset (' +' == substr($datetime, -8, 2)) || (' -' == substr($datetime, -8, 2)) ) { $tz = substr($datetime, -7, 7); $datetime = substr($datetime, 0, ($len - 7)); } elseif ((6 < $len) && (ctype_digit(substr($datetime, -6, 6)))) { $continue = TRUE; } elseif ('T' == substr($datetime, -7, 1)) { $continue = TRUE; } else { $cx = $tx = 0; // 19970415T133000 US-Eastern for ($cx = -1; $cx > (9 - $len); $cx--) { if ((' ' == substr($datetime, $cx, 1)) || ctype_digit(substr($datetime, $cx, 1))) break; // if exists, tz ends here.. . ? elseif (ctype_alpha(substr($datetime, $cx, 1)) || (in_array(substr($datetime, $cx, 1), array('-', '/'))) ) $tx--; // tz length counter } if (0 > $tx) { $tz = substr($datetime, $tx); $datetime = trim(substr($datetime, 0, $len + $tx + 1)); } } if (0 < substr_count($datetime, '-')) { $datetime = str_replace('-', '/', $datetime); } elseif (ctype_digit(substr($datetime, 0, 8)) && ('T' == substr($datetime, 8, 1)) && ctype_digit(substr($datetime, 9, 6)) ) { $datetime = substr($datetime, 4, 2) . '/' . substr($datetime, 6, 2) . '/' . substr($datetime, 0, 4) . ' ' . substr($datetime, 9, 2) . ':' . substr($datetime, 11, 2) . ':' . substr($datetime, 13); } $datestring = date('Y-m-d H:i:s', strtotime($datetime)); $tz = trim($tz); $output = array(); $output['year'] = substr($datestring, 0, 4); $output['month'] = substr($datestring, 5, 2); $output['day'] = substr($datestring, 8, 2); if ((6 == $parno) || (7 == $parno)) { $output['hour'] = substr($datestring, 11, 2); $output['min'] = substr($datestring, 14, 2); $output['sec'] = substr($datestring, 17, 2); if (!empty($tz)) $output['tz'] = $tz; } elseif (3 != $parno) { if (('00' < substr($datestring, 11, 2)) || ('00' < substr($datestring, 14, 2)) || ('00' < substr($datestring, 17, 2)) ) { $output['hour'] = substr($datestring, 11, 2); $output['min'] = substr($datestring, 14, 2); $output['sec'] = substr($datestring, 17, 2); } if (!empty($tz)) $output['tz'] = $tz; } return $output; } /** * ensures internal duration format for input in array format * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.1.1 - 2007-06-24 * @param array $duration * @return array */ function _duration_array($duration) { $output = array(); if (is_array($duration) && (1 == count($duration)) && isset($duration['sec']) && (60 < $duration['sec']) ) { $durseconds = $duration['sec']; $output['week'] = floor($durseconds / (60 * 60 * 24 * 7)); $durseconds = $durseconds % (60 * 60 * 24 * 7); $output['day'] = floor($durseconds / (60 * 60 * 24)); $durseconds = $durseconds % (60 * 60 * 24); $output['hour'] = floor($durseconds / (60 * 60)); $durseconds = $durseconds % (60 * 60); $output['min'] = floor($durseconds / (60)); $output['sec'] = ($durseconds % (60)); } else { foreach ($duration as $durKey => $durValue) { if (empty($durValue)) continue; switch ($durKey) { case '0': case 'week': $output['week'] = $durValue; break; case '1': case 'day': $output['day'] = $durValue; break; case '2': case 'hour': $output['hour'] = $durValue; break; case '3': case 'min': $output['min'] = $durValue; break; case '4': case 'sec': $output['sec'] = $durValue; break; } } } if (isset($output['week']) && (0 < $output['week'])) { unset($output['day'], $output['hour'], $output['min'], $output['sec']); return $output; } unset($output['week']); if (empty($output['day'])) unset($output['day']); if (isset($output['hour']) || isset($output['min']) || isset($output['sec'])) { if (!isset($output['hour'])) $output['hour'] = 0; if (!isset($output['min'])) $output['min'] = 0; if (!isset($output['sec'])) $output['sec'] = 0; if ((0 == $output['hour']) && (0 == $output['min']) && (0 == $output['sec'])) unset($output['hour'], $output['min'], $output['sec']); } return $output; } /** * convert duration to date in array format based on input or dtstart value * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-30 * @param array $startdate , optional * @param array $duration , optional * @return array, date format */ function duration2date($startdate = FALSE, $duration = FALSE) { if ($startdate && $duration) { $d1 = $startdate; $dur = $duration; } elseif (isset($this->dtstart['value']) && isset($this->duration['value'])) { $d1 = $this->dtstart['value']; $dur = $this->duration['value']; } else return null; $dateOnly = (isset($d1['hour']) || isset($d1['min']) || isset($d1['sec'])) ? FALSE : TRUE; $d1['hour'] = (isset($d1['hour'])) ? $d1['hour'] : 0; $d1['min'] = (isset($d1['min'])) ? $d1['min'] : 0; $d1['sec'] = (isset($d1['sec'])) ? $d1['sec'] : 0; $dtend = mktime($d1['hour'], $d1['min'], $d1['sec'], $d1['month'], $d1['day'], $d1['year']); if (isset($dur['week'])) $dtend += ($dur['week'] * 7 * 24 * 60 * 60); if (isset($dur['day'])) $dtend += ($dur['day'] * 24 * 60 * 60); if (isset($dur['hour'])) $dtend += ($dur['hour'] * 60 * 60); if (isset($dur['min'])) $dtend += ($dur['min'] * 60); if (isset($dur['sec'])) $dtend += $dur['sec']; $dtend2 = array(); $dtend2['year'] = date('Y', $dtend); $dtend2['month'] = date('m', $dtend); $dtend2['day'] = date('d', $dtend); $dtend2['hour'] = date('H', $dtend); $dtend2['min'] = date('i', $dtend); $dtend2['sec'] = date('s', $dtend); if (isset($d1['tz'])) $dtend2['tz'] = $d1['tz']; if ($dateOnly && ((0 == $dtend2['hour']) && (0 == $dtend2['min']) && (0 == $dtend2['sec']))) unset($dtend2['hour'], $dtend2['min'], $dtend2['sec']); return $dtend2; } /** * ensures internal duration format for input in string format * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.0.5 - 2007-03-14 * @param string $duration * @return array */ function _duration_string($duration) { $duration = (string)trim($duration); while ('P' != strtoupper(substr($duration, 0, 1))) { if (0 < strlen($duration)) $duration = substr($duration, 1); else return false; // no leading P !?!? } $duration = substr($duration, 1); // skip P $duration = str_replace('t', 'T', $duration); $duration = str_replace('T', '', $duration); $output = array(); $val = null; for ($ix = 0; $ix < strlen($duration); $ix++) { switch (strtoupper($duration{$ix})) { case 'W': $output['week'] = $val; $val = null; break; case 'D': $output['day'] = $val; $val = null; break; case 'H': $output['hour'] = $val; $val = null; break; case 'M': $output['min'] = $val; $val = null; break; case 'S': $output['sec'] = $val; $val = null; break; default: if (!ctype_digit($duration{$ix})) return false; // unknown duration controll character !?!? else $val .= $duration{$ix}; } } return $this->_duration_array($output); } /** * if not preSet, if exist, remove key with expected value from array and return hit value else return elseValue * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-11-08 * @param array $array * @param string $expkey , expected key * @param string $expval , expected value * @param int $hitVal optional, return value if found * @param int $elseVal optional, return value if not found * @param int $preSet optional, return value if already preset * @return int */ function _existRem(&$array, $expkey, $expval = FALSE, $hitVal = null, $elseVal = null, $preSet = null) { if ($preSet) return $preSet; if (!is_array($array) || (0 == count($array))) return $elseVal; foreach ($array as $key => $value) { if (strtoupper($expkey) == strtoupper($key)) { if (!$expval || (strtoupper($expval) == strtoupper($array[$key]))) { unset($array[$key]); return $hitVal; } } } return $elseVal; } /** * creates formatted output for calendar component property data value type date/date-time * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-30 * @param array $datetime * @param int $parno , optional, default 6 * @return string */ function _format_date_time($datetime, $parno = 6) { if (!isset($datetime['year']) && !isset($datetime['month']) && !isset($datetime['day']) && !isset($datetime['hour']) && !isset($datetime['min']) && !isset($datetime['sec']) ) return; $output = null; // if( !isset( $datetime['day'] )) { $o=''; foreach($datetime as $k=>$v) {if(is_array($v)) $v=implode('-',$v);$o.=" $k=>$v";} echo " day SAKNAS : $o <br />\n"; } foreach ($datetime as $dkey => $dvalue) { if ('tz' != $dkey) $datetime[$dkey] = (integer)$dvalue; } $output = date('Ymd', mktime(0, 0, 0, $datetime['month'], $datetime['day'], $datetime['year'])); if (isset($datetime['hour']) || isset($datetime['min']) || isset($datetime['sec']) || isset($datetime['tz']) ) { if (isset($datetime['tz']) && !isset($datetime['hour']) ) $datetime['hour'] = 0; if (isset($datetime['hour']) && !isset($datetime['min']) ) $datetime['min'] = 0; if (isset($datetime['hour']) && isset($datetime['min']) && !isset($datetime['sec']) ) $datetime['sec'] = 0; $date = mktime($datetime['hour'], $datetime['min'], $datetime['sec'], $datetime['month'], $datetime['day'], $datetime['year']); $output .= date('\THis', $date); if (isset($datetime['tz']) && ('' < trim($datetime['tz']))) { $datetime['tz'] = trim($datetime['tz']); if ('Z' == $datetime['tz']) $output .= 'Z'; $offset = $this->_tz2offset($datetime['tz']); if (0 != $offset) { $date = mktime($datetime['hour'], $datetime['min'], ($datetime['sec'] + $offset), $datetime['month'], $datetime['day'], $datetime['year']); $output = date('Ymd\THis\Z', $date); } } elseif (7 == $parno) $output .= 'Z'; } return $output; } /** * creates formatted output for calendar component property data value type duration * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-10 * @param array $duration ( week, day, hour, min, sec ) * @return string */ function _format_duration($duration) { if (!isset($duration['week']) && !isset($duration['day']) && !isset($duration['hour']) && !isset($duration['min']) && !isset($duration['sec']) ) return; $output = 'P'; if (isset($duration['week']) && (0 < $duration['week'])) $output .= $duration['week'] . 'W'; else { if (isset($duration['day']) && (0 < $duration['day'])) $output .= $duration['day'] . 'D'; if ((isset($duration['hour']) && (0 < $duration['hour'])) || (isset($duration['min']) && (0 < $duration['min'])) || (isset($duration['sec']) && (0 < $duration['sec'])) ) { $output .= 'T'; $output .= (isset($duration['hour']) && (0 < $duration['hour'])) ? $duration['hour'] . 'H' : '0H'; $output .= (isset($duration['min']) && (0 < $duration['min'])) ? $duration['min'] . 'M' : '0M'; $output .= (isset($duration['sec']) && (0 < $duration['sec'])) ? $duration['sec'] . 'S' : '0S'; } } return $output; } /** * creates formatted output for calendar component property data value type recur * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-22 * @param array $recurlabel * @param array $recurdata * @return string */ function _format_recur($recurlabel, $recurdata) { $output = null; foreach ($recurdata as $therule) { if (empty($therule['value'])) { if ($this->getConfig('allowEmpty')) $output .= $this->_createElement($recurlabel); continue; } $attributes = (isset($therule['params'])) ? $this->_createParams($therule['params']) : null; $content1 = $content2 = null; foreach ($therule['value'] as $rulelabel => $rulevalue) { switch ($rulelabel) { case 'FREQ': { $content1 .= "FREQ=$rulevalue"; break; } case 'UNTIL': { $content2 .= ";UNTIL="; $content2 .= $this->_format_date_time($rulevalue); break; } case 'COUNT': case 'INTERVAL': case 'WKST': { $content2 .= ";$rulelabel=$rulevalue"; break; } case 'BYSECOND': case 'BYMINUTE': case 'BYHOUR': case 'BYMONTHDAY': case 'BYYEARDAY': case 'BYWEEKNO': case 'BYMONTH': case 'BYSETPOS': { $content2 .= ";$rulelabel="; if (is_array($rulevalue)) { foreach ($rulevalue as $vix => $valuePart) { $content2 .= ($vix) ? ',' : null; $content2 .= $valuePart; } } else $content2 .= $rulevalue; break; } case 'BYDAY': { $content2 .= ";$rulelabel="; $bydaycnt = 0; foreach ($rulevalue as $vix => $valuePart) { $content21 = $content22 = null; if (is_array($valuePart)) { $content2 .= ($bydaycnt) ? ',' : null; foreach ($valuePart as $vix2 => $valuePart2) { if ('DAY' != strtoupper($vix2)) $content21 .= $valuePart2; else $content22 .= $valuePart2; } $content2 .= $content21 . $content22; $bydaycnt++; } else { $content2 .= ($bydaycnt) ? ',' : null; if ('DAY' != strtoupper($vix)) $content21 .= $valuePart; else { $content22 .= $valuePart; $bydaycnt++; } $content2 .= $content21 . $content22; } } break; } default: { $content2 .= ";$rulelabel=$rulevalue"; break; } } } $output .= $this->_createElement($recurlabel, $attributes, $content1 . $content2); } return $output; } /** * create property name case - lower/upper * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 0.9.7 - 2006-11-20 * @param string $propertyName * @return string */ function _formatPropertyName($propertyName) { switch ($this->format) { case 'xcal': return strtolower($propertyName); break; default: return strtoupper($propertyName); break; } } /** * checks if input array contains a date * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-25 * @param array $input * @return bool */ function _isArrayDate($input) { if (isset($input['week']) || (!in_array(count($input), array(3, 6, 7)))) return FALSE; if (7 == count($input)) return TRUE; if (isset($input['year']) && isset($input['month']) && isset($input['day'])) return checkdate((int)$input['month'], (int)$input['day'], (int)$input['year']); if (isset($input['day']) || isset($input['hour']) || isset($input['min']) || isset($input['sec'])) return FALSE; if (in_array(0, $input)) return FALSE; if ((1970 > $input[0]) || (12 < $input[1]) || (31 < $input[2])) return FALSE; if ((isset($input[0]) && isset($input[1]) && isset($input[2])) && checkdate((int)$input[1], (int)$input[2], (int)$input[0]) ) return TRUE; $input = $this->_date_time_string($input[1] . '/' . $input[2] . '/' . $input[0], 3); // m - d - Y if (isset($input['year']) && isset($input['month']) && isset($input['day'])) return checkdate((int)$input['month'], (int)$input['day'], (int)$input['year']); return FALSE; } /** * checks if input array contains a timestamp date * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-18 * @param array $input * @return bool */ function _isArrayTimestampDate($input) { return (is_array($input) && isset($input['timestamp'])) ? TRUE : FALSE; } /** * controll if input string contains traling UTC offset * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-19 * @param string $input * @return bool */ function _isOffset($input) { $input = trim((string)$input); if ('Z' == substr($input, -1)) return TRUE; elseif ((5 <= strlen($input)) && (in_array(substr($input, -5, 1), array('+', '-'))) && ('0000' < substr($input, -4)) && ('9999' >= substr($input, -4)) ) return TRUE; elseif ((7 <= strlen($input)) && (in_array(substr($input, -7, 1), array('+', '-'))) && ('000000' < substr($input, -6)) && ('999999' >= substr($input, -6)) ) return TRUE; return FALSE; } /** * check if property not exists within component * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-15 * @param string $propName * @return bool */ function _notExistProp($propName) { if (empty($propName)) return FALSE; // when deleting x-prop, an empty propName may be used=allowed $propName = strtolower($propName); if ('last-modified' == $propName) { if (!isset($this->lastmodified)) return TRUE; } elseif ('percent-complete' == $propName) { if (!isset($this->percentcomplete)) return TRUE; } elseif ('recurrence-id' == $propName) { if (!isset($this->recurrenceid)) return TRUE; } elseif ('related-to' == $propName) { if (!isset($this->relatedto)) return TRUE; } elseif ('request-status' == $propName) { if (!isset($this->requeststatus)) return TRUE; } elseif (('x-' != substr($propName, 0, 2)) && !isset($this->$propName)) return TRUE; return FALSE; } /** * remakes a recur pattern to an array of dates * * if missing, UNTIL is set 1 year from startdate (emergency break) * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-18 * @param array $result , array to update, array([timestamp] => timestamp) * @param array $recur , pattern for recurrency (only value part, params ignored) * @param array $wdate , component start date * @param array $startdate , start date * @param array $enddate , optional * @return array of recurrence (start-)dates as index * @todo BYHOUR, BYMINUTE, BYSECOND, ev. BYSETPOS due to ambiguity, WEEKLY at year end/start */ function _recur2date(& $result, $recur, $wdate, $startdate, $enddate = FALSE) { foreach ($wdate as $k => $v) if (ctype_digit($v)) $wdate[$k] = (int)$v; $wdatets = $this->_date2timestamp($wdate); $startdatets = $this->_date2timestamp($startdate); if (!$enddate) { $enddate = $startdate; $enddate['year'] += 1; // echo "recur __in_ ".implode('-',$startdate)." period start ".implode('-',$wdate)." period end ".implode('-',$enddate)."<br />\n";print_r($recur);echo "<br />\n";//test### } $endDatets = $this->_date2timestamp($enddate); // fix break if (!isset($recur['COUNT']) && !isset($recur['UNTIL'])) $recur['UNTIL'] = $enddate; // create break if (isset($recur['UNTIL'])) { $tdatets = $this->_date2timestamp($recur['UNTIL']); if ($endDatets > $tdatets) { $endDatets = $tdatets; // emergency break $enddate = $this->_timestamp2date($endDatets, 6); } else $recur['UNTIL'] = $this->_timestamp2date($endDatets, 6); } if ($wdatets > $endDatets) { //echo "recur out of date ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test return array(); // nothing to do.. . } if (!isset($recur['FREQ'])) // "MUST be specified.. ." $recur['FREQ'] = 'DAILY'; // ?? $wkst = (isset($recur['WKST']) && ('SU' == $recur['WKST'])) ? 24 * 60 * 60 : 0; // ?? if (!isset($recur['INTERVAL'])) $recur['INTERVAL'] = 1; $countcnt = (!isset($recur['BYSETPOS'])) ? 1 : 0; // DTSTART counts as the first occurrence /* find out how to step up dates and set index for interval count */ $step = array(); if ('YEARLY' == $recur['FREQ']) $step['year'] = 1; elseif ('MONTHLY' == $recur['FREQ']) $step['month'] = 1; elseif ('WEEKLY' == $recur['FREQ']) $step['day'] = 7; else $step['day'] = 1; if (isset($step['year']) && isset($recur['BYMONTH'])) $step = array('month' => 1); if (empty($step) && isset($recur['BYWEEKNO'])) // ?? $step = array('day' => 7); if (isset($recur['BYYEARDAY']) || isset($recur['BYMONTHDAY']) || isset($recur['BYDAY'])) $step = array('day' => 1); $intervalarr = array(); if (1 < $recur['INTERVAL']) { $intervalix = $this->_recurIntervalIx($recur['FREQ'], $wdate, $wkst); $intervalarr = array($intervalix => 0); } if (isset($recur['BYSETPOS'])) { // save start date + weekno $bysetposymd1 = $bysetposymd2 = $bysetposw1 = $bysetposw2 = array(); $bysetposWold = (int)date('W', ($wdatets + $wkst)); $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; $bysetposDold = $wdate['day']; if (is_array($recur['BYSETPOS'])) { foreach ($recur['BYSETPOS'] as $bix => $bval) $recur['BYSETPOS'][$bix] = (int)$bval; } else $recur['BYSETPOS'] = array((int)$recur['BYSETPOS']); $this->_stepdate($enddate, $endDatets, $step); // make sure to count whole last period } $this->_stepdate($wdate, $wdatets, $step); $year_old = null; $daynames = array('SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'); /* MAIN LOOP */ // echo "recur start ".implode('-',$wdate)." end ".implode('-',$enddate)."<br />\n";//test while (TRUE) { if (isset($endDatets) && ($wdatets > $endDatets)) break; if (isset($recur['COUNT']) && ($countcnt >= $recur['COUNT'])) break; if ($year_old != $wdate['year']) { $year_old = $wdate['year']; $daycnts = array(); $yeardays = $weekno = 0; $yeardaycnt = array(); for ($m = 1; $m <= 12; $m++) { // count up and update up-counters $daycnts[$m] = array(); $weekdaycnt = array(); foreach ($daynames as $dn) $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0; $mcnt = date('t', mktime(0, 0, 0, $m, 1, $wdate['year'])); for ($d = 1; $d <= $mcnt; $d++) { $daycnts[$m][$d] = array(); if (isset($recur['BYYEARDAY'])) { $yeardays++; $daycnts[$m][$d]['yearcnt_up'] = $yeardays; } if (isset($recur['BYDAY'])) { $day = date('w', mktime(0, 0, 0, $m, $d, $wdate['year'])); $day = $daynames[$day]; $daycnts[$m][$d]['DAY'] = $day; $weekdaycnt[$day]++; $daycnts[$m][$d]['monthdayno_up'] = $weekdaycnt[$day]; $yeardaycnt[$day]++; $daycnts[$m][$d]['yeardayno_up'] = $yeardaycnt[$day]; } if (isset($recur['BYWEEKNO']) || ($recur['FREQ'] == 'WEEKLY')) $daycnts[$m][$d]['weekno_up'] = (int)date('W', mktime(0, 0, $wkst, $m, $d, $wdate['year'])); } } $daycnt = 0; $yeardaycnt = array(); if (isset($recur['BYWEEKNO']) || ($recur['FREQ'] == 'WEEKLY')) { $weekno = null; for ($d = 31; $d > 25; $d--) { // get last weekno for year if (!$weekno) $weekno = $daycnts[12][$d]['weekno_up']; elseif ($weekno < $daycnts[12][$d]['weekno_up']) { $weekno = $daycnts[12][$d]['weekno_up']; break; } } } for ($m = 12; $m > 0; $m--) { // count down and update down-counters $weekdaycnt = array(); foreach ($daynames as $dn) $yeardaycnt[$dn] = $weekdaycnt[$dn] = 0; $monthcnt = 0; $mcnt = date('t', mktime(0, 0, 0, $m, 1, $wdate['year'])); for ($d = $mcnt; $d > 0; $d--) { if (isset($recur['BYYEARDAY'])) { $daycnt -= 1; $daycnts[$m][$d]['yearcnt_down'] = $daycnt; } if (isset($recur['BYMONTHDAY'])) { $monthcnt -= 1; $daycnts[$m][$d]['monthcnt_down'] = $monthcnt; } if (isset($recur['BYDAY'])) { $day = $daycnts[$m][$d]['DAY']; $weekdaycnt[$day] -= 1; $daycnts[$m][$d]['monthdayno_down'] = $weekdaycnt[$day]; $yeardaycnt[$day] -= 1; $daycnts[$m][$d]['yeardayno_down'] = $yeardaycnt[$day]; } if (isset($recur['BYWEEKNO']) || ($recur['FREQ'] == 'WEEKLY')) $daycnts[$m][$d]['weekno_down'] = ($daycnts[$m][$d]['weekno_up'] - $weekno - 1); } } } /* check interval */ if (1 < $recur['INTERVAL']) { /* create interval index */ $intervalix = $this->_recurIntervalIx($recur['FREQ'], $wdate, $wkst); /* check interval */ $currentKey = array_keys($intervalarr); $currentKey = end($currentKey); // get last index if ($currentKey != $intervalix) $intervalarr = array($intervalix => ($intervalarr[$currentKey] + 1)); if (($recur['INTERVAL'] != $intervalarr[$intervalix]) && (0 != $intervalarr[$intervalix]) ) { /* step up date */ //echo "skip: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test $this->_stepdate($wdate, $wdatets, $step); continue; } else // continue within the selected interval $intervalarr[$intervalix] = 0; //echo "cont: ".implode('-',$wdate)." ix=$intervalix old=$currentKey interval=".$intervalarr[$intervalix]."<br />\n";//test } $updateOK = TRUE; if ($updateOK && isset($recur['BYMONTH'])) $updateOK = $this->_recurBYcntcheck($recur['BYMONTH'] , $wdate['month'] , ($wdate['month'] - 13)); if ($updateOK && isset($recur['BYWEEKNO'])) $updateOK = $this->_recurBYcntcheck($recur['BYWEEKNO'] , $daycnts[$wdate['month']][$wdate['day']]['weekno_up'] , $daycnts[$wdate['month']][$wdate['day']]['weekno_down']); if ($updateOK && isset($recur['BYYEARDAY'])) $updateOK = $this->_recurBYcntcheck($recur['BYYEARDAY'] , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_up'] , $daycnts[$wdate['month']][$wdate['day']]['yearcnt_down']); if ($updateOK && isset($recur['BYMONTHDAY'])) $updateOK = $this->_recurBYcntcheck($recur['BYMONTHDAY'] , $wdate['day'] , $daycnts[$wdate['month']][$wdate['day']]['monthcnt_down']); //echo "efter BYMONTHDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n";//test### if ($updateOK && isset($recur['BYDAY'])) { $updateOK = FALSE; $m = $wdate['month']; $d = $wdate['day']; if (isset($recur['BYDAY']['DAY'])) { // single day, opt with year/month day order no $daynoexists = $daynosw = $daynamesw = FALSE; if ($recur['BYDAY']['DAY'] == $daycnts[$m][$d]['DAY']) $daynamesw = TRUE; if (isset($recur['BYDAY'][0])) { $daynoexists = TRUE; if ((isset($recur['FREQ']) && ($recur['FREQ'] == 'MONTHLY')) || isset($recur['BYMONTH'])) $daynosw = $this->_recurBYcntcheck($recur['BYDAY'][0] , $daycnts[$m][$d]['monthdayno_up'] , $daycnts[$m][$d]['monthdayno_down']); elseif (isset($recur['FREQ']) && ($recur['FREQ'] == 'YEARLY')) $daynosw = $this->_recurBYcntcheck($recur['BYDAY'][0] , $daycnts[$m][$d]['yeardayno_up'] , $daycnts[$m][$d]['yeardayno_down']); } if (($daynoexists && $daynosw && $daynamesw) || (!$daynoexists && !$daynosw && $daynamesw) ) { $updateOK = TRUE; } //echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ### } else { foreach ($recur['BYDAY'] as $bydayvalue) { $daynoexists = $daynosw = $daynamesw = FALSE; if (isset($bydayvalue['DAY']) && ($bydayvalue['DAY'] == $daycnts[$m][$d]['DAY']) ) $daynamesw = TRUE; if (isset($bydayvalue[0])) { $daynoexists = TRUE; if ((isset($recur['FREQ']) && ($recur['FREQ'] == 'MONTHLY')) || isset($recur['BYMONTH']) ) $daynosw = $this->_recurBYcntcheck($bydayvalue['0'] , $daycnts[$m][$d]['monthdayno_up'] , $daycnts[$m][$d]['monthdayno_down']); elseif (isset($recur['FREQ']) && ($recur['FREQ'] == 'YEARLY')) $daynosw = $this->_recurBYcntcheck($bydayvalue['0'] , $daycnts[$m][$d]['yeardayno_up'] , $daycnts[$m][$d]['yeardayno_down']); } //echo "daynoexists:$daynoexists daynosw:$daynosw daynamesw:$daynamesw<br />\n"; // test ### if (($daynoexists && $daynosw && $daynamesw) || (!$daynoexists && !$daynosw && $daynamesw) ) { $updateOK = TRUE; break; } } } } //echo "efter BYDAY: ".implode('-',$wdate).' status: '; echo ($updateOK) ? 'TRUE' : 'FALSE'; echo "<br />\n"; // test ### /* check BYSETPOS */ if ($updateOK) { if (isset($recur['BYSETPOS']) && (in_array($recur['FREQ'], array('YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY'))) ) { if (isset($recur['WEEKLY'])) { if ($bysetposWold == $daycnts[$wdate['month']][$wdate['day']]['weekno_up']) $bysetposw1[] = $wdatets; else $bysetposw2[] = $wdatets; } else { if ((isset($recur['FREQ']) && ('YEARLY' == $recur['FREQ']) && ($bysetposYold == $wdate['year'])) || (isset($recur['FREQ']) && ('MONTHLY' == $recur['FREQ']) && (($bysetposYold == $wdate['year']) && ($bysetposMold == $wdate['month']))) || (isset($recur['FREQ']) && ('MONTHLY' == $recur['FREQ']) && (($bysetposYold == $wdate['year']) && ($bysetposMold == $wdate['month']) && ($bysetposDold == $wdate['sday']))) ) $bysetposymd1[] = $wdatets; else $bysetposymd2[] = $wdatets; } } else { /* update result array if BYSETPOS is set */ $countcnt++; if ($startdatets <= $wdatets) { // only output within period $result[$wdatets] = TRUE; //echo "recur ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$wdatets),6))."<br />\n";//test } //else echo "recur undate ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$wdatets),6))." okdatstart ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$startdatets),6))."<br />\n";//test $updateOK = FALSE; } } /* step up date */ $this->_stepdate($wdate, $wdatets, $step); /* check if BYSETPOS is set for updating result array */ if ($updateOK && isset($recur['BYSETPOS'])) { $bysetpos = FALSE; if (isset($recur['FREQ']) && ('YEARLY' == $recur['FREQ']) && ($bysetposYold != $wdate['year']) ) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; } elseif (isset($recur['FREQ']) && ('MONTHLY' == $recur['FREQ'] && (($bysetposYold != $wdate['year']) || ($bysetposMold != $wdate['month']))) ) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; } elseif (isset($recur['FREQ']) && ('WEEKLY' == $recur['FREQ'])) { $weekno = (int)date('W', mktime(0, 0, $wkst, $wdate['month'], $wdate['day'], $wdate['year'])); if ($bysetposWold != $weekno) { $bysetposWold = $weekno; $bysetpos = TRUE; } } elseif (isset($recur['FREQ']) && ('DAILY' == $recur['FREQ']) && (($bysetposYold != $wdate['year']) || ($bysetposMold != $wdate['month']) || ($bysetposDold != $wdate['sday'])) ) { $bysetpos = TRUE; $bysetposYold = $wdate['year']; $bysetposMold = $wdate['month']; $bysetposDold = $wdate['day']; } if ($bysetpos) { if (isset($recur['BYWEEKNO'])) { $bysetposarr1 = &$bysetposw1; $bysetposarr2 = &$bysetposw2; } else { $bysetposarr1 = &$bysetposymd1; $bysetposarr2 = &$bysetposymd2; } foreach ($recur['BYSETPOS'] as $ix) { if (0 > $ix) // both positive and negative BYSETPOS allowed $ix = (count($bysetposarr1) + $ix + 1); $ix--; if (isset($bysetposarr1[$ix])) { if ($startdatets <= $bysetposarr1[$ix]) { // only output within period $result[$bysetposarr1[$ix]] = TRUE; //echo "recur ".implode('-',$this->_date_time_string(date('Y-m-d H:i:s',$bysetposarr1[$ix]),6))."<br />\n";//test } $countcnt++; } if (isset($recur['COUNT']) && ($countcnt >= $recur['COUNT'])) break; } $bysetposarr1 = $bysetposarr2; $bysetposarr2 = array(); } } } } function _recurBYcntcheck($BYvalue, $upValue, $downValue) { if (is_array($BYvalue) && (in_array($upValue, $BYvalue) || in_array($downValue, $BYvalue)) ) return TRUE; elseif (($BYvalue == $upValue) || ($BYvalue == $downValue)) return TRUE; else return FALSE; } function _recurIntervalIx($freq, $date, $wkst) { /* create interval index */ switch ($freq) { case 'YEARLY': $intervalix = $date['year']; break; case 'MONTHLY': $intervalix = $date['year'] . '-' . $date['month']; break; case 'WEEKLY': $wdatets = $this->_date2timestamp($date); $intervalix = (int)date('W', ($wdatets + $wkst)); break; case 'DAILY': default: $intervalix = $date['year'] . '-' . $date['month'] . '-' . $date['day']; break; } return $intervalix; } /** * convert input format for exrule and rrule to internal format * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-19 * @param array $rexrule * @return array */ function _setRexrule($rexrule) { $input = array(); if (empty($rexrule)) return $input; foreach ($rexrule as $rexrulelabel => $rexrulevalue) { $rexrulelabel = strtoupper($rexrulelabel); if ('UNTIL' != $rexrulelabel) $input[$rexrulelabel] = $rexrulevalue; else { if ($this->_isArrayTimestampDate($rexrulevalue)) // timestamp date $input[$rexrulelabel] = $this->_timestamp2date($rexrulevalue, 6); elseif ($this->_isArrayDate($rexrulevalue)) // date-time $input[$rexrulelabel] = $this->_date_time_array($rexrulevalue, 6); elseif (8 <= strlen(trim($rexrulevalue))) // ex. 2006-08-03 10:12:18 $input[$rexrulelabel] = $this->_date_time_string($rexrulevalue); if ((3 < count($input[$rexrulelabel])) && !isset($input[$rexrulelabel]['tz'])) $input[$rexrulelabel]['tz'] = 'Z'; } } return $input; } /** * convert format for input date to internal date with parameters * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.17 - 2008-10-31 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param array $params optional * @param string $caller optional * @return array */ function _setDate($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE, $caller = null) { $input = $parno = null; $localtime = (('dtstart' == $caller) && in_array($this->objName, array('vtimezone', 'standard', 'daylight'))) ? TRUE : FALSE; if ($this->_isArrayDate($year)) { if ($localtime) unset ($month['VALUE'], $month['TZID']); $input['params'] = $this->_setParams($month, array('VALUE' => 'DATE-TIME')); if (isset($input['params']['TZID'])) { $input['params']['VALUE'] = 'DATE-TIME'; unset($year['tz']); } $hitval = ((!empty($year['tz']) || !empty($year[6]))) ? 7 : 6; $parno = $this->_existRem($input['params'], 'VALUE', 'DATE-TIME', $hitval); $parno = $this->_existRem($input['params'], 'VALUE', 'DATE', 3, count($year), $parno); $input['value'] = $this->_date_time_array($year, $parno); } elseif ($this->_isArrayTimestampDate($year)) { if ($localtime) unset ($month['VALUE'], $month['TZID']); $input['params'] = $this->_setParams($month, array('VALUE' => 'DATE-TIME')); if (isset($input['params']['TZID'])) { $input['params']['VALUE'] = 'DATE-TIME'; unset($year['tz']); } $parno = $this->_existRem($input['params'], 'VALUE', 'DATE', 3); $hitval = (isset($year['tz'])) ? 7 : 6; $parno = $this->_existRem($input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno); $input['value'] = $this->_timestamp2date($year, $parno); } elseif (8 <= strlen(trim($year))) { // ex. 2006-08-03 10:12:18 if ($localtime) unset ($month['VALUE'], $month['TZID']); $input['params'] = $this->_setParams($month, array('VALUE' => 'DATE-TIME')); if (isset($input['params']['TZID'])) { $input['params']['VALUE'] = 'DATE-TIME'; $parno = 6; } $parno = $this->_existRem($input['params'], 'VALUE', 'DATE-TIME', 7, $parno); $parno = $this->_existRem($input['params'], 'VALUE', 'DATE', 3, $parno, $parno); $input['value'] = $this->_date_time_string($year, $parno); } else { if (is_array($params)) { if ($localtime) unset ($params['VALUE'], $params['TZID']); $input['params'] = $this->_setParams($params, array('VALUE' => 'DATE-TIME')); } elseif (is_array($tz)) { $input['params'] = $this->_setParams($tz, array('VALUE' => 'DATE-TIME')); $tz = FALSE; } elseif (is_array($hour)) { $input['params'] = $this->_setParams($hour, array('VALUE' => 'DATE-TIME')); $hour = $min = $sec = $tz = FALSE; } if (isset($input['params']['TZID'])) { $tz = null; $input['params']['VALUE'] = 'DATE-TIME'; } $parno = $this->_existRem($input['params'], 'VALUE', 'DATE', 3); $hitval = (!empty($tz)) ? 7 : 6; $parno = $this->_existRem($input['params'], 'VALUE', 'DATE-TIME', $hitval, $parno, $parno); $input['value'] = array('year' => $year, 'month' => $month, 'day' => $day); if (3 != $parno) { $input['value']['hour'] = ($hour) ? $hour : '0'; $input['value']['min'] = ($min) ? $min : '0'; $input['value']['sec'] = ($sec) ? $sec : '0'; if (!empty($tz)) $input['value']['tz'] = $tz; } } if (3 == $parno) { $input['params']['VALUE'] = 'DATE'; unset($input['value']['tz']); unset($input['params']['TZID']); } elseif (isset($input['params']['TZID'])) unset($input['value']['tz']); if ($localtime) unset($input['value']['tz'], $input['params']['TZID']); if (isset($input['value']['tz'])) $input['value']['tz'] = (string)$input['value']['tz']; if (!empty($input['value']['tz']) && ('Z' != $input['value']['tz']) && (!$this->_isOffset($input['value']['tz'])) ) $input['params']['TZID'] = $input['value']['tz']; return $input; } /** * convert format for input date (UTC) to internal date with parameters * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.17 - 2008-10-31 * @param mixed $year * @param mixed $month optional * @param int $day optional * @param int $hour optional * @param int $min optional * @param int $sec optional * @param array $params optional * @return array */ function _setDate2($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE) { $input = null; if ($this->_isArrayDate($year)) { $input['value'] = $this->_date_time_array($year, 7); $input['params'] = $this->_setParams($month, array('VALUE' => 'DATE-TIME')); } elseif ($this->_isArrayTimestampDate($year)) { $input['value'] = $this->_timestamp2date($year, 7); $input['params'] = $this->_setParams($month, array('VALUE' => 'DATE-TIME')); } elseif (8 <= strlen(trim($year))) { // ex. 2006-08-03 10:12:18 $input['value'] = $this->_date_time_string($year, 7); $input['params'] = $this->_setParams($month, array('VALUE' => 'DATE-TIME')); } else { $input['value'] = array('year' => $year , 'month' => $month , 'day' => $day , 'hour' => $hour , 'min' => $min , 'sec' => $sec); $input['params'] = $this->_setParams($params, array('VALUE' => 'DATE-TIME')); } $parno = $this->_existRem($input['params'], 'VALUE', 'DATE-TIME', 7); // remove default if (!isset($input['value']['hour'])) $input['value']['hour'] = 0; if (!isset($input['value']['min'])) $input['value']['min'] = 0; if (!isset($input['value']['sec'])) $input['value']['sec'] = 0; if (!isset($input['value']['tz']) || !$this->_isOffset($input['value']['tz'])) $input['value']['tz'] = 'Z'; return $input; } /** * check index and set (an indexed) content in multiple value array * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-06 * @param array $valArr * @param mixed $value * @param array $params * @param array $defaults * @param int $index * @return void */ function _setMval(& $valArr, $value, $params = FALSE, $defaults = FALSE, $index = FALSE) { if (!is_array($valArr)) $valArr = array(); if ($index) $index = $index - 1; elseif (0 < count($valArr)) { $index = end(array_keys($valArr)); $index += 1; } else $index = 0; $valArr[$index] = array('value' => $value, 'params' => $this->_setParams($params, $defaults)); ksort($valArr); } /** * set input (formatted) parameters- component property attributes * * default parameters can be set, if missing * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 1.x.x - 2007-05-01 * @param array $params * @param array $defaults * @return array */ function _setParams($params, $defaults = FALSE) { if (!is_array($params)) $params = array(); $input = array(); foreach ($params as $paramKey => $paramValue) { if (is_array($paramValue)) { foreach ($paramValue as $pkey => $pValue) { if (('"' == substr($pValue, 0, 1)) && ('"' == substr($pValue, -1))) $paramValue[$pkey] = substr($pValue, 1, (strlen($pValue) - 2)); } } elseif (('"' == substr($paramValue, 0, 1)) && ('"' == substr($paramValue, -1))) $paramValue = substr($paramValue, 1, (strlen($paramValue) - 2)); if ('VALUE' == strtoupper($paramKey)) $input['VALUE'] = strtoupper($paramValue); else $input[strtoupper($paramKey)] = $paramValue; } if (is_array($defaults)) { foreach ($defaults as $paramKey => $paramValue) { if (!isset($input[$paramKey])) $input[$paramKey] = $paramValue; } } return (0 < count($input)) ? $input : null; } /** * step date, return updated date, array and timpstamp * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-18 * @param array $date , date to step * @param int $timestamp * @param array $step , default array( 'day' => 1 ) * @return void */ function _stepdate(&$date, &$timestamp, $step = array('day' => 1)) { foreach ($step as $stepix => $stepvalue) $date[$stepix] += $stepvalue; $timestamp = $this->_date2timestamp($date); $date = $this->_timestamp2date($timestamp, 6); foreach ($date as $k => $v) { if (ctype_digit($v)) $date[$k] = (int)$v; } } /** * convert timestamp to date array * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-11-01 * @param mixed $timestamp * @param int $parno * @return array */ function _timestamp2date($timestamp, $parno = 6) { if (is_array($timestamp)) { if ((7 == $parno) && !empty($timestamp['tz'])) $tz = $timestamp['tz']; $timestamp = $timestamp['timestamp']; } $output = array('year' => date('Y', $timestamp) , 'month' => date('m', $timestamp) , 'day' => date('d', $timestamp)); if (3 != $parno) { $output['hour'] = date('H', $timestamp); $output['min'] = date('i', $timestamp); $output['sec'] = date('s', $timestamp); if (isset($tz)) $output['tz'] = $tz; } return $output; } /** * convert (numeric) local time offset to seconds correcting localtime to GMT * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.16 - 2008-10-19 * @param string $offset * @return integer */ function _tz2offset($tz) { $tz = trim((string)$tz); $offset = 0; if (((5 != strlen($tz)) && (7 != strlen($tz))) || (('+' != substr($tz, 0, 1)) && ('-' != substr($tz, 0, 1))) || (('0000' >= substr($tz, 1, 4)) && ('9999' < substr($tz, 1, 4))) || ((7 == strlen($tz)) && ('00' > substr($tz, 5, 2)) && ('99' < substr($tz, 5, 2))) ) return $offset; $hours2sec = (int)substr($tz, 1, 2) * 3600; $min2sec = (int)substr($tz, 3, 2) * 60; $sec = (7 == strlen($tz)) ? (int)substr($tz, -2) : '00'; $offset = $hours2sec + $min2sec + $sec; $offset = ('-' == substr($tz, 0, 1)) ? $offset : -1 * $offset; return $offset; } /*********************************************************************************/ /*********************************************************************************/ /** * get general component config variables or info about subcomponents * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-02 * @param string $config * @return value */ function getConfig($config) { switch (strtoupper($config)) { case 'ALLOWEMPTY': return $this->allowEmpty; break; case 'COMPSINFO': unset($this->compix); $info = array(); if (isset($this->components)) { foreach ($this->components as $cix => $component) { if (empty($component)) continue; unset($component->propix); $info[$cix]['ordno'] = $cix + 1; $info[$cix]['type'] = $component->objName; $info[$cix]['uid'] = $component->getProperty('uid'); $info[$cix]['props'] = $component->getConfig('propinfo'); $info[$cix]['sub'] = $component->getConfig('compsinfo'); unset($component->propix); } } return $info; break; case 'FORMAT': return $this->format; break; case 'LANGUAGE': // get language for calendar component as defined in [RFC 1766] return $this->language; break; case 'NL': case 'NEWLINECHAR': return $this->nl; break; case 'PROPINFO': $output = array(); if (!in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight'))) { if (empty($this->uid['value'])) $this->_makeuid(); $output['UID'] = 1; } if (!empty($this->dtstamp)) $output['DTSTAMP'] = 1; if (!empty($this->summary)) $output['SUMMARY'] = 1; if (!empty($this->description)) $output['DESCRIPTION'] = count($this->description); if (!empty($this->dtstart)) $output['DTSTART'] = 1; if (!empty($this->dtend)) $output['DTEND'] = 1; if (!empty($this->due)) $output['DUE'] = 1; if (!empty($this->duration)) $output['DURATION'] = 1; if (!empty($this->rrule)) $output['RRULE'] = count($this->rrule); if (!empty($this->rdate)) $output['RDATE'] = count($this->rdate); if (!empty($this->exdate)) $output['EXDATE'] = count($this->exdate); if (!empty($this->exrule)) $output['EXRULE'] = count($this->exrule); if (!empty($this->action)) $output['ACTION'] = 1; if (!empty($this->attach)) $output['ATTACH'] = count($this->attach); if (!empty($this->attendee)) $output['ATTENDEE'] = count($this->attendee); if (!empty($this->categories)) $output['CATEGORIES'] = count($this->categories); if (!empty($this->class)) $output['CLASS'] = 1; if (!empty($this->comment)) $output['COMMENT'] = count($this->comment); if (!empty($this->completed)) $output['COMPLETED'] = 1; if (!empty($this->contact)) $output['CONTACT'] = count($this->contact); if (!empty($this->created)) $output['CREATED'] = 1; if (!empty($this->freebusy)) $output['FREEBUSY'] = count($this->freebusy); if (!empty($this->geo)) $output['GEO'] = 1; if (!empty($this->lastmodified)) $output['LAST-MODIFIED'] = 1; if (!empty($this->location)) $output['LOCATION'] = 1; if (!empty($this->organizer)) $output['ORGANIZER'] = 1; if (!empty($this->percentcomplete)) $output['PERCENT-COMPLETE'] = 1; if (!empty($this->priority)) $output['PRIORITY'] = 1; if (!empty($this->recurrenceid)) $output['RECURRENCE-ID'] = 1; if (!empty($this->relatedto)) $output['RELATED-TO'] = count($this->relatedto); if (!empty($this->repeat)) $output['REPEAT'] = 1; if (!empty($this->requeststatus)) $output['REQUEST-STATUS'] = count($this->requeststatus); if (!empty($this->resources)) $output['RESOURCES'] = count($this->resources); if (!empty($this->sequence)) $output['SEQUENCE'] = 1; if (!empty($this->status)) $output['STATUS'] = 1; if (!empty($this->transp)) $output['TRANSP'] = 1; if (!empty($this->trigger)) $output['TRIGGER'] = 1; if (!empty($this->tzid)) $output['TZID'] = 1; if (!empty($this->tzname)) $output['TZNAME'] = count($this->tzname); if (!empty($this->tzoffsetfrom)) $output['TZOFFSETTFROM'] = 1; if (!empty($this->tzoffsetto)) $output['TZOFFSETTO'] = 1; if (!empty($this->tzurl)) $output['TZURL'] = 1; if (!empty($this->url)) $output['URL'] = 1; if (!empty($this->xprop)) $output['X-PROP'] = count($this->xprop); return $output; break; case 'UNIQUE_ID': if (empty($this->unique_id)) $this->unique_id = (isset($_SERVER['SERVER_NAME'])) ? gethostbyname($_SERVER['SERVER_NAME']) : 'localhost'; return $this->unique_id; break; } } /** * general component config setting * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.8 - 2008-10-24 * @param string $config * @param string $value * @return void */ function setConfig($config, $value) { $res = FALSE; switch (strtoupper($config)) { case 'ALLOWEMPTY': $this->allowEmpty = $value; $subcfg = array('ALLOWEMPTY' => $value); $res = TRUE; break; case 'FORMAT': $value = trim($value); $this->format = $value; $this->_createFormat(); $subcfg = array('FORMAT' => $value); $res = TRUE; break; case 'LANGUAGE': // set language for calendar component as defined in [RFC 1766] $value = trim($value); $this->language = $value; $subcfg = array('LANGUAGE' => $value); $res = TRUE; break; case 'NL': case 'NEWLINECHAR': $this->nl = $value; $subcfg = array('NL' => $value); $res = TRUE; break; case 'UNIQUE_ID': $value = trim($value); $this->unique_id = $value; $subcfg = array('UNIQUE_ID' => $value); $res = TRUE; break; } if (!$res) return FALSE; if (isset($subcfg) && !empty($this->components)) { foreach ($subcfg as $cfgkey => $cfgvalue) { foreach ($this->components as $cix => $component) { $res = $component->setConfig($cfgkey, $cfgvalue); if (!$res) break 2; $this->components[$cix] = $component; // PHP4 compliant } } } return $res; } /*********************************************************************************/ /** * delete component property value * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-14 * @param string $propName * @param int @propix, optional, if specific property is wanted in case of multiply occurences * @return bool, if successfull delete TRUE */ function deleteProperty($propName, $propix = FALSE) { if ($this->_notExistProp($propName)) return FALSE; $propName = strtoupper($propName); if (in_array($propName, array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE', 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP'))) { if (!$propix) $propix = (isset($this->propdelix[$propName])) ? $this->propdelix[$propName] + 2 : 1; $this->propdelix[$propName] = --$propix; } $return = FALSE; switch ($propName) { case 'ACTION': if (!empty($this->action)) { $this->action = ''; $return = TRUE; } break; case 'ATTACH': return $this->deletePropertyM($this->attach, $propix); break; case 'ATTENDEE': return $this->deletePropertyM($this->attendee, $propix); break; case 'CATEGORIES': return $this->deletePropertyM($this->categories, $propix); break; case 'CLASS': if (!empty($this->class)) { $this->class = ''; $return = TRUE; } break; case 'COMMENT': return $this->deletePropertyM($this->comment, $propix); break; case 'COMPLETED': if (!empty($this->completed)) { $this->completed = ''; $return = TRUE; } break; case 'CONTACT': return $this->deletePropertyM($this->contact, $propix); break; case 'CREATED': if (!empty($this->created)) { $this->created = ''; $return = TRUE; } break; case 'DESCRIPTION': return $this->deletePropertyM($this->description, $propix); break; case 'DTEND': if (!empty($this->dtend)) { $this->dtend = ''; $return = TRUE; } break; case 'DTSTAMP': if (in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight'))) return FALSE; if (!empty($this->dtstamp)) { $this->dtstamp = ''; $return = TRUE; } break; case 'DTSTART': if (!empty($this->dtstart)) { $this->dtstart = ''; $return = TRUE; } break; case 'DUE': if (!empty($this->due)) { $this->due = ''; $return = TRUE; } break; case 'DURATION': if (!empty($this->duration)) { $this->duration = ''; $return = TRUE; } break; case 'EXDATE': return $this->deletePropertyM($this->exdate, $propix); break; case 'EXRULE': return $this->deletePropertyM($this->exrule, $propix); break; case 'FREEBUSY': return $this->deletePropertyM($this->freebusy, $propix); break; case 'GEO': if (!empty($this->geo)) { $this->geo = ''; $return = TRUE; } break; case 'LAST-MODIFIED': if (!empty($this->lastmodified)) { $this->lastmodified = ''; $return = TRUE; } break; case 'LOCATION': if (!empty($this->location)) { $this->location = ''; $return = TRUE; } break; case 'ORGANIZER': if (!empty($this->organizer)) { $this->organizer = ''; $return = TRUE; } break; case 'PERCENT-COMPLETE': if (!empty($this->percentcomplete)) { $this->percentcomplete = ''; $return = TRUE; } break; case 'PRIORITY': if (!empty($this->priority)) { $this->priority = ''; $return = TRUE; } break; case 'RDATE': return $this->deletePropertyM($this->rdate, $propix); break; case 'RECURRENCE-ID': if (!empty($this->recurrenceid)) { $this->recurrenceid = ''; $return = TRUE; } break; case 'RELATED-TO': return $this->deletePropertyM($this->relatedto, $propix); break; case 'REPEAT': if (!empty($this->repeat)) { $this->repeat = ''; $return = TRUE; } break; case 'REQUEST-STATUS': return $this->deletePropertyM($this->requeststatus, $propix); break; case 'RESOURCES': return $this->deletePropertyM($this->resources, $propix); break; case 'RRULE': return $this->deletePropertyM($this->rrule, $propix); break; case 'SEQUENCE': if (!empty($this->sequence)) { $this->sequence = ''; $return = TRUE; } break; case 'STATUS': if (!empty($this->status)) { $this->status = ''; $return = TRUE; } break; case 'SUMMARY': if (!empty($this->summary)) { $this->summary = ''; $return = TRUE; } break; case 'TRANSP': if (!empty($this->transp)) { $this->transp = ''; $return = TRUE; } break; case 'TRIGGER': if (!empty($this->trigger)) { $this->trigger = ''; $return = TRUE; } break; case 'TZID': if (!empty($this->tzid)) { $this->tzid = ''; $return = TRUE; } break; case 'TZNAME': return $this->deletePropertyM($this->tzname, $propix); break; case 'TZOFFSETFROM': if (!empty($this->tzoffsetfrom)) { $this->tzoffsetfrom = ''; $return = TRUE; } break; case 'TZOFFSETTO': if (!empty($this->tzoffsetto)) { $this->tzoffsetto = ''; $return = TRUE; } break; case 'TZURL': if (!empty($this->tzurl)) { $this->tzurl = ''; $return = TRUE; } break; case 'UID': if (in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight'))) return FALSE; if (!empty($this->uid)) { $this->uid = ''; $return = TRUE; } break; case 'URL': if (!empty($this->url)) { $this->url = ''; $return = TRUE; } break; default: $reduced = ''; if ($propName != 'X-PROP') { if (!isset($this->xprop[$propName])) return FALSE; foreach ($this->xprop as $k => $a) { if (($k != $propName) && !empty($a)) $reduced[$k] = $a; } } else { if (count($this->xprop) <= $propix) return FALSE; $xpropno = 0; foreach ($this->xprop as $xpropkey => $xpropvalue) { if ($propix != $xpropno) $reduced[$xpropkey] = $xpropvalue; $xpropno++; } } $this->xprop = $reduced; return TRUE; } return $return; } /*********************************************************************************/ /** * delete component property value, fixing components with multiple occurencies * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.5 - 2008-11-07 * @param array $multiprop , reference to a component property * @param int @propix, default 0 * @return bool TRUE */ function deletePropertyM(& $multiprop, $propix = 0) { if (!isset($multiprop[$propix])) return FALSE; unset($multiprop[$propix]); if (empty($multiprop)) $multiprop = ''; return (isset($this->multiprop[$propix])) ? FALSE : TRUE; } /** * get component property value/params * * if property has multiply values, consequtive function calls are needed * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-02 * @param string $propName , optional * @param int @propix, optional, if specific property is wanted in case of multiply occurences * @param bool $inclParam =FALSE * @param bool $specform =FALSE * @return mixed */ function getProperty($propName = FALSE, $propix = FALSE, $inclParam = FALSE, $specform = FALSE) { if ($this->_notExistProp($propName)) return FALSE; $propName = ($propName) ? strtoupper($propName) : 'X-PROP'; if (in_array($propName, array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION', 'EXDATE', 'EXRULE', 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME', 'X-PROP'))) { if (!$propix) $propix = (isset($this->propix[$propName])) ? $this->propix[$propName] + 2 : 1; $this->propix[$propName] = --$propix; } switch ($propName) { case 'ACTION': if (!empty($this->action['value'])) return ($inclParam) ? $this->action : $this->action['value']; break; case 'ATTACH': if (!isset($this->attach[$propix])) return FALSE; return ($inclParam) ? $this->attach[$propix] : $this->attach[$propix]['value']; break; case 'ATTENDEE': if (!isset($this->attendee[$propix])) return FALSE; return ($inclParam) ? $this->attendee[$propix] : $this->attendee[$propix]['value']; break; case 'CATEGORIES': if (!isset($this->categories[$propix])) return FALSE; return ($inclParam) ? $this->categories[$propix] : $this->categories[$propix]['value']; break; case 'CLASS': if (!empty($this->class['value'])) return ($inclParam) ? $this->class : $this->class['value']; break; case 'COMMENT': if (!isset($this->comment[$propix])) return FALSE; return ($inclParam) ? $this->comment[$propix] : $this->comment[$propix]['value']; break; case 'COMPLETED': if (!empty($this->completed['value'])) return ($inclParam) ? $this->completed : $this->completed['value']; break; case 'CONTACT': if (!isset($this->contact[$propix])) return FALSE; return ($inclParam) ? $this->contact[$propix] : $this->contact[$propix]['value']; break; case 'CREATED': if (!empty($this->created['value'])) return ($inclParam) ? $this->created : $this->created['value']; break; case 'DESCRIPTION': if (!isset($this->description[$propix])) return FALSE; return ($inclParam) ? $this->description[$propix] : $this->description[$propix]['value']; break; case 'DTEND': if (!empty($this->dtend['value'])) return ($inclParam) ? $this->dtend : $this->dtend['value']; break; case 'DTSTAMP': if (in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight'))) return; if (!isset($this->dtstamp['value'])) $this->_makeDtstamp(); return ($inclParam) ? $this->dtstamp : $this->dtstamp['value']; break; case 'DTSTART': if (!empty($this->dtstart['value'])) return ($inclParam) ? $this->dtstart : $this->dtstart['value']; break; case 'DUE': if (!empty($this->due['value'])) return ($inclParam) ? $this->due : $this->due['value']; break; case 'DURATION': if (!isset($this->duration['value'])) return FALSE; $value = ($specform) ? $this->duration2date() : $this->duration['value']; return ($inclParam) ? array('value' => $value, 'params' => $this->duration['params']) : $value; break; case 'EXDATE': if (!isset($this->exdate[$propix])) return FALSE; return ($inclParam) ? $this->exdate[$propix] : $this->exdate[$propix]['value']; break; case 'EXRULE': if (!isset($this->exrule[$propix])) return FALSE; return ($inclParam) ? $this->exrule[$propix] : $this->exrule[$propix]['value']; break; case 'FREEBUSY': if (!isset($this->freebusy[$propix])) return FALSE; return ($inclParam) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value']; break; case 'GEO': if (!empty($this->geo['value'])) return ($inclParam) ? $this->geo : $this->geo['value']; break; case 'LAST-MODIFIED': if (!empty($this->lastmodified['value'])) return ($inclParam) ? $this->lastmodified : $this->lastmodified['value']; break; case 'LOCATION': if (!empty($this->location['value'])) return ($inclParam) ? $this->location : $this->location['value']; break; case 'ORGANIZER': if (!empty($this->organizer['value'])) return ($inclParam) ? $this->organizer : $this->organizer['value']; break; case 'PERCENT-COMPLETE': if (!empty($this->percentcomplete['value'])) return ($inclParam) ? $this->percentcomplete : $this->percentcomplete['value']; break; case 'PRIORITY': if (!empty($this->priority['value'])) return ($inclParam) ? $this->priority : $this->priority['value']; break; case 'RDATE': if (!isset($this->rdate[$propix])) return FALSE; return ($inclParam) ? $this->rdate[$propix] : $this->rdate[$propix]['value']; break; case 'RECURRENCE-ID': if (!empty($this->recurrenceid['value'])) return ($inclParam) ? $this->recurrenceid : $this->recurrenceid['value']; break; case 'RELATED-TO': if (!isset($this->relatedto[$propix])) return FALSE; return ($inclParam) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value']; break; case 'REPEAT': if (!empty($this->repeat['value'])) return ($inclParam) ? $this->repeat : $this->repeat['value']; break; case 'REQUEST-STATUS': if (!isset($this->requeststatus[$propix])) return FALSE; return ($inclParam) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value']; break; case 'RESOURCES': if (!isset($this->resources[$propix])) return FALSE; return ($inclParam) ? $this->resources[$propix] : $this->resources[$propix]['value']; break; case 'RRULE': if (!isset($this->rrule[$propix])) return FALSE; return ($inclParam) ? $this->rrule[$propix] : $this->rrule[$propix]['value']; break; case 'SEQUENCE': if (!empty($this->sequence['value'])) return ($inclParam) ? $this->sequence : $this->sequence['value']; break; case 'STATUS': if (!empty($this->status['value'])) return ($inclParam) ? $this->status : $this->status['value']; break; case 'SUMMARY': if (!empty($this->summary['value'])) return ($inclParam) ? $this->summary : $this->summary['value']; break; case 'TRANSP': if (!empty($this->transp['value'])) return ($inclParam) ? $this->transp : $this->transp['value']; break; case 'TRIGGER': if (!empty($this->trigger['value'])) return ($inclParam) ? $this->trigger : $this->trigger['value']; break; case 'TZID': if (!empty($this->tzid['value'])) return ($inclParam) ? $this->tzid : $this->tzid['value']; break; case 'TZNAME': if (!isset($this->tzname[$propix])) return FALSE; return ($inclParam) ? $this->tzname[$propix] : $this->tzname[$propix]['value']; break; case 'TZOFFSETFROM': if (!empty($this->tzoffsetfrom['value'])) return ($inclParam) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value']; break; case 'TZOFFSETTO': if (!empty($this->tzoffsetto['value'])) return ($inclParam) ? $this->tzoffsetto : $this->tzoffsetto['value']; break; case 'TZURL': if (!empty($this->tzurl['value'])) return ($inclParam) ? $this->tzurl : $this->tzurl['value']; break; case 'UID': if (in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight'))) return FALSE; if (empty($this->uid['value'])) $this->_makeuid(); return ($inclParam) ? $this->uid : $this->uid['value']; break; case 'URL': if (!empty($this->url['value'])) return ($inclParam) ? $this->url : $this->url['value']; break; default: if ($propName != 'X-PROP') { if (!isset($this->xprop[$propName])) return FALSE; return ($inclParam) ? array($propName, $this->xprop[$propName]) : array($propName, $this->xprop[$propName]['value']); } else { if (empty($this->xprop)) return FALSE; $xpropno = 0; foreach ($this->xprop as $xpropkey => $xpropvalue) { if ($propix == $xpropno) return ($inclParam) ? array($xpropkey, $this->xprop[$xpropkey]) : array($xpropkey, $this->xprop[$xpropkey]['value']); else $xpropno++; } return FALSE; // not found ?? } } return FALSE; } /** * general component property setting * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-05 * @param mixed $args variable number of function arguments, * first argument is ALWAYS component name, * second ALWAYS component value! * @return void */ function setProperty() { $numargs = func_num_args(); if (1 > $numargs) return FALSE; $arglist = func_get_args(); if ($this->_notExistProp($arglist[0])) return FALSE; if (!$this->getConfig('allowEmpty') && (!isset($arglist[1]) || empty($arglist[1]))) return FALSE; $arglist[0] = strtoupper($arglist[0]); for ($argix = $numargs; $argix < 12; $argix++) { if (!isset($arglist[$argix])) $arglist[$argix] = null; } switch ($arglist[0]) { case 'ACTION': return $this->setAction($arglist[1], $arglist[2]); case 'ATTACH': return $this->setAttach($arglist[1], $arglist[2], $arglist[3]); case 'ATTENDEE': return $this->setAttendee($arglist[1], $arglist[2], $arglist[3]); case 'CATEGORIES': return $this->setCategories($arglist[1], $arglist[2], $arglist[3]); case 'CLASS': return $this->setClass($arglist[1], $arglist[2]); case 'COMMENT': return $this->setComment($arglist[1], $arglist[2], $arglist[3]); case 'COMPLETED': return $this->setCompleted($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7]); case 'CONTACT': return $this->setContact($arglist[1], $arglist[2], $arglist[3]); case 'CREATED': return $this->setCreated($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7]); case 'DESCRIPTION': return $this->setDescription($arglist[1], $arglist[2], $arglist[3]); case 'DTEND': return $this->setDtend($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8]); case 'DTSTAMP': return $this->setDtstamp($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7]); case 'DTSTART': return $this->setDtstart($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8]); case 'DUE': return $this->setDue($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8]); case 'DURATION': return $this->setDuration($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6]); case 'EXDATE': return $this->setExdate($arglist[1], $arglist[2], $arglist[3]); case 'EXRULE': return $this->setExrule($arglist[1], $arglist[2], $arglist[3]); case 'FREEBUSY': return $this->setFreebusy($arglist[1], $arglist[2], $arglist[3], $arglist[4]); case 'GEO': return $this->setGeo($arglist[1], $arglist[2], $arglist[3]); case 'LAST-MODIFIED': return $this->setLastModified($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7]); case 'LOCATION': return $this->setLocation($arglist[1], $arglist[2]); case 'ORGANIZER': return $this->setOrganizer($arglist[1], $arglist[2]); case 'PERCENT-COMPLETE': return $this->setPercentComplete($arglist[1], $arglist[2]); case 'PRIORITY': return $this->setPriority($arglist[1], $arglist[2]); case 'RDATE': return $this->setRdate($arglist[1], $arglist[2], $arglist[3]); case 'RECURRENCE-ID': return $this->setRecurrenceid($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8]); case 'RELATED-TO': return $this->setRelatedTo($arglist[1], $arglist[2], $arglist[3]); case 'REPEAT': return $this->setRepeat($arglist[1], $arglist[2]); case 'REQUEST-STATUS': return $this->setRequestStatus($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5]); case 'RESOURCES': return $this->setResources($arglist[1], $arglist[2], $arglist[3]); case 'RRULE': return $this->setRrule($arglist[1], $arglist[2], $arglist[3]); case 'SEQUENCE': return $this->setSequence($arglist[1], $arglist[2]); case 'STATUS': return $this->setStatus($arglist[1], $arglist[2]); case 'SUMMARY': return $this->setSummary($arglist[1], $arglist[2]); case 'TRANSP': return $this->setTransp($arglist[1], $arglist[2]); case 'TRIGGER': return $this->setTrigger($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8], $arglist[9], $arglist[10], $arglist[11]); case 'TZID': return $this->setTzid($arglist[1], $arglist[2]); case 'TZNAME': return $this->setTzname($arglist[1], $arglist[2], $arglist[3]); case 'TZOFFSETFROM': return $this->setTzoffsetfrom($arglist[1], $arglist[2]); case 'TZOFFSETTO': return $this->setTzoffsetto($arglist[1], $arglist[2]); case 'TZURL': return $this->setTzurl($arglist[1], $arglist[2]); case 'UID': return $this->setUid($arglist[1], $arglist[2]); case 'URL': return $this->setUrl($arglist[1], $arglist[2]); default: return $this->setXprop($arglist[0], $arglist[1], $arglist[2]); } return FALSE; } /*********************************************************************************/ /** * parse component unparsed data into properties * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.2 - 2008-10-23 * @param mixed $unparsedtext , optional, strict rfc2445 formatted, single property string or array of property strings * @return bool FALSE if error occurs during parsing * */ function parse($unparsedtext = null) { if ($unparsedtext) { $this->unparsed = array(); if (is_array($unparsedtext)) { $comp = &$this; foreach ($unparsedtext as $line) { if ('END:VALARM' == strtoupper(substr($line, 0, 10))) { $this->setComponent($comp); $comp = &$this; continue; } elseif ('BEGIN:VALARM' == strtoupper(substr($line, 0, 12))) { $comp = new valarm(); continue; } else $comp->unparsed[] = $line; } } else $this->unparsed = array(trim($unparsedtext)); } elseif (!isset($this->unparsed)) $this->unparsed = array(); /* concatenate property values spread over several lines */ $lastix = -1; $propnames = array('action', 'attach', 'attendee', 'categories', 'comment', 'completed' , 'contact', 'class', 'created', 'description', 'dtend', 'dtstart' , 'dtstamp', 'due', 'duration', 'exdate', 'exrule', 'freebusy', 'geo' , 'last-modified', 'location', 'organizer', 'percent-complete' , 'priority', 'rdate', 'recurrence-id', 'related-to', 'repeat' , 'request-status', 'resources', 'rrule', 'sequence', 'status' , 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom' , 'tzoffsetto', 'tzurl', 'uid', 'url', 'x-'); $proprows = array(); foreach ($this->unparsed as $line) { $newProp = FALSE; foreach ($propnames as $propname) { if ($propname == strtolower(substr($line, 0, strlen($propname)))) { $newProp = TRUE; break; } } if ($newProp) { $newProp = FALSE; $lastix++; $proprows[$lastix] = $line; } else { /* remove line breaks */ if (('\n' == substr($proprows[$lastix], -2)) && (' ' == substr($line, 0, 1)) ) { $proprows[$lastix] = substr($proprows[$lastix], 0, strlen($proprows[$lastix]) - 2); $line = substr($line, 1); } $proprows[$lastix] .= $line; } } /* parse each property 'line' */ foreach ($proprows as $line) { $line = str_replace("\n ", '', $line); if ('\n' == substr($line, -2)) $line = substr($line, 0, strlen($line) - 2); /* get propname, (problem with x-properties, otherwise in previous loop) */ $cix = $propname = null; for ($cix = 0; $cix < strlen($line); $cix++) { if (in_array($line{$cix}, array(':', ';'))) break; else { $propname .= $line{$cix}; } } if (('x-' == substr($propname, 0, 2)) || ('X-' == substr($propname, 0, 2))) { $propname2 = $propname; $propname = 'X-'; } /* rest of the line is opt.params and value */ $line = substr($line, $cix); /* separate attributes from value */ $attr = array(); $attrix = -1; $strlen = strlen($line); for ($cix = 0; $cix < $strlen; $cix++) { if ((':' == $line{$cix}) && ('://' != substr($line, $cix, 3)) && ('mailto:' != strtolower(substr($line, $cix - 6, 7))) ) { $attrEnd = TRUE; if (($cix < ($strlen - 4)) && ctype_digit(substr($line, $cix + 1, 4)) ) { // an URI with a (4pos) portnr?? for ($c2ix = $cix; 3 < $c2ix; $c2ix--) { if ('://' == substr($line, $c2ix - 2, 3)) { $attrEnd = FALSE; break; // an URI with a portnr!! } } } if ($attrEnd) { $line = substr($line, $cix + 1); break; } } if (';' == $line{$cix}) $attr[++$attrix] = null; else $attr[$attrix] .= $line{$cix}; } /* make attributes in array format */ $propattr = array(); foreach ($attr as $attribute) { $attrsplit = explode('=', $attribute, 2); if (1 < count($attrsplit)) $propattr[$attrsplit[0]] = $attrsplit[1]; else $propattr[] = $attribute; } /* call setProperty( $propname.. . */ switch ($propname) { case 'ATTENDEE': foreach ($propattr as $pix => $attr) { $attr2 = explode(',', $attr); if (1 < count($attr2)) $propattr[$pix] = $attr2; } $this->setProperty($propname, $line, $propattr); break; case 'CATEGORIES': case 'RESOURCES': if (FALSE !== strpos($line, ',')) { $content = explode(',', $line); $clen = count($content); for ($cix = 0; $cix < $clen; $cix++) { if ("\\" == substr($content[$cix], -1)) { $content[$cix] .= ',' . $content[$cix + 1]; unset($content[$cix + 1]); $cix++; } } if (1 < count($content)) { $content = array_values($content); foreach ($content as $cix => $contentPart) $content[$cix] = $this->_strunrep($contentPart); $this->setProperty($propname, $content, $propattr); break; } else $line = reset($content); } case 'X-': $propname = (isset($propname2)) ? $propname2 : $propname; case 'COMMENT': case 'CONTACT': case 'DESCRIPTION': case 'LOCATION': case 'SUMMARY': if (empty($line)) $propattr = null; $this->setProperty($propname, $this->_strunrep($line), $propattr); unset($propname2); break; case 'REQUEST-STATUS': $values = explode(';', $line, 3); $values[1] = (!isset($values[1])) ? null : $this->_strunrep($values[1]); $values[2] = (!isset($values[2])) ? null : $this->_strunrep($values[2]); $this->setProperty($propname , $values[0] // statcode , $values[1] // statdesc , $values[2] // extdata , $propattr); break; case 'FREEBUSY': $fbtype = (isset($propattr['FBTYPE'])) ? $propattr['FBTYPE'] : ''; // force setting default, if missing unset($propattr['FBTYPE']); $values = explode(',', $line); foreach ($values as $vix => $value) { $value2 = explode('/', $value); if (1 < count($value2)) $values[$vix] = $value2; } $this->setProperty($propname, $fbtype, $values, $propattr); break; case 'GEO': $value = explode(';', $line, 2); if (2 > count($value)) $value[1] = null; $this->setProperty($propname, $value[0], $value[1], $propattr); break; case 'EXDATE': $values = (!empty($line)) ? explode(',', $line) : null; $this->setProperty($propname, $values, $propattr); break; case 'RDATE': if (empty($line)) { $this->setProperty($propname, $line, $propattr); break; } $values = explode(',', $line); foreach ($values as $vix => $value) { $value2 = explode('/', $value); if (1 < count($value2)) $values[$vix] = $value2; } $this->setProperty($propname, $values, $propattr); break; case 'EXRULE': case 'RRULE': $values = explode(';', $line); $recur = array(); foreach ($values as $value2) { if (empty($value2)) continue; // ;-char in ending position ??? $value3 = explode('=', $value2, 2); $rulelabel = strtoupper($value3[0]); switch ($rulelabel) { case 'BYDAY': { $value4 = explode(',', $value3[1]); if (1 < count($value4)) { foreach ($value4 as $v5ix => $value5) { $value6 = array(); $dayno = $dayname = null; $value5 = trim((string)$value5); if ((ctype_alpha(substr($value5, -1))) && (ctype_alpha(substr($value5, -2, 1))) ) { $dayname = substr($value5, -2, 2); if (2 < strlen($value5)) $dayno = substr($value5, 0, (strlen($value5) - 2)); } if ($dayno) $value6[] = $dayno; if ($dayname) $value6['DAY'] = $dayname; $value4[$v5ix] = $value6; } } else { $value4 = array(); $dayno = $dayname = null; $value5 = trim((string)$value3[1]); if ((ctype_alpha(substr($value5, -1))) && (ctype_alpha(substr($value5, -2, 1))) ) { $dayname = substr($value5, -2, 2); if (2 < strlen($value5)) $dayno = substr($value5, 0, (strlen($value5) - 2)); } if ($dayno) $value4[] = $dayno; if ($dayname) $value4['DAY'] = $dayname; } $recur[$rulelabel] = $value4; break; } default: { $value4 = explode(',', $value3[1]); if (1 < count($value4)) $value3[1] = $value4; $recur[$rulelabel] = $value3[1]; break; } } // end - switch $rulelabel } // end - foreach( $values.. . $this->setProperty($propname, $recur, $propattr); break; default: $this->setProperty($propname, $line, $propattr); break; } // end switch( $propname.. . } // end - foreach( $proprows.. . unset($this->unparsed, $proprows); if (isset($this->components) && is_array($this->components) && (0 < count($this->components))) { for ($six = 0; $six < count($this->components); $six++) { if (!empty($this->components[$six]->unparsed)) $this->components[$six]->parse(); } } } /*********************************************************************************/ /*********************************************************************************/ /** * return a copy of this component * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.16 - 2007-11-07 * @return object */ function copy() { $serialized_contents = serialize($this); $copy = unserialize($serialized_contents); unset($copy->propix); return $copy; } /*********************************************************************************/ /*********************************************************************************/ /** * delete calendar subcomponent from component container * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-15 * @param mixed $arg1 ordno / component type / component uid * @param mixed $arg2 optional, ordno if arg1 = component type * @return void */ function deleteComponent($arg1, $arg2 = FALSE) { if (!isset($this->components)) return FALSE; $argType = $index = null; if (ctype_digit((string)$arg1)) { $argType = 'INDEX'; $index = (int)$arg1 - 1; } elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@'))) { $argType = strtolower($arg1); $index = (!empty($arg2) && ctype_digit((string)$arg2)) ? (( int )$arg2 - 1) : 0; } $cix2dC = 0; foreach ($this->components as $cix => $component) { if (empty($component)) continue; unset($component->propix); if (('INDEX' == $argType) && ($index == $cix)) { unset($this->components[$cix]); return TRUE; } elseif ($argType == $component->objName) { if ($index == $cix2dC) { unset($this->components[$cix]); return TRUE; } $cix2dC++; } elseif (!$argType && ($arg1 == $component->getProperty('uid'))) { unset($this->components[$cix]); return TRUE; } } return FALSE; } /** * get calendar component subcomponent from component container * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-15 * @param mixed $arg1 optional, ordno/component type/ component uid * @param mixed $arg2 optional, ordno if arg1 = component type * @return object */ function getComponent($arg1 = FALSE, $arg2 = FALSE) { if (!isset($this->components)) return FALSE; $index = $argType = null; if (!$arg1) { $argType = 'INDEX'; $index = $this->compix['INDEX'] = (isset($this->compix['INDEX'])) ? $this->compix['INDEX'] + 1 : 1; } elseif (ctype_digit((string)$arg1)) { $argType = 'INDEX'; $index = (int)$arg1; unset($this->compix); } elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@'))) { unset($this->compix['INDEX']); $argType = strtolower($arg1); if (!$arg2) $index = $this->compix[$argType] = (isset($this->compix[$argType])) ? $this->compix[$argType] + 1 : 1; else $index = (int)$arg2; } $index -= 1; $ckeys = array_keys($this->components); if (!empty($index) && ($index > end($ckeys))) return FALSE; $cix2gC = 0; foreach ($this->components as $cix => $component) { if (empty($component)) continue; unset($component->propix); if (('INDEX' == $argType) && ($index == $cix)) return $component->copy(); elseif ($argType == $component->objName) { if ($index == $cix2gC) return $component->copy(); $cix2gC++; } elseif (!$argType && ($arg1 == $component->getProperty('uid'))) { unset($component->propix); return $component->copy(); } } /* not found.. . */ unset($this->compix); return false; } /** * add calendar component as subcomponent to container for subcomponents * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 1.x.x - 2007-04-24 * @param object $component calendar component * @return void */ function addSubComponent($component) { $this->setComponent($component); } /** * add calendar component as subcomponent to container for subcomponents * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.13 - 2008-09-24 * @param object $component calendar component * @param mixed $arg1 optional, ordno/component type/ component uid * @param mixed $arg2 optional, ordno if arg1 = component type * @return bool */ function setComponent($component, $arg1 = FALSE, $arg2 = FALSE) { if (!isset($this->components)) return FALSE; if ('' >= $component->getConfig('language')) $component->setConfig('language', $this->getConfig('language')); $component->setConfig('allowEmpty', $this->getConfig('allowEmpty')); $component->setConfig('nl', $this->getConfig('nl')); $component->setConfig('unique_id', $this->getConfig('unique_id')); $component->setConfig('format', $this->getConfig('format')); if (!in_array($component->objName, array('valarm', 'vtimezone', 'standard', 'daylight'))) { unset($component->propix); /* make sure dtstamp and uid is set */ $dummy = $component->getProperty('dtstamp'); $dummy = $component->getProperty('uid'); } if (!$arg1) { $this->components[] = $component->copy(); return TRUE; } $argType = $index = null; if (ctype_digit((string)$arg1)) { $argType = 'INDEX'; $index = (int)$arg1 - 1; } elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@'))) { $argType = strtolower($arg1); $index = (ctype_digit((string)$arg2)) ? ((int)$arg2) - 1 : 0; } $cix2sC = 0; foreach ($this->components as $cix => $component2) { if (empty($component2)) continue; unset($component2->propix); if (('INDEX' == $argType) && ($index == $cix)) { $this->components[$cix] = $component->copy(); return TRUE; } elseif ($argType == $component2->objName) { if ($index == $cix2sC) { $this->components[$cix] = $component->copy(); return TRUE; } $cix2sC++; } elseif (!$argType && ($arg1 == $component2->getProperty('uid'))) { $this->components[$cix] = $component->copy(); return TRUE; } } /* not found.. . insert anyway.. .*/ $this->components[] = $component->copy(); return TRUE; } /** * creates formatted output for subcomponents * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.4.10 - 2008-08-06 * @return string */ function createSubComponent() { $output = null; foreach ($this->components as $component) { if (empty($component)) continue; if ('' >= $component->getConfig('language')) $component->setConfig('language', $this->getConfig('language')); $component->setConfig('allowEmpty', $this->getConfig('allowEmpty')); $component->setConfig('nl', $this->getConfig('nl')); $component->setConfig('unique_id', $this->getConfig('unique_id')); $component->setConfig('format', $this->getConfig('format')); $output .= $component->createComponent($this->xcaldecl); } return $output; } /********************************************************************************/ /** * break lines at pos 75 * * Lines of text SHOULD NOT be longer than 75 octets, excluding the line * break. Long content lines SHOULD be split into a multiple line * representations using a line "folding" technique. That is, a long * line can be split between any two characters by inserting a CRLF * immediately followed by a single linear white space character (i.e., * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence * of CRLF followed immediately by a single linear white space character * is ignored (i.e., removed) when processing the content type. * * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where * the reserved expression "\n" in the arg $string could be broken up by the * folding of lines, causing ambiguity in the return string. * Fix uses var $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be. * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.2.8 - 2006-09-03 * @param string $value * @return string */ function _size75($string) { $strlen = strlen($string); $tmp = $string; $string = null; while ($strlen > 75) { $breakAtChar = 75; if (substr($tmp, ($breakAtChar - 1), strlen('\n')) == '\n') $breakAtChar = $breakAtChar - 1; $string .= substr($tmp, 0, $breakAtChar); $string .= $this->nl; $tmp = ' ' . substr($tmp, $breakAtChar); $strlen = strlen($tmp); } // while $string .= rtrim($tmp); // the rest if ($this->nl != substr($string, (0 - strlen($this->nl)))) $string .= $this->nl; return $string; } /** * special characters management output * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.3.3 - 2007-12-20 * @param string $string * @return string */ function _strrep($string) { switch ($this->format) { case 'xcal': $string = str_replace('\n', $this->nl, $string); $string = htmlspecialchars(strip_tags(stripslashes(urldecode($string)))); break; default: $pos = 0; while ($pos <= strlen($string)) { $pos = strpos($string, "\\", $pos); if (FALSE === $pos) break; if (!in_array($string{($pos + 1)}, array('n', 'N', 'r', ',', ';'))) { $string = substr($string, 0, $pos) . "\\" . substr($string, ($pos + 1)); $pos += 1; } $pos += 1; } if (FALSE !== strpos($string, '"')) $string = str_replace('"', "'", $string); if (FALSE !== strpos($string, ',')) $string = str_replace(',', '\,', $string); if (FALSE !== strpos($string, ';')) $string = str_replace(';', '\;', $string); if (FALSE !== strpos($string, "\r\n")) $string = str_replace("\r\n", '\n', $string); elseif (FALSE !== strpos($string, "\r")) $string = str_replace("\r", '\n', $string); if (FALSE !== strpos($string, '\N')) $string = str_replace('\N', '\n', $string); // if( FALSE !== strpos( $string, $this->nl )) $string = str_replace($this->nl, '\n', $string); break; } return $string; } /** * special characters management input (from iCal file) * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.3.3 - 2007-11-23 * @param string $string * @return string */ function _strunrep($string) { $string = str_replace('\\\\', '\\', $string); $string = str_replace('\,', ',', $string); $string = str_replace('\;', ';', $string); // $string = str_replace( '\n', $this->nl, $string); // ?? return $string; } } /*********************************************************************************/ /*********************************************************************************/ /** * class for calendar component VEVENT * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-12 */ class vevent extends calendarComponent { var $attach; var $attendee; var $categories; var $comment; var $contact; var $class; var $created; var $description; var $dtend; var $dtstart; var $duration; var $exdate; var $exrule; var $geo; var $lastmodified; var $location; var $organizer; var $priority; var $rdate; var $recurrenceid; var $relatedto; var $requeststatus; var $resources; var $rrule; var $sequence; var $status; var $summary; var $transp; var $url; var $xprop; // component subcomponents container var $components; /** * constructor for calendar component VEVENT object * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-31 * @return void */ function vevent() { $this->calendarComponent(); $this->attach = ''; $this->attendee = ''; $this->categories = ''; $this->class = ''; $this->comment = ''; $this->contact = ''; $this->created = ''; $this->description = ''; $this->dtstart = ''; $this->dtend = ''; $this->duration = ''; $this->exdate = ''; $this->exrule = ''; $this->geo = ''; $this->lastmodified = ''; $this->location = ''; $this->organizer = ''; $this->priority = ''; $this->rdate = ''; $this->recurrenceid = ''; $this->relatedto = ''; $this->requeststatus = ''; $this->resources = ''; $this->rrule = ''; $this->sequence = ''; $this->status = ''; $this->summary = ''; $this->transp = ''; $this->url = ''; $this->xprop = ''; $this->components = array(); } /** * create formatted output for calendar component VEVENT object instance * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-07 * @param array $xcaldecl * @return string */ function createComponent(&$xcaldecl) { $objectname = $this->_createFormat(); $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl; $component .= $this->createUid(); $component .= $this->createDtstamp(); $component .= $this->createAttach(); $component .= $this->createAttendee(); $component .= $this->createCategories(); $component .= $this->createComment(); $component .= $this->createContact(); $component .= $this->createClass(); $component .= $this->createCreated(); $component .= $this->createDescription(); $component .= $this->createDtstart(); $component .= $this->createDtend(); $component .= $this->createDuration(); $component .= $this->createExdate(); $component .= $this->createExrule(); $component .= $this->createGeo(); $component .= $this->createLastModified(); $component .= $this->createLocation(); $component .= $this->createOrganizer(); $component .= $this->createPriority(); $component .= $this->createRdate(); $component .= $this->createRrule(); $component .= $this->createRelatedTo(); $component .= $this->createRequestStatus(); $component .= $this->createRecurrenceid(); $component .= $this->createResources(); $component .= $this->createSequence(); $component .= $this->createStatus(); $component .= $this->createSummary(); $component .= $this->createTransp(); $component .= $this->createUrl(); $component .= $this->createXprop(); $component .= $this->createSubComponent(); $component .= $this->componentEnd1 . $objectname . $this->componentEnd2; if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl))) { foreach ($this->xcaldecl as $localxcaldecl) $xcaldecl[] = $localxcaldecl; } return $component; } } /*********************************************************************************/ /*********************************************************************************/ /** * class for calendar component VTODO * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-12 */ class vtodo extends calendarComponent { var $attach; var $attendee; var $categories; var $comment; var $completed; var $contact; var $class; var $created; var $description; var $dtstart; var $due; var $duration; var $exdate; var $exrule; var $geo; var $lastmodified; var $location; var $organizer; var $percentcomplete; var $priority; var $rdate; var $recurrenceid; var $relatedto; var $requeststatus; var $resources; var $rrule; var $sequence; var $status; var $summary; var $url; var $xprop; // component subcomponents container var $components; /** * constructor for calendar component VTODO object * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-31 * @return void */ function vtodo() { $this->calendarComponent(); $this->attach = ''; $this->attendee = ''; $this->categories = ''; $this->class = ''; $this->comment = ''; $this->completed = ''; $this->contact = ''; $this->created = ''; $this->description = ''; $this->dtstart = ''; $this->due = ''; $this->duration = ''; $this->exdate = ''; $this->exrule = ''; $this->geo = ''; $this->lastmodified = ''; $this->location = ''; $this->organizer = ''; $this->percentcomplete = ''; $this->priority = ''; $this->rdate = ''; $this->recurrenceid = ''; $this->relatedto = ''; $this->requeststatus = ''; $this->resources = ''; $this->rrule = ''; $this->sequence = ''; $this->status = ''; $this->summary = ''; $this->url = ''; $this->xprop = ''; $this->components = array(); } /** * create formatted output for calendar component VTODO object instance * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-11-07 * @param array $xcaldecl * @return string */ function createComponent(&$xcaldecl) { $objectname = $this->_createFormat(); $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl; $component .= $this->createUid(); $component .= $this->createDtstamp(); $component .= $this->createAttach(); $component .= $this->createAttendee(); $component .= $this->createCategories(); $component .= $this->createClass(); $component .= $this->createComment(); $component .= $this->createCompleted(); $component .= $this->createContact(); $component .= $this->createCreated(); $component .= $this->createDescription(); $component .= $this->createDtstart(); $component .= $this->createDue(); $component .= $this->createDuration(); $component .= $this->createExdate(); $component .= $this->createExrule(); $component .= $this->createGeo(); $component .= $this->createLastModified(); $component .= $this->createLocation(); $component .= $this->createOrganizer(); $component .= $this->createPercentComplete(); $component .= $this->createPriority(); $component .= $this->createRdate(); $component .= $this->createRelatedTo(); $component .= $this->createRequestStatus(); $component .= $this->createRecurrenceid(); $component .= $this->createResources(); $component .= $this->createRrule(); $component .= $this->createSequence(); $component .= $this->createStatus(); $component .= $this->createSummary(); $component .= $this->createUrl(); $component .= $this->createXprop(); $component .= $this->createSubComponent(); $component .= $this->componentEnd1 . $objectname . $this->componentEnd2; if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl))) { foreach ($this->xcaldecl as $localxcaldecl) $xcaldecl[] = $localxcaldecl; } return $component; } } /*********************************************************************************/ /*********************************************************************************/ /** * class for calendar component VJOURNAL * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-12 */ class vjournal extends calendarComponent { var $attach; var $attendee; var $categories; var $comment; var $contact; var $class; var $created; var $description; var $dtstart; var $exdate; var $exrule; var $lastmodified; var $organizer; var $rdate; var $recurrenceid; var $relatedto; var $requeststatus; var $rrule; var $sequence; var $status; var $summary; var $url; var $xprop; /** * constructor for calendar component VJOURNAL object * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-31 * @return void */ function vjournal() { $this->calendarComponent(); $this->attach = ''; $this->attendee = ''; $this->categories = ''; $this->class = ''; $this->comment = ''; $this->contact = ''; $this->created = ''; $this->description = ''; $this->dtstart = ''; $this->exdate = ''; $this->exrule = ''; $this->lastmodified = ''; $this->organizer = ''; $this->rdate = ''; $this->recurrenceid = ''; $this->relatedto = ''; $this->requeststatus = ''; $this->rrule = ''; $this->sequence = ''; $this->status = ''; $this->summary = ''; $this->url = ''; $this->xprop = ''; } /** * create formatted output for calendar component VJOURNAL object instance * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-12 * @param array $xcaldecl * @return string */ function createComponent(&$xcaldecl) { $objectname = $this->_createFormat(); $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl; $component .= $this->createUid(); $component .= $this->createDtstamp(); $component .= $this->createAttach(); $component .= $this->createAttendee(); $component .= $this->createCategories(); $component .= $this->createClass(); $component .= $this->createComment(); $component .= $this->createContact(); $component .= $this->createCreated(); $component .= $this->createDescription(); $component .= $this->createDtstart(); $component .= $this->createExdate(); $component .= $this->createExrule(); $component .= $this->createLastModified(); $component .= $this->createOrganizer(); $component .= $this->createRdate(); $component .= $this->createRequestStatus(); $component .= $this->createRecurrenceid(); $component .= $this->createRelatedTo(); $component .= $this->createRrule(); $component .= $this->createSequence(); $component .= $this->createStatus(); $component .= $this->createSummary(); $component .= $this->createUrl(); $component .= $this->createXprop(); $component .= $this->componentEnd1 . $objectname . $this->componentEnd2; if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl))) { foreach ($this->xcaldecl as $localxcaldecl) $xcaldecl[] = $localxcaldecl; } return $component; } } /*********************************************************************************/ /*********************************************************************************/ /** * class for calendar component VFREEBUSY * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-12 */ class vfreebusy extends calendarComponent { var $attendee; var $comment; var $contact; var $dtend; var $dtstart; var $duration; var $freebusy; var $organizer; var $requeststatus; var $url; var $xprop; // component subcomponents container var $components; /** * constructor for calendar component VFREEBUSY object * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-31 * @return void */ function vfreebusy() { $this->calendarComponent(); $this->attendee = ''; $this->comment = ''; $this->contact = ''; $this->dtend = ''; $this->dtstart = ''; $this->duration = ''; $this->freebusy = ''; $this->organizer = ''; $this->requeststatus = ''; $this->url = ''; $this->xprop = ''; } /** * create formatted output for calendar component VFREEBUSY object instance * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.3.1 - 2007-11-19 * @param array $xcaldecl * @return string */ function createComponent(&$xcaldecl) { $objectname = $this->_createFormat(); $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl; $component .= $this->createUid(); $component .= $this->createDtstamp(); $component .= $this->createAttendee(); $component .= $this->createComment(); $component .= $this->createContact(); $component .= $this->createDtstart(); $component .= $this->createDtend(); $component .= $this->createDuration(); $component .= $this->createFreebusy(); $component .= $this->createOrganizer(); $component .= $this->createRequestStatus(); $component .= $this->createUrl(); $component .= $this->createXprop(); $component .= $this->componentEnd1 . $objectname . $this->componentEnd2; if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl))) { foreach ($this->xcaldecl as $localxcaldecl) $xcaldecl[] = $localxcaldecl; } return $component; } } /*********************************************************************************/ /*********************************************************************************/ /** * class for calendar component VALARM * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-12 */ class valarm extends calendarComponent { var $action; var $attach; var $attendee; var $description; var $duration; var $repeat; var $summary; var $trigger; var $xprop; /** * constructor for calendar component VALARM object * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-31 * @return void */ function valarm() { $this->calendarComponent(); $this->action = ''; $this->attach = ''; $this->attendee = ''; $this->description = ''; $this->duration = ''; $this->repeat = ''; $this->summary = ''; $this->trigger = ''; $this->xprop = ''; } /** * create formatted output for calendar component VALARM object instance * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-22 * @param array $xcaldecl * @return string */ function createComponent(&$xcaldecl) { $objectname = $this->_createFormat(); $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl; $component .= $this->createAction(); $component .= $this->createAttach(); $component .= $this->createAttendee(); $component .= $this->createDescription(); $component .= $this->createDuration(); $component .= $this->createRepeat(); $component .= $this->createSummary(); $component .= $this->createTrigger(); $component .= $this->createXprop(); $component .= $this->componentEnd1 . $objectname . $this->componentEnd2; return $component; } } /********************************************************************************** * /*********************************************************************************/ /** * class for calendar component VTIMEZONE * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-12 */ class vtimezone extends calendarComponent { var $timezonetype; var $comment; var $dtstart; var $lastmodified; var $rdate; var $rrule; var $tzid; var $tzname; var $tzoffsetfrom; var $tzoffsetto; var $tzurl; var $xprop; // component subcomponents container var $components; /** * constructor for calendar component VTIMEZONE object * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-31 * @param string $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT ) * @return void */ function vtimezone($timezonetype = FALSE) { if (!$timezonetype) $this->timezonetype = 'VTIMEZONE'; else $this->timezonetype = strtoupper($timezonetype); $this->calendarComponent(); $this->comment = ''; $this->dtstart = ''; $this->lastmodified = ''; $this->rdate = ''; $this->rrule = ''; $this->tzid = ''; $this->tzname = ''; $this->tzoffsetfrom = ''; $this->tzoffsetto = ''; $this->tzurl = ''; $this->xprop = ''; $this->components = array(); } /** * create formatted output for calendar component VTIMEZONE object instance * * @author Kjell-Inge Gustafsson <ical@kigkonsult.se> * @since 2.5.1 - 2008-10-25 * @param array $xcaldecl * @return string */ function createComponent(&$xcaldecl) { $objectname = $this->_createFormat(); $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl; $component .= $this->createTzid(); $component .= $this->createLastModified(); $component .= $this->createTzurl(); $component .= $this->createDtstart(); $component .= $this->createTzoffsetfrom(); $component .= $this->createTzoffsetto(); $component .= $this->createComment(); $component .= $this->createRdate(); $component .= $this->createRrule(); $component .= $this->createTzname(); $component .= $this->createXprop(); $component .= $this->createSubComponent(); $component .= $this->componentEnd1 . $objectname . $this->componentEnd2; if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl))) { foreach ($this->xcaldecl as $localxcaldecl) $xcaldecl[] = $localxcaldecl; } return $component; } } ?>