PageRenderTime 301ms CodeModel.GetById 24ms RepoModel.GetById 3ms app.codeStats 2ms

/common/libraries/plugin/icalcreator/iCalcreator.class.php

https://bitbucket.org/cbenelug/chamilo
PHP | 8102 lines | 6268 code | 160 blank | 1674 comment | 1469 complexity | 495f10ed443ca84acbe7803a69faeb22 MD5 | raw file
Possible License(s): GPL-3.0, MIT, GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /*********************************************************************************/
  3. /**
  4. * iCalcreator class v2.10.5
  5. * copyright (c) 2007-2011 Kjell-Inge Gustafsson kigkonsult
  6. * www.kigkonsult.se/iCalcreator/index.php
  7. * ical@kigkonsult.se
  8. *
  9. * Description:
  10. * This file is a PHP implementation of RFC 2445.
  11. *
  12. * This library is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU Lesser General Public
  14. * License as published by the Free Software Foundation; either
  15. * version 2.1 of the License, or (at your option) any later version.
  16. *
  17. * This library is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * Lesser General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU Lesser General Public
  23. * License along with this library; if not, write to the Free Software
  24. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25. */
  26. /*********************************************************************************/
  27. /*********************************************************************************/
  28. /* A little setup */
  29. /*********************************************************************************/
  30. /* your local language code */
  31. // define( 'ICAL_LANG', 'sv' );
  32. // alt. autosetting
  33. /*
  34. $langstr = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
  35. $pos = strpos( $langstr, ';' );
  36. if ($pos !== false) {
  37. $langstr = substr( $langstr, 0, $pos );
  38. $pos = strpos( $langstr, ',' );
  39. if ($pos !== false) {
  40. $pos = strpos( $langstr, ',' );
  41. $langstr = substr( $langstr, 0, $pos );
  42. }
  43. define( 'ICAL_LANG', $langstr );
  44. }
  45. */
  46. /*********************************************************************************/
  47. /* only for phpversion 5.1 and later, */
  48. /* date management, default timezone setting */
  49. /* since 2.6.36 - 2010-12-31 */
  50. if (substr(phpversion(), 0, 3) >= '5.1')
  51. // && ( 'UTC' == date_default_timezone_get()))
  52. date_default_timezone_set('Europe/Stockholm');
  53. /*********************************************************************************/
  54. /* since 2.6.22 - 2010-09-25, do NOT remove!! */
  55. require_once 'iCalUtilityFunctions.class.php';
  56. /*********************************************************************************/
  57. /* version, do NOT remove!! */
  58. define('ICALCREATOR_VERSION', 'iCalcreator 2.10.5');
  59. /*********************************************************************************/
  60. /*********************************************************************************/
  61. /**
  62. * vcalendar class
  63. *
  64. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  65. * @since 2.9.6 - 2011-05-14
  66. */
  67. class vcalendar
  68. {
  69. // calendar property variables
  70. var $calscale;
  71. var $method;
  72. var $prodid;
  73. var $version;
  74. var $xprop;
  75. // container for calendar components
  76. var $components;
  77. // component config variables
  78. var $allowEmpty;
  79. var $unique_id;
  80. var $language;
  81. var $directory;
  82. var $filename;
  83. var $url;
  84. var $delimiter;
  85. var $nl;
  86. var $format;
  87. var $dtzid;
  88. // component internal variables
  89. var $attributeDelimiter;
  90. var $valueInit;
  91. // component xCal declaration container
  92. var $xcaldecl;
  93. /**
  94. * constructor for calendar object
  95. *
  96. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  97. * @since 2.9.6 - 2011-05-14
  98. * @param array $config
  99. * @return void
  100. */
  101. function vcalendar($config = array())
  102. {
  103. $this->_makeVersion();
  104. $this->calscale = null;
  105. $this->method = null;
  106. $this->_makeUnique_id();
  107. $this->prodid = null;
  108. $this->xprop = array();
  109. $this->language = null;
  110. $this->directory = null;
  111. $this->filename = null;
  112. $this->url = null;
  113. $this->dtzid = null;
  114. /**
  115. * language = <Text identifying a language, as defined in [RFC 1766]>
  116. */
  117. if (defined('ICAL_LANG') && ! isset($config['language']))
  118. $config['language'] = ICAL_LANG;
  119. if (! isset($config['allowEmpty']))
  120. $config['allowEmpty'] = TRUE;
  121. if (! isset($config['nl']))
  122. $config['nl'] = "\r\n";
  123. if (! isset($config['format']))
  124. $config['format'] = 'iCal';
  125. if (! isset($config['delimiter']))
  126. $config['delimiter'] = DIRECTORY_SEPARATOR;
  127. $this->setConfig($config);
  128. $this->xcaldecl = array();
  129. $this->components = array();
  130. }
  131. /*********************************************************************************/
  132. /**
  133. * Property Name: CALSCALE
  134. */
  135. /**
  136. * creates formatted output for calendar property calscale
  137. *
  138. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  139. * @since 2.4.8 - 2008-10-21
  140. * @return string
  141. */
  142. function createCalscale()
  143. {
  144. if (empty($this->calscale))
  145. return FALSE;
  146. switch ($this->format)
  147. {
  148. case 'xcal' :
  149. return ' calscale="' . $this->calscale . '"' . $this->nl;
  150. break;
  151. default :
  152. return 'CALSCALE:' . $this->calscale . $this->nl;
  153. break;
  154. }
  155. }
  156. /**
  157. * set calendar property calscale
  158. *
  159. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  160. * @since 2.4.8 - 2008-10-21
  161. * @param string $value
  162. * @return void
  163. */
  164. function setCalscale($value)
  165. {
  166. if (empty($value))
  167. return FALSE;
  168. $this->calscale = $value;
  169. }
  170. /*********************************************************************************/
  171. /**
  172. * Property Name: METHOD
  173. */
  174. /**
  175. * creates formatted output for calendar property method
  176. *
  177. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  178. * @since 0.9.7 - 2006-11-20
  179. * @return string
  180. */
  181. function createMethod()
  182. {
  183. if (empty($this->method))
  184. return FALSE;
  185. switch ($this->format)
  186. {
  187. case 'xcal' :
  188. return ' method="' . $this->method . '"' . $this->nl;
  189. break;
  190. default :
  191. return 'METHOD:' . $this->method . $this->nl;
  192. break;
  193. }
  194. }
  195. /**
  196. * set calendar property method
  197. *
  198. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  199. * @since 2.4.8 - 2008-20-23
  200. * @param string $value
  201. * @return bool
  202. */
  203. function setMethod($value)
  204. {
  205. if (empty($value))
  206. return FALSE;
  207. $this->method = $value;
  208. return TRUE;
  209. }
  210. /*********************************************************************************/
  211. /**
  212. * Property Name: PRODID
  213. *
  214. * The identifier is RECOMMENDED to be the identical syntax to the
  215. * [RFC 822] addr-spec. A good method to assure uniqueness is to put the
  216. * domain name or a domain literal IP address of the host on which.. .
  217. */
  218. /**
  219. * creates formatted output for calendar property prodid
  220. *
  221. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  222. * @since 0.9.7 - 2006-11-20
  223. * @return string
  224. */
  225. function createProdid()
  226. {
  227. if (! isset($this->prodid))
  228. $this->_makeProdid();
  229. switch ($this->format)
  230. {
  231. case 'xcal' :
  232. return ' prodid="' . $this->prodid . '"' . $this->nl;
  233. break;
  234. default :
  235. return 'PRODID:' . $this->prodid . $this->nl;
  236. break;
  237. }
  238. }
  239. /**
  240. * make default value for calendar prodid
  241. *
  242. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  243. * @since 2.6.8 - 2009-12-30
  244. * @return void
  245. */
  246. function _makeProdid()
  247. {
  248. $this->prodid = '-//' . $this->unique_id . '//NONSGML kigkonsult.se ' . ICALCREATOR_VERSION . '//' . strtoupper($this->language);
  249. }
  250. /**
  251. * Conformance: The property MUST be specified once in an iCalendar object.
  252. * Description: The vendor of the implementation SHOULD assure that this
  253. * is a globally unique identifier; using some technique such as an FPI
  254. * value, as defined in [ISO 9070].
  255. */
  256. /**
  257. * make default unique_id for calendar prodid
  258. *
  259. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  260. * @since 0.3.0 - 2006-08-10
  261. * @return void
  262. */
  263. function _makeUnique_id()
  264. {
  265. $this->unique_id = (isset($_SERVER['SERVER_NAME'])) ? gethostbyname($_SERVER['SERVER_NAME']) : 'localhost';
  266. }
  267. /*********************************************************************************/
  268. /**
  269. * Property Name: VERSION
  270. *
  271. * Description: A value of "2.0" corresponds to this memo.
  272. */
  273. /**
  274. * creates formatted output for calendar property version
  275. *
  276. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  277. * @since 0.9.7 - 2006-11-20
  278. * @return string
  279. */
  280. function createVersion()
  281. {
  282. if (empty($this->version))
  283. $this->_makeVersion();
  284. switch ($this->format)
  285. {
  286. case 'xcal' :
  287. return ' version="' . $this->version . '"' . $this->nl;
  288. break;
  289. default :
  290. return 'VERSION:' . $this->version . $this->nl;
  291. break;
  292. }
  293. }
  294. /**
  295. * set default calendar version
  296. *
  297. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  298. * @since 0.3.0 - 2006-08-10
  299. * @return void
  300. */
  301. function _makeVersion()
  302. {
  303. $this->version = '2.0';
  304. }
  305. /**
  306. * set calendar version
  307. *
  308. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  309. * @since 2.4.8 - 2008-10-23
  310. * @param string $value
  311. * @return void
  312. */
  313. function setVersion($value)
  314. {
  315. if (empty($value))
  316. return FALSE;
  317. $this->version = $value;
  318. return TRUE;
  319. }
  320. /*********************************************************************************/
  321. /**
  322. * Property Name: x-prop
  323. */
  324. /**
  325. * creates formatted output for calendar property x-prop, iCal format only
  326. *
  327. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  328. * @since 2.9.3 - 2011-05-14
  329. * @return string
  330. */
  331. function createXprop()
  332. {
  333. if ('xcal' == $this->format)
  334. return false;
  335. if (empty($this->xprop) || ! is_array($this->xprop))
  336. return FALSE;
  337. $output = null;
  338. $toolbox = new calendarComponent();
  339. $toolbox->setConfig($this->getConfig());
  340. foreach ($this->xprop as $label => $xpropPart)
  341. {
  342. if (! isset($xpropPart['value']) || (empty($xpropPart['value']) && ! is_numeric($xpropPart['value'])))
  343. {
  344. $output .= $toolbox->_createElement($label);
  345. continue;
  346. }
  347. $attributes = $toolbox->_createParams($xpropPart['params'], array('LANGUAGE'));
  348. if (is_array($xpropPart['value']))
  349. {
  350. foreach ($xpropPart['value'] as $pix => $theXpart)
  351. $xpropPart['value'][$pix] = $toolbox->_strrep($theXpart);
  352. $xpropPart['value'] = implode(',', $xpropPart['value']);
  353. }
  354. else
  355. $xpropPart['value'] = $toolbox->_strrep($xpropPart['value']);
  356. $output .= $toolbox->_createElement($label, $attributes, $xpropPart['value']);
  357. }
  358. return $output;
  359. }
  360. /**
  361. * set calendar property x-prop
  362. *
  363. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  364. * @since 2.9.3 - 2011-05-14
  365. * @param string $label
  366. * @param string $value
  367. * @param array $params optional
  368. * @return bool
  369. */
  370. function setXprop($label, $value, $params = FALSE)
  371. {
  372. if (empty($label))
  373. return FALSE;
  374. if (empty($value) && ! is_numeric($value))
  375. if ($this->getConfig('allowEmpty'))
  376. $value = null;
  377. else
  378. return FALSE;
  379. $xprop = array('value' => $value);
  380. $xprop['params'] = iCalUtilityFunctions :: _setParams($params);
  381. if (! is_array($this->xprop))
  382. $this->xprop = array();
  383. $this->xprop[strtoupper($label)] = $xprop;
  384. return TRUE;
  385. }
  386. /*********************************************************************************/
  387. /**
  388. * delete calendar property value
  389. *
  390. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  391. * @since 2.8.8 - 2011-03-15
  392. * @param mixed $propName, bool FALSE => X-property
  393. * @param int $propix, optional, if specific property is wanted in case of multiply occurences
  394. * @return bool, if successfull delete
  395. */
  396. function deleteProperty($propName = FALSE, $propix = FALSE)
  397. {
  398. $propName = ($propName) ? strtoupper($propName) : 'X-PROP';
  399. if (! $propix)
  400. $propix = (isset($this->propdelix[$propName]) && ('X-PROP' != $propName)) ? $this->propdelix[$propName] + 2 : 1;
  401. $this->propdelix[$propName] = -- $propix;
  402. $return = FALSE;
  403. switch ($propName)
  404. {
  405. case 'CALSCALE' :
  406. if (isset($this->calscale))
  407. {
  408. $this->calscale = null;
  409. $return = TRUE;
  410. }
  411. break;
  412. case 'METHOD' :
  413. if (isset($this->method))
  414. {
  415. $this->method = null;
  416. $return = TRUE;
  417. }
  418. break;
  419. default :
  420. $reduced = array();
  421. if ($propName != 'X-PROP')
  422. {
  423. if (! isset($this->xprop[$propName]))
  424. {
  425. unset($this->propdelix[$propName]);
  426. return FALSE;
  427. }
  428. foreach ($this->xprop as $k => $a)
  429. {
  430. if (($k != $propName) && ! empty($a))
  431. $reduced[$k] = $a;
  432. }
  433. }
  434. else
  435. {
  436. if (count($this->xprop) <= $propix)
  437. return FALSE;
  438. $xpropno = 0;
  439. foreach ($this->xprop as $xpropkey => $xpropvalue)
  440. {
  441. if ($propix != $xpropno)
  442. $reduced[$xpropkey] = $xpropvalue;
  443. $xpropno ++;
  444. }
  445. }
  446. $this->xprop = $reduced;
  447. if (empty($this->xprop))
  448. {
  449. unset($this->propdelix[$propName]);
  450. return FALSE;
  451. }
  452. return TRUE;
  453. }
  454. return $return;
  455. }
  456. /**
  457. * get calendar property value/params
  458. *
  459. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  460. * @since 2.8.8 - 2011-04-16
  461. * @param string $propName, optional
  462. * @param int $propix, optional, if specific property is wanted in case of multiply occurences
  463. * @param bool $inclParam=FALSE
  464. * @return mixed
  465. */
  466. function getProperty($propName = FALSE, $propix = FALSE, $inclParam = FALSE)
  467. {
  468. $propName = ($propName) ? strtoupper($propName) : 'X-PROP';
  469. if ('X-PROP' == $propName)
  470. {
  471. if (! $propix)
  472. $propix = (isset($this->propix[$propName])) ? $this->propix[$propName] + 2 : 1;
  473. $this->propix[$propName] = -- $propix;
  474. }
  475. switch ($propName)
  476. {
  477. case 'ATTENDEE' :
  478. case 'CATEGORIES' :
  479. case 'DTSTART' :
  480. case 'LOCATION' :
  481. case 'ORGANIZER' :
  482. case 'PRIORITY' :
  483. case 'RESOURCES' :
  484. case 'STATUS' :
  485. case 'SUMMARY' :
  486. case 'RECURRENCE-ID-UID' :
  487. case 'R-UID' :
  488. case 'UID' :
  489. $output = array();
  490. foreach ($this->components as $cix => $component)
  491. {
  492. if (! in_array($component->objName, array('vevent', 'vtodo', 'vjournal', 'vfreebusy')))
  493. continue;
  494. if (('ATTENDEE' == $propName) || ('CATEGORIES' == $propName) || ('RESOURCES' == $propName))
  495. {
  496. $component->_getProperties($propName, $output);
  497. continue;
  498. }
  499. elseif ((3 < strlen($propName)) && ('UID' == substr($propName, - 3)))
  500. {
  501. if (FALSE !== ($content = $component->getProperty('RECURRENCE-ID')))
  502. $content = $component->getProperty('UID');
  503. }
  504. elseif (FALSE === ($content = $component->getProperty($propName)))
  505. continue;
  506. if (FALSE === $content)
  507. continue;
  508. elseif (is_array($content))
  509. {
  510. if (isset($content['year']))
  511. {
  512. $key = sprintf('%04d%02d%02d', $content['year'], $content['month'], $content['day']);
  513. if (! isset($output[$key]))
  514. $output[$key] = 1;
  515. else
  516. $output[$key] += 1;
  517. }
  518. else
  519. {
  520. foreach ($content as $partValue => $partCount)
  521. {
  522. if (! isset($output[$partValue]))
  523. $output[$partValue] = $partCount;
  524. else
  525. $output[$partValue] += $partCount;
  526. }
  527. }
  528. } // end elseif( is_array( $content )) {
  529. elseif (! isset($output[$content]))
  530. $output[$content] = 1;
  531. else
  532. $output[$content] += 1;
  533. } // end foreach ( $this->components as $cix => $component)
  534. if (! empty($output))
  535. ksort($output);
  536. return $output;
  537. break;
  538. case 'CALSCALE' :
  539. return (! empty($this->calscale)) ? $this->calscale : FALSE;
  540. break;
  541. case 'METHOD' :
  542. return (! empty($this->method)) ? $this->method : FALSE;
  543. break;
  544. case 'PRODID' :
  545. if (empty($this->prodid))
  546. $this->_makeProdid();
  547. return $this->prodid;
  548. break;
  549. case 'VERSION' :
  550. return (! empty($this->version)) ? $this->version : FALSE;
  551. break;
  552. default :
  553. if ($propName != 'X-PROP')
  554. {
  555. if (! isset($this->xprop[$propName]))
  556. return FALSE;
  557. return ($inclParam) ? array($propName, $this->xprop[$propName]) : array($propName,
  558. $this->xprop[$propName]['value']);
  559. }
  560. else
  561. {
  562. if (empty($this->xprop))
  563. return FALSE;
  564. $xpropno = 0;
  565. foreach ($this->xprop as $xpropkey => $xpropvalue)
  566. {
  567. if ($propix == $xpropno)
  568. return ($inclParam) ? array($xpropkey, $this->xprop[$xpropkey]) : array($xpropkey,
  569. $this->xprop[$xpropkey]['value']);
  570. else
  571. $xpropno ++;
  572. }
  573. unset($this->propix[$propName]);
  574. return FALSE; // not found ??
  575. }
  576. }
  577. return FALSE;
  578. }
  579. /**
  580. * general vcalendar property setting
  581. *
  582. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  583. * @since 2.2.13 - 2007-11-04
  584. * @param mixed $args variable number of function arguments,
  585. * first argument is ALWAYS component name,
  586. * second ALWAYS component value!
  587. * @return bool
  588. */
  589. function setProperty()
  590. {
  591. $numargs = func_num_args();
  592. if (1 > $numargs)
  593. return FALSE;
  594. $arglist = func_get_args();
  595. $arglist[0] = strtoupper($arglist[0]);
  596. switch ($arglist[0])
  597. {
  598. case 'CALSCALE' :
  599. return $this->setCalscale($arglist[1]);
  600. case 'METHOD' :
  601. return $this->setMethod($arglist[1]);
  602. case 'VERSION' :
  603. return $this->setVersion($arglist[1]);
  604. default :
  605. if (! isset($arglist[1]))
  606. $arglist[1] = null;
  607. if (! isset($arglist[2]))
  608. $arglist[2] = null;
  609. return $this->setXprop($arglist[0], $arglist[1], $arglist[2]);
  610. }
  611. return FALSE;
  612. }
  613. /*********************************************************************************/
  614. /**
  615. * get vcalendar config values or * calendar components
  616. *
  617. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  618. * @since 2.9.6 - 2011-05-14
  619. * @param mixed $config
  620. * @return value
  621. */
  622. function getConfig($config = FALSE)
  623. {
  624. if (! $config)
  625. {
  626. $return = array();
  627. $return['ALLOWEMPTY'] = $this->getConfig('ALLOWEMPTY');
  628. $return['DELIMITER'] = $this->getConfig('DELIMITER');
  629. $return['DIRECTORY'] = $this->getConfig('DIRECTORY');
  630. $return['FILENAME'] = $this->getConfig('FILENAME');
  631. $return['DIRFILE'] = $this->getConfig('DIRFILE');
  632. $return['FILESIZE'] = $this->getConfig('FILESIZE');
  633. $return['FORMAT'] = $this->getConfig('FORMAT');
  634. if (FALSE !== ($lang = $this->getConfig('LANGUAGE')))
  635. $return['LANGUAGE'] = $lang;
  636. $return['NEWLINECHAR'] = $this->getConfig('NEWLINECHAR');
  637. $return['UNIQUE_ID'] = $this->getConfig('UNIQUE_ID');
  638. if (FALSE !== ($url = $this->getConfig('URL')))
  639. $return['URL'] = $url;
  640. $return['TZID'] = $this->getConfig('TZID');
  641. return $return;
  642. }
  643. switch (strtoupper($config))
  644. {
  645. case 'ALLOWEMPTY' :
  646. return $this->allowEmpty;
  647. break;
  648. case 'COMPSINFO' :
  649. unset($this->compix);
  650. $info = array();
  651. foreach ($this->components as $cix => $component)
  652. {
  653. if (empty($component))
  654. continue;
  655. $info[$cix]['ordno'] = $cix + 1;
  656. $info[$cix]['type'] = $component->objName;
  657. $info[$cix]['uid'] = $component->getProperty('uid');
  658. $info[$cix]['props'] = $component->getConfig('propinfo');
  659. $info[$cix]['sub'] = $component->getConfig('compsinfo');
  660. }
  661. return $info;
  662. break;
  663. case 'DELIMITER' :
  664. return $this->delimiter;
  665. break;
  666. case 'DIRECTORY' :
  667. if (empty($this->directory))
  668. $this->directory = '.';
  669. return $this->directory;
  670. break;
  671. case 'DIRFILE' :
  672. return $this->getConfig('directory') . $this->getConfig('delimiter') . $this->getConfig('filename');
  673. break;
  674. case 'FILEINFO' :
  675. return array($this->getConfig('directory'), $this->getConfig('filename'), $this->getConfig('filesize'));
  676. break;
  677. case 'FILENAME' :
  678. if (empty($this->filename))
  679. {
  680. if ('xcal' == $this->format)
  681. $this->filename = date('YmdHis') . '.xml'; // recommended xcs.. .
  682. else
  683. $this->filename = date('YmdHis') . '.ics';
  684. }
  685. return $this->filename;
  686. break;
  687. case 'FILESIZE' :
  688. $size = 0;
  689. if (empty($this->url))
  690. {
  691. $dirfile = $this->getConfig('dirfile');
  692. if (! is_file($dirfile) || (FALSE === ($size = filesize($dirfile))))
  693. $size = 0;
  694. clearstatcache();
  695. }
  696. return $size;
  697. break;
  698. case 'FORMAT' :
  699. return ($this->format == 'xcal') ? 'xCal' : 'iCal';
  700. break;
  701. case 'LANGUAGE':
  702. /* get language for calendar component as defined in [RFC 1766] */
  703. return $this->language;
  704. break;
  705. case 'NL' :
  706. case 'NEWLINECHAR' :
  707. return $this->nl;
  708. break;
  709. case 'TZID' :
  710. return $this->dtzid;
  711. break;
  712. case 'UNIQUE_ID' :
  713. return $this->unique_id;
  714. break;
  715. case 'URL' :
  716. if (! empty($this->url))
  717. return $this->url;
  718. else
  719. return FALSE;
  720. break;
  721. }
  722. }
  723. /**
  724. * general vcalendar config setting
  725. *
  726. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  727. * @since 2.9.6 - 2011-05-14
  728. * @param mixed $config
  729. * @param string $value
  730. * @return void
  731. */
  732. function setConfig($config, $value = FALSE)
  733. {
  734. if (is_array($config))
  735. {
  736. foreach ($config as $cKey => $cValue)
  737. {
  738. if (FALSE === $this->setConfig($cKey, $cValue))
  739. return FALSE;
  740. }
  741. return TRUE;
  742. }
  743. $res = FALSE;
  744. switch (strtoupper($config))
  745. {
  746. case 'ALLOWEMPTY' :
  747. $this->allowEmpty = $value;
  748. $subcfg = array('ALLOWEMPTY' => $value);
  749. $res = TRUE;
  750. break;
  751. case 'DELIMITER' :
  752. $this->delimiter = $value;
  753. return TRUE;
  754. break;
  755. case 'DIRECTORY' :
  756. $value = trim($value);
  757. $del = $this->getConfig('delimiter');
  758. if ($del == substr($value, (0 - strlen($del))))
  759. $value = substr($value, 0, (strlen($value) - strlen($del)));
  760. if (is_dir($value))
  761. {
  762. /* local directory */
  763. clearstatcache();
  764. $this->directory = $value;
  765. $this->url = null;
  766. return TRUE;
  767. }
  768. else
  769. return FALSE;
  770. break;
  771. case 'FILENAME' :
  772. $value = trim($value);
  773. if (! empty($this->url))
  774. {
  775. /* remote directory+file -> URL */
  776. $this->filename = $value;
  777. return TRUE;
  778. }
  779. $dirfile = $this->getConfig('directory') . $this->getConfig('delimiter') . $value;
  780. if (file_exists($dirfile))
  781. {
  782. /* local file exists */
  783. if (is_readable($dirfile) || is_writable($dirfile))
  784. {
  785. clearstatcache();
  786. $this->filename = $value;
  787. return TRUE;
  788. }
  789. else
  790. return FALSE;
  791. }
  792. elseif (is_readable($this->getConfig('directory')) || is_writable($this->getConfig('directory')))
  793. {
  794. /* read- or writable directory */
  795. $this->filename = $value;
  796. return TRUE;
  797. }
  798. else
  799. return FALSE;
  800. break;
  801. case 'FORMAT' :
  802. $value = trim(strtolower($value));
  803. if ('xcal' == $value)
  804. {
  805. $this->format = 'xcal';
  806. $this->attributeDelimiter = $this->nl;
  807. $this->valueInit = null;
  808. }
  809. else
  810. {
  811. $this->format = null;
  812. $this->attributeDelimiter = ';';
  813. $this->valueInit = ':';
  814. }
  815. $subcfg = array('FORMAT' => $value);
  816. $res = TRUE;
  817. break;
  818. case 'LANGUAGE' :
  819. // set language for calendar component as defined in [RFC 1766]
  820. $value = trim($value);
  821. $this->language = $value;
  822. $subcfg = array('LANGUAGE' => $value);
  823. $res = TRUE;
  824. break;
  825. case 'NL' :
  826. case 'NEWLINECHAR' :
  827. $this->nl = $value;
  828. $subcfg = array('NL' => $value);
  829. $res = TRUE;
  830. break;
  831. case 'TZID' :
  832. $this->dtzid = $value;
  833. $subcfg = array('TZID' => $value);
  834. $res = TRUE;
  835. break;
  836. case 'UNIQUE_ID' :
  837. $value = trim($value);
  838. $this->unique_id = $value;
  839. $subcfg = array('UNIQUE_ID' => $value);
  840. $res = TRUE;
  841. break;
  842. case 'URL':
  843. /* remote file - URL */
  844. $value = trim($value);
  845. $value = str_replace('HTTP://', 'http://', $value);
  846. $value = str_replace('WEBCAL://', 'http://', $value);
  847. $value = str_replace('webcal://', 'http://', $value);
  848. $this->url = $value;
  849. $this->directory = null;
  850. $parts = pathinfo($value);
  851. return $this->setConfig('filename', $parts['basename']);
  852. break;
  853. default : // any unvalid config key.. .
  854. return TRUE;
  855. }
  856. if (! $res)
  857. return FALSE;
  858. if (isset($subcfg) && ! empty($this->components))
  859. {
  860. foreach ($subcfg as $cfgkey => $cfgvalue)
  861. {
  862. foreach ($this->components as $cix => $component)
  863. {
  864. $res = $component->setConfig($cfgkey, $cfgvalue, TRUE);
  865. if (! $res)
  866. break 2;
  867. $this->components[$cix] = $component->copy(); // PHP4 compliant
  868. }
  869. }
  870. }
  871. return $res;
  872. }
  873. /*********************************************************************************/
  874. /**
  875. * add calendar component to container
  876. *
  877. * alias to setComponent
  878. *
  879. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  880. * @since 1.x.x - 2007-04-24
  881. * @param object $component calendar component
  882. * @return void
  883. */
  884. function addComponent($component)
  885. {
  886. $this->setComponent($component);
  887. }
  888. /**
  889. * delete calendar component from container
  890. *
  891. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  892. * @since 2.8.8 - 2011-03-15
  893. * @param mixed $arg1 ordno / component type / component uid
  894. * @param mixed $arg2 optional, ordno if arg1 = component type
  895. * @return void
  896. */
  897. function deleteComponent($arg1, $arg2 = FALSE)
  898. {
  899. $argType = $index = null;
  900. if (ctype_digit((string) $arg1))
  901. {
  902. $argType = 'INDEX';
  903. $index = (int) $arg1 - 1;
  904. }
  905. elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@')))
  906. {
  907. $argType = strtolower($arg1);
  908. $index = (! empty($arg2) && ctype_digit((string) $arg2)) ? ((int) $arg2 - 1) : 0;
  909. }
  910. $cix1dC = 0;
  911. foreach ($this->components as $cix => $component)
  912. {
  913. if (empty($component))
  914. continue;
  915. if (('INDEX' == $argType) && ($index == $cix))
  916. {
  917. unset($this->components[$cix]);
  918. return TRUE;
  919. }
  920. elseif ($argType == $component->objName)
  921. {
  922. if ($index == $cix1dC)
  923. {
  924. unset($this->components[$cix]);
  925. return TRUE;
  926. }
  927. $cix1dC ++;
  928. }
  929. elseif (! $argType && ($arg1 == $component->getProperty('uid')))
  930. {
  931. unset($this->components[$cix]);
  932. return TRUE;
  933. }
  934. }
  935. return FALSE;
  936. }
  937. /**
  938. * get calendar component from container
  939. *
  940. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  941. * @since 2.9.1 - 2011-04-16
  942. * @param mixed $arg1 optional, ordno/component type/ component uid
  943. * @param mixed $arg2 optional, ordno if arg1 = component type
  944. * @return object
  945. */
  946. function getComponent($arg1 = FALSE, $arg2 = FALSE)
  947. {
  948. $index = $argType = null;
  949. if (! $arg1)
  950. { // first or next in component chain
  951. $argType = 'INDEX';
  952. $index = $this->compix['INDEX'] = (isset($this->compix['INDEX'])) ? $this->compix['INDEX'] + 1 : 1;
  953. }
  954. elseif (ctype_digit((string) $arg1))
  955. { // specific component in chain
  956. $argType = 'INDEX';
  957. $index = (int) $arg1;
  958. unset($this->compix);
  959. }
  960. elseif (is_array($arg1))
  961. { // array( *[propertyName => propertyValue] )
  962. $arg2 = implode('-', array_keys($arg1));
  963. $index = $this->compix[$arg2] = (isset($this->compix[$arg2])) ? $this->compix[$arg2] + 1 : 1;
  964. $dateProps = array('DTSTART', 'DTEND', 'DUE', 'CREATED', 'COMPLETED', 'DTSTAMP', 'LAST-MODIFIED',
  965. 'RECURRENCE-ID');
  966. $otherProps = array('ATTENDEE', 'CATEGORIES', 'LOCATION', 'ORGANIZER', 'PRIORITY', 'RESOURCES', 'STATUS',
  967. 'SUMMARY', 'UID');
  968. }
  969. elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@')))
  970. { // object class name
  971. unset($this->compix['INDEX']);
  972. $argType = strtolower($arg1);
  973. if (! $arg2)
  974. $index = $this->compix[$argType] = (isset($this->compix[$argType])) ? $this->compix[$argType] + 1 : 1;
  975. elseif (isset($arg2) && ctype_digit((string) $arg2))
  976. $index = (int) $arg2;
  977. }
  978. elseif ((strlen($arg1) > strlen('vfreebusy')) && (FALSE !== strpos($arg1, '@')))
  979. { // UID as 1st argument
  980. if (! $arg2)
  981. $index = $this->compix[$arg1] = (isset($this->compix[$arg1])) ? $this->compix[$arg1] + 1 : 1;
  982. elseif (isset($arg2) && ctype_digit((string) $arg2))
  983. $index = (int) $arg2;
  984. }
  985. if (isset($index))
  986. $index -= 1;
  987. $ckeys = array_keys($this->components);
  988. if (! empty($index) && ($index > end($ckeys)))
  989. return FALSE;
  990. $cix1gC = 0;
  991. foreach ($this->components as $cix => $component)
  992. {
  993. if (empty($component))
  994. continue;
  995. if (('INDEX' == $argType) && ($index == $cix))
  996. return $component->copy();
  997. elseif ($argType == $component->objName)
  998. {
  999. if ($index == $cix1gC)
  1000. return $component->copy();
  1001. $cix1gC ++;
  1002. }
  1003. elseif (is_array($arg1))
  1004. { // array( *[propertyName => propertyValue] )
  1005. $hit = FALSE;
  1006. foreach ($arg1 as $pName => $pValue)
  1007. {
  1008. $pName = strtoupper($pName);
  1009. if (! in_array($pName, $dateProps) && ! in_array($pName, $otherProps))
  1010. continue;
  1011. if (('ATTENDEE' == $pName) || ('CATEGORIES' == $pName) || ('RESOURCES' == $pName))
  1012. { // multiple ocurrence may occur
  1013. $propValues = array();
  1014. $component->_getProperties($pName, $propValues);
  1015. $propValues = array_keys($propValues);
  1016. $hit = (in_array($pValue, $propValues)) ? TRUE : FALSE;
  1017. continue;
  1018. } // end if(( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName )) { // multiple ocurrence may occur
  1019. if (FALSE === ($value = $component->getProperty($pName)))
  1020. { // single ocurrency
  1021. $hit = FALSE; // missing property
  1022. continue;
  1023. }
  1024. if ('SUMMARY' == $pName)
  1025. { // exists within (any case)
  1026. $hit = (FALSE !== stripos($d, $pValue)) ? TRUE : FALSE;
  1027. continue;
  1028. }
  1029. if (in_array(strtoupper($pName), $dateProps))
  1030. {
  1031. $valuedate = sprintf('%04d%02d%02d', $value['year'], $value['month'], $value['day']);
  1032. if (8 < strlen($pValue))
  1033. {
  1034. if (isset($value['hour']))
  1035. {
  1036. if ('T' == substr($pValue, 8, 1))
  1037. $pValue = str_replace('T', '', $pValue);
  1038. $valuedate .= sprintf('%02d%02d%02d', $value['hour'], $value['min'], $value['sec']);
  1039. }
  1040. else
  1041. $pValue = substr($pValue, 0, 8);
  1042. }
  1043. $hit = ($pValue == $valuedate) ? TRUE : FALSE;
  1044. continue;
  1045. }
  1046. elseif (! is_array($value))
  1047. $value = array($value);
  1048. foreach ($value as $part)
  1049. {
  1050. $part = (FALSE !== strpos($part, ',')) ? explode(',', $part) : array($part);
  1051. foreach ($part as $subPart)
  1052. {
  1053. if ($pValue == $subPart)
  1054. {
  1055. $hit = TRUE;
  1056. continue 2;
  1057. }
  1058. }
  1059. }
  1060. $hit = FALSE; // no hit in property
  1061. } // end foreach( $arg1 as $pName => $pValue )
  1062. if ($hit)
  1063. {
  1064. if ($index == $cix1gC)
  1065. return $component->copy();
  1066. $cix1gC ++;
  1067. }
  1068. } // end elseif( is_array( $arg1 )) { // array( *[propertyName => propertyValue] )
  1069. elseif (! $argType && ($arg1 == $component->getProperty('uid')))
  1070. { // UID
  1071. if ($index == $cix1gC)
  1072. return $component->copy();
  1073. $cix1gC ++;
  1074. }
  1075. } // end foreach ( $this->components.. .
  1076. /* not found.. . */
  1077. unset($this->compix);
  1078. return FALSE;
  1079. }
  1080. /**
  1081. * create new calendar component, already included within calendar
  1082. *
  1083. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  1084. * @since 2.6.33 - 2011-01-03
  1085. * @param string $compType component type
  1086. * @return object (reference)
  1087. */
  1088. function &newComponent($compType)
  1089. {
  1090. $config = $this->getConfig();
  1091. $keys = array_keys($this->components);
  1092. $ix = end($keys) + 1;
  1093. switch (strtoupper($compType))
  1094. {
  1095. case 'EVENT' :
  1096. case 'VEVENT' :
  1097. $this->components[$ix] = new vevent($config);
  1098. break;
  1099. case 'TODO' :
  1100. case 'VTODO' :
  1101. $this->components[$ix] = new vtodo($config);
  1102. break;
  1103. case 'JOURNAL' :
  1104. case 'VJOURNAL' :
  1105. $this->components[$ix] = new vjournal($config);
  1106. break;
  1107. case 'FREEBUSY' :
  1108. case 'VFREEBUSY' :
  1109. $this->components[$ix] = new vfreebusy($config);
  1110. break;
  1111. case 'TIMEZONE' :
  1112. case 'VTIMEZONE' :
  1113. array_unshift($this->components, new vtimezone($config));
  1114. $ix = 0;
  1115. break;
  1116. default :
  1117. return FALSE;
  1118. }
  1119. return $this->components[$ix];
  1120. }
  1121. /**
  1122. * select components from calendar on date or selectOption basis
  1123. *
  1124. * Ensure DTSTART is set for every component.
  1125. * No date controls occurs.
  1126. *
  1127. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  1128. * @since 2.9.7 - 2011-06-04
  1129. * @param mixed $startY optional, start Year, default current Year ALT. array selecOptions
  1130. * @param int $startM optional, start Month, default current Month
  1131. * @param int $startD optional, start Day, default current Day
  1132. * @param int $endY optional, end Year, default $startY
  1133. * @param int $endY optional, end Month, default $startM
  1134. * @param int $endY optional, end Day, default $startD
  1135. * @param mixed $cType optional, calendar component type(-s), default FALSE=all else string/array type(-s)
  1136. * @param bool $flat optional, FALSE (default) => output : array[Year][Month][Day][]
  1137. * TRUE => output : array[] (ignores split)
  1138. * @param bool $any optional, TRUE (default) - select component that take place within period
  1139. * FALSE - only components that starts within period
  1140. * @param bool $split optional, TRUE (default) - one component copy every day it take place during the
  1141. * period (implies flat=FALSE)
  1142. * FALSE - one occurance of component only in output array
  1143. * @return array or FALSE
  1144. */
  1145. function selectComponents($startY = FALSE, $startM = FALSE, $startD = FALSE, $endY = FALSE, $endM = FALSE, $endD = FALSE, $cType = FALSE, $flat = FALSE, $any = TRUE, $split = TRUE)
  1146. {
  1147. /* check if empty calendar */
  1148. if (0 >= count($this->components))
  1149. return FALSE;
  1150. if (is_array($startY))
  1151. return $this->selectComponents2($startY);
  1152. /* check default dates */
  1153. if (! $startY)
  1154. $startY = date('Y');
  1155. if (! $startM)
  1156. $startM = date('m');
  1157. if (! $startD)
  1158. $startD = date('d');
  1159. $startDate = mktime(0, 0, 0, $startM, $startD, $startY);
  1160. if (! $endY)
  1161. $endY = $startY;
  1162. if (! $endM)
  1163. $endM = $startM;
  1164. if (! $endD)
  1165. $endD = $startD;
  1166. $endDate = mktime(23, 59, 59, $endM, $endD, $endY);
  1167. //echo 'selectComp arg='.date( 'Y-m-d H:i:s', $startDate).' -- '.date( 'Y-m-d H:i:s', $endDate)."<br />\n"; $tcnt = 0;// test ###
  1168. /* check component types */
  1169. $validTypes = array('vevent', 'vtodo', 'vjournal', 'vfreebusy');
  1170. if (is_array($cType))
  1171. {
  1172. foreach ($cType as $cix => $theType)
  1173. {
  1174. $cType[$cix] = $theType = strtolower($theType);
  1175. if (! in_array($theType, $validTypes))
  1176. $cType[$cix] = 'vevent';
  1177. }
  1178. $cType = array_unique($cType);
  1179. }
  1180. elseif (! empty($cType))
  1181. {
  1182. $cType = strtolower($cType);
  1183. if (! in_array($cType, $validTypes))
  1184. $cType = array('vevent');
  1185. else
  1186. $cType = array($cType);
  1187. }
  1188. else
  1189. $cType = $validTypes;
  1190. if (0 >= count($cType))
  1191. $cType = $validTypes;
  1192. if ((TRUE === $flat) && (TRUE === $split)) // invalid combination
  1193. $split = FALSE;
  1194. /* iterate components */
  1195. $result = array();
  1196. foreach ($this->components as $cix => $component)
  1197. {
  1198. if (empty($component))
  1199. continue;
  1200. unset($start);
  1201. /* deselect unvalid type components */
  1202. if (! in_array($component->objName, $cType))
  1203. continue;
  1204. $start = $component->getProperty('dtstart');
  1205. /* select due when dtstart is missing */
  1206. if (empty($start) && ($component->objName == 'vtodo') && (FALSE === ($start = $component->getProperty('due'))))
  1207. continue;
  1208. $dtendExist = $dueExist = $durationExist = $endAllDayEvent = FALSE;
  1209. unset($end, $startWdate, $endWdate, $rdurWsecs, $rdur, $exdatelist, $workstart, $workend, $endDateFormat); // clean up
  1210. $startWdate = iCalUtilityFunctions :: _date2timestamp($start);
  1211. $startDateFormat = (isset($start['hour'])) ? 'Y-m-d H:i:s' : 'Y-m-d';
  1212. /* get end date from dtend/due/duration properties */
  1213. $end = $component->getProperty('dtend');
  1214. if (! empty($end))
  1215. {
  1216. $dtendExist = TRUE;
  1217. $endDateFormat = (isset($end['hour'])) ? 'Y-m-d H:i:s' : 'Y-m-d';
  1218. }
  1219. if (empty($end) && ($component->objName == 'vtodo'))
  1220. {
  1221. $end = $component->getProperty('due');
  1222. if (! empty($end))
  1223. {
  1224. $dueExist = TRUE;
  1225. $endDateFormat = (isset($end['hour'])) ? 'Y-m-d H:i:s' : 'Y-m-d';
  1226. }
  1227. }
  1228. if (! empty($end) && ! isset($end['hour']))
  1229. {
  1230. /* a DTEND without time part regards an event that ends the day before,
  1231. for an all-day event DTSTART=20071201 DTEND=20071202 (taking place 20071201!!! */
  1232. $endAllDayEvent = TRUE;
  1233. $endWdate = mktime(23, 59, 59, $end['month'], ($end['day'] - 1), $end['year']);
  1234. $end['year'] = date('Y', $endWdate);
  1235. $end['month'] = date('m', $endWdate);
  1236. $end['day'] = date('d', $endWdate);
  1237. $end['hour'] = 23;
  1238. $end['min'] = $end['sec'] = 59;
  1239. }
  1240. if (empty($end))
  1241. {
  1242. $end = $component->getProperty('duration', FALSE, FALSE, TRUE); // in dtend (array) format
  1243. if (! empty($end))
  1244. $durationExist = TRUE;
  1245. $endDateFormat = (isset($start['hour'])) ? 'Y-m-d H:i:s' : 'Y-m-d';
  1246. // if( !empty($end)) echo 'selectComp 4 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  1247. }
  1248. if (empty($end))
  1249. { // assume one day duration if missing end date
  1250. $end = array('year' => $start['year'], 'month' => $start['month'],
  1251. 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59);
  1252. }
  1253. // if( isset($end)) echo 'selectComp 5 start='.implode('-',$start).' end='.implode('-',$end)."<br />\n"; // test ###
  1254. $endWdate = iCalUtilityFunctions :: _date2timestamp($end);
  1255. if ($endWdate < $startWdate)
  1256. { // MUST be after start date!!
  1257. $end = array('year' => $start['year'], 'month' => $start['month'],
  1258. 'day' => $start['day'], 'hour' => 23, 'min' => 59, 'sec' => 59);
  1259. $endWdate = iCalUtilityFunctions :: _date2timestamp($end);
  1260. }
  1261. $rdurWsecs = $endWdate - $startWdate; // compute component duration in seconds
  1262. /* make a list of optional exclude dates for component occurence from exrule and exdate */
  1263. $exdatelist = array();
  1264. $workstart = iCalUtilityFunctions :: _timestamp2date(($startDate - $rdurWsecs), 6);
  1265. $workend = iCalUtilityFunctions :: _timestamp2date(($endDate + $rdurWsecs), 6);
  1266. while (FALSE !== ($exrule = $component->getProperty('exrule'))) // check exrule
  1267. iCalUtilityFunctions :: _recur2date($exdatelist, $exrule, $start, $workstart, $workend);
  1268. while (FALSE !== ($exdate = $component->getProperty('exdate')))
  1269. { // check exdate
  1270. foreach ($exdate as $theExdate)
  1271. {
  1272. $exWdate = iCalUtilityFunctions :: _date2timestamp($theExdate);
  1273. $exWdate = mktime(0, 0, 0, date('m', $exWdate), date('d', $exWdate), date('Y', $exWdate)); // on a day-basis !!!
  1274. if ((($startDate - $rdurWsecs) <= $exWdate) && ($endDate >= $exWdate))
  1275. $exdatelist[$exWdate] = TRUE;
  1276. }
  1277. }
  1278. /* if 'any' components, check repeating components, removing all excluding dates */
  1279. if (TRUE === $any)
  1280. {
  1281. /* make a list of optional repeating dates for component occurence, rrule, rdate */
  1282. $recurlist = array();
  1283. while (FALSE !== ($rrule = $component->getProperty('rrule'))) // check rrule
  1284. iCalUtilityFunctions :: _recur2date($recurlist, $rrule, $start, $workstart, $workend);
  1285. foreach ($recurlist as $recurkey => $recurvalue) // key=match date as timestamp
  1286. $recurlist[$recurkey] = $rdurWsecs; // add duration in seconds
  1287. while (FALSE !== ($rdate = $component->getProperty('rdate')))
  1288. { // check rdate
  1289. foreach ($rdate as $theRdate)
  1290. {
  1291. if (is_array($theRdate) && (2 == count($theRdate)) && // all days within PERIOD
  1292. array_key_exists('0', $theRdate) && array_key_exists('1', $theRdate))
  1293. {
  1294. $rstart = iCalUtilityFunctions :: _date2timestamp($theRdate[0]);
  1295. if (($rstart < ($startDate - $rdurWsecs)) || ($rstart > $endDate))
  1296. continue;
  1297. if (isset($theRdate[1]['year'])) // date-date period
  1298. $rend = iCalUtilityFunctions :: _date2timestamp($theRdate[1]);
  1299. else
  1300. { // date-duration period
  1301. $rend = iCalUtilityFunctions :: _duration2date($theRdate[0], $theRdate[1]);
  1302. $rend = iCalUtilityFunctions :: _date2timestamp($rend);
  1303. }
  1304. while ($rstart < $rend)
  1305. {
  1306. $recurlist[$rstart] = $rdurWsecs; // set start date for recurrence instance + rdate duration in seconds
  1307. $rstart = mktime(date('H', $rstart), date('i', $rstart), date('s', $rstart), date('m', $rstart), date('d', $rstart) + 1, date('Y', $rstart)); // step one day
  1308. }
  1309. } // PERIOD end
  1310. else
  1311. { // single date
  1312. $theRdate = iCalUtilityFunctions :: _date2timestamp($theRdate);
  1313. if ((($startDate - $rdurWsecs) <= $theRdate) && ($endDate >= $theRdate))
  1314. $recurlist[$theRdate] = $rdurWsecs; // set start date for recurrence instance + event duration in seconds
  1315. }
  1316. }
  1317. }
  1318. if (0 < count($recurlist))
  1319. {
  1320. ksort($recurlist);
  1321. $xRecurrence = 1;
  1322. foreach ($recurlist as $recurkey => $durvalue)
  1323. {
  1324. // echo "recurKey=".date( 'Y-m-d H:i:s', $recurkey ).' dur='.iCalUtilityFunctions::offsetSec2His( $durvalue )."<br />\n"; // test ###;
  1325. if ((($startDate - $rdurWsecs) > $recurkey) || ($endDate < $recurkey)) // not within period
  1326. continue;
  1327. $checkDate = mktime(0, 0, 0, date('m', $recurkey), date('d', $recurkey), date('Y', $recurkey)); // on a day-basis !!!
  1328. if (isset($exdatelist[$checkDate])) // check excluded dates
  1329. continue;
  1330. if ($startWdate >= $recurkey) // exclude component start date
  1331. continue;
  1332. $component2 = $component->copy();
  1333. $rstart = $recurkey;
  1334. $rend = $recurkey + $durvalue;
  1335. /* add repeating components within valid dates to output array, only start date set */
  1336. if ($flat)
  1337. {
  1338. $datestring = date($startDateFormat, $recurkey);
  1339. if (isset($start['tz']))
  1340. $datestring .= ' ' . $start['tz'];
  1341. // echo "X-CURRENT-DTSTART 0 =$datestring tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
  1342. $component2->setProperty('X-CURRENT-DTSTART', $datestring);
  1343. if ($dtendExist || $dueExist || $durationExist)
  1344. {
  1345. $datestring = date($endDateFormat, $recurkey + $durvalue); // fixa korrekt sluttid
  1346. if (isset($end['tz']))
  1347. $datestring .= ' ' . $end['tz'];
  1348. $propName = (! $dueExist) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
  1349. $component2->setProperty($propName, $datestring);
  1350. } // end if( $dtendExist || $dueExist || $durationExist )
  1351. $component2->setProperty('X-RECURRENCE', ++ $xRecurrence);
  1352. $result[$component2->getProperty('UID')] = $component2->copy(); // copy to output
  1353. }
  1354. /* add repeating components within valid dates to output array, one each day */
  1355. elseif ($split)
  1356. {
  1357. if ($rend > $endDate)
  1358. $rend = $endDate;
  1359. $startYMD = date('Ymd', $rstart);
  1360. $endYMD = date('Ymd', $rend);
  1361. // echo "splitStart=".date( 'Y-m-d H:i:s', $rstart ).' end='.date( 'Y-m-d H:i:s', $rend )."<br />\n"; // test ###;
  1362. while ($rstart <= $rend)
  1363. { // iterate.. .
  1364. $checkDate = mktime(0, 0, 0, date('m', $rstart), date('d', $rstart), date('Y', $rstart)); // on a day-basis !!!
  1365. if (isset($exdatelist[$checkDate])) // exclude any recurrence START date, found in exdatelist
  1366. break;
  1367. // echo "checking date after startdate=".date( 'Y-m-d H:i:s', $rstart ).' mot '.date( 'Y-m-d H:i:s', $startDate )."<br />"; // test ###;
  1368. if ($rstart >= $startDate)
  1369. { // date after dtstart
  1370. if (date('Ymd', $rstart) > $startYMD) // date after dtstart
  1371. $datestring = date($startDateFormat, $checkDate);
  1372. else
  1373. $datestring = date($startDateFormat, $rstart);
  1374. if (isset($start['tz']))
  1375. $datestring .= ' ' . $start['tz'];
  1376. //echo "X-CURRENT-DTSTART 1 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
  1377. $component2->setProperty('X-CURRENT-DTSTART', $datestring);
  1378. if ($dtendExist || $dueExist || $durationExist)
  1379. {
  1380. if (date('Ymd', $rstart) < $endYMD) // not the last day
  1381. $tend = mktime(23, 59, 59, date('m', $rstart), date('d', $rstart), date('Y', $rstart));
  1382. else
  1383. $tend = mktime(date('H', $endWdate), date('i', $endWdate), date('s', $endWdate), date('m', $rstart), date('d', $rstart), date('Y', $rstart)); // on a day-basis !!!
  1384. $datestring = date($endDateFormat, $tend);
  1385. if (isset($end['tz']))
  1386. $datestring .= ' ' . $end['tz'];
  1387. $propName = (! $dueExist) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
  1388. $component2->setProperty($propName, $datestring);
  1389. } // end if( $dtendExist || $dueExist || $durationExist )
  1390. $component2->setProperty('X-RECURRENCE', $xRecurrence);
  1391. $wd = getdate($rstart);
  1392. $result[$wd['year']][$wd['mon']][$wd['mday']][$component2->getProperty('UID')] = $component2->copy(); // copy to output
  1393. } // end if( $checkDate > $startYMD ) { // date after dtstart
  1394. $rstart = mktime(date('H', $rstart), date('i', $rstart), date('s', $rstart), date('m', $rstart), date('d', $rstart) + 1, date('Y', $rstart)); // step one day
  1395. } // end while( $rstart <= $rend )
  1396. $xRecurrence += 1;
  1397. } // end elseif( $split )
  1398. elseif ($rstart >= $startDate)
  1399. { // date within period //* flat=FALSE && split=FALSE *//
  1400. $checkDate = mktime(0, 0, 0, date('m', $rstart), date('d', $rstart), date('Y', $rstart)); // on a day-basis !!!
  1401. if (! isset($exdatelist[$checkDate]))
  1402. { // exclude any recurrence START date, found in exdatelist
  1403. $xRecurrence += 1;
  1404. $datestring = date($startDateFormat, $rstart);
  1405. if (isset($start['tz']))
  1406. $datestring .= ' ' . $start['tz'];
  1407. //echo "X-CURRENT-DTSTART 2 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component2->setProperty( 'X-CNT', $tcnt ); // test ###
  1408. $component2->setProperty('X-CURRENT-DTSTART', $datestring);
  1409. if ($dtendExist || $dueExist || $durationExist)
  1410. {
  1411. $rstart += $rdurWsecs;
  1412. if (date('Ymd', $rstart) < date('Ymd', $endWdate))
  1413. $tend = mktime(23, 59, 59, date('m', $rstart), date('d', $rstart), date('Y', $rstart));
  1414. else
  1415. $tend = mktime(date('H', $endWdate), date('i', $endWdate), date('s', $endWdate), date('m', $rstart), date('d', $rstart), date('Y', $rstart)); // on a day-basis !!!
  1416. $datestring = date($endDateFormat, $tend);
  1417. if (isset($end['tz']))
  1418. $datestring .= ' ' . $end['tz'];
  1419. $propName = (! $dueExist) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
  1420. $component2->setProperty($propName, $datestring);
  1421. } // end if( $dtendExist || $dueExist || $durationExist )
  1422. $component2->setProperty('X-RECURRENCE', $xRecurrence);
  1423. $wd = getdate($rstart);
  1424. $result[$wd['year']][$wd['mon']][$wd['mday']][$component2->getProperty('UID')] = $component2->copy(); // copy to output
  1425. } // end if( !isset( $exdatelist[$checkDate] ))
  1426. } // end elseif( $rstart >= $startDate )
  1427. } // end foreach( $recurlist as $recurkey => $durvalue )
  1428. } // end if( 0 < count( $recurlist ))
  1429. /* deselect components with startdate/enddate not within period */
  1430. if (($endWdate < $startDate) || ($startWdate > $endDate))
  1431. continue;
  1432. } // end if( TRUE === $any )
  1433. /* deselect components with startdate not within period */
  1434. elseif (($startWdate < $startDate) || ($startWdate > $endDate))
  1435. continue;
  1436. /* add the selected component (WITHIN valid dates) to output array */
  1437. if ($flat)
  1438. $result[$component->getProperty('UID')] = $component->copy(); // copy to output;
  1439. elseif ($split)
  1440. { // split the original component
  1441. if ($endWdate > $endDate)
  1442. $endWdate = $endDate; // use period end date
  1443. $rstart = $startWdate;
  1444. if ($rstart < $startDate)
  1445. $rstart = $startDate; // use period start date
  1446. $checkDate = mktime(0, 0, 0, date('m', $rstart), date('d', $rstart), date('Y', $rstart)); // on a day-basis !!!
  1447. if (! isset($exdatelist[$checkDate]))
  1448. { // exclude any recurrence START date, found in exdatelist
  1449. foreach (array('X-CURRENT-DTSTART', 'X-CURRENT-DTEND', 'X-CURRENT-DUE',
  1450. 'X-RECURRENCE') as $propName)
  1451. $component->deleteProperty($propName); // remove any x-props, if set
  1452. while ($rstart <= $endWdate)
  1453. { // iterate
  1454. if ($rstart > $startWdate)
  1455. { // if NOT startdate, set X-properties
  1456. $datestring = date($startDateFormat, mktime(0, 0, 0, date('m', $rstart), date('d', $rstart), date('Y', $rstart)));
  1457. if (isset($start['tz']))
  1458. $datestring .= ' ' . $start['tz'];
  1459. // echo "X-CURRENT-DTSTART 3 = $datestring xRecurrence=$xRecurrence tcnt =".++$tcnt."<br />";$component->setProperty( 'X-CNT', $tcnt ); // test ###
  1460. $component->setProperty('X-CURRENT-DTSTART', $datestring);
  1461. if ($dtendExist || $dueExist || $durationExist)
  1462. {
  1463. if (date('Ymd', $rstart) < date('Ymd', $endWdate))
  1464. $tend = mktime(0, 0, 0, date('m', $rstart), date('d', $rstart), date('Y', $rstart));
  1465. else
  1466. $tend = mktime(date('H', $endWdate), date('i', $endWdate), date('s', $endWdate), date('m', $rstart), date('d', $rstart), date('Y', $rstart)); // on a day-basis !!!
  1467. $datestring = date($endDateFormat, $tend);
  1468. if (isset($end['tz']))
  1469. $datestring .= ' ' . $end['tz'];
  1470. $propName = (! $dueExist) ? 'X-CURRENT-DTEND' : 'X-CURRENT-DUE';
  1471. $component->setProperty($propName, $datestring);
  1472. } // end if( $dtendExist || $dueExist || $durationExist )
  1473. } // end if( $rstart > $startWdate )
  1474. $wd = getdate($rstart);
  1475. $result[$wd['year']][$wd['mon']][$wd['mday']][$component->getProperty('UID')] = $component->copy(); // copy to output
  1476. $rstart = mktime(date('H', $rstart), date('i', $rstart), date('s', $rstart), date('m', $rstart), date('d', $rstart) + 1, date('Y', $rstart)); // step one day
  1477. } // end while( $rstart <= $endWdate )
  1478. } // end if( !isset( $exdatelist[$checkDate] ))
  1479. } // end if( $split ) - else use component date
  1480. elseif ($startWdate >= $startDate)
  1481. { // within period
  1482. $checkDate = mktime(0, 0, 0, date('m', $startWdate), date('d', $startWdate), date('Y', $startWdate)); // on a day-basis !!!
  1483. if (! isset($exdatelist[$checkDate]))
  1484. { // exclude any recurrence START date, found in exdatelist
  1485. foreach (array('X-CURRENT-DTSTART', 'X-CURRENT-DTEND', 'X-CURRENT-DUE',
  1486. 'X-RECURRENCE') as $propName)
  1487. $component->deleteProperty($propName); // remove any x-props, if set
  1488. $wd = getdate($startWdate);
  1489. $result[$wd['year']][$wd['mon']][$wd['mday']][$component->getProperty('UID')] = $component->copy(); // copy to output
  1490. }
  1491. }
  1492. } // end foreach ( $this->components as $cix => $component )
  1493. if (0 >= count($result))
  1494. return FALSE;
  1495. elseif (! $flat)
  1496. {
  1497. foreach ($result as $y => $yeararr)
  1498. {
  1499. foreach ($yeararr as $m => $montharr)
  1500. {
  1501. foreach ($montharr as $d => $dayarr)
  1502. $result[$y][$m][$d] = array_values($dayarr); // skip tricky UID-index
  1503. ksort($result[$y][$m]);
  1504. }
  1505. ksort($result[$y]);
  1506. }
  1507. ksort($result);
  1508. } // end elseif( !$flat )
  1509. return $result;
  1510. }
  1511. /**
  1512. * select components from calendar on based on Categories, Location, Resources and/or Summary
  1513. *
  1514. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  1515. * @since 2.8.8 - 2011-05-03
  1516. * @param array $selectOptions, (string) key => (mixed) value, (key=propertyName)
  1517. * @return array
  1518. */
  1519. function selectComponents2($selectOptions)
  1520. {
  1521. $output = array();
  1522. $allowedProperties = array('ATTENDEE', 'CATEGORIES', 'LOCATION', 'ORGANIZER', 'RESOURCES', 'PRIORITY', 'STATUS',
  1523. 'SUMMARY', 'UID');
  1524. foreach ($this->components as $cix => $component3)
  1525. {
  1526. if (! in_array($component3->objName, array('vevent', 'vtodo', 'vjournal', 'vfreebusy')))
  1527. continue;
  1528. $uid = $component3->getProperty('UID');
  1529. foreach ($selectOptions as $propName => $pvalue)
  1530. {
  1531. $propName = strtoupper($propName);
  1532. if (! in_array($propName, $allowedProperties))
  1533. continue;
  1534. if (! is_array($pvalue))
  1535. $pvalue = array($pvalue);
  1536. if (('UID' == $propName) && in_array($uid, $pvalue))
  1537. {
  1538. $output[] = $component3->copy();
  1539. continue;
  1540. }
  1541. elseif (('ATTENDEE' == $propName) || ('CATEGORIES' == $propName) || ('RESOURCES' == $propName))
  1542. {
  1543. $propValues = array();
  1544. $component3->_getProperties($propName, $propValues);
  1545. $propValues = array_keys($propValues);
  1546. foreach ($pvalue as $theValue)
  1547. {
  1548. if (in_array($theValue, $propValues) && ! isset($output[$uid]))
  1549. {
  1550. $output[$uid] = $component3->copy();
  1551. break;
  1552. }
  1553. }
  1554. continue;
  1555. } // end elseif(( 'ATTENDEE' == $propName ) || ( 'CATEGORIES' == $propName ) || ( 'RESOURCES' == $propName ))
  1556. elseif (FALSE === ($d = $component3->getProperty($propName))) // single ocurrence
  1557. continue;
  1558. if (is_array($d))
  1559. {
  1560. foreach ($d as $part)
  1561. {
  1562. if (in_array($part, $pvalue) && ! isset($output[$uid]))
  1563. $output[$uid] = $component3->copy();
  1564. }
  1565. }
  1566. elseif (('SUMMARY' == $propName) && ! isset($output[$uid]))
  1567. {
  1568. foreach ($pvalue as $pval)
  1569. {
  1570. if (FALSE !== stripos($d, $pval))
  1571. {
  1572. $output[$uid] = $component3->copy();
  1573. break;
  1574. }
  1575. }
  1576. }
  1577. elseif (in_array($d, $pvalue) && ! isset($output[$uid]))
  1578. $output[$uid] = $component3->copy();
  1579. } // end foreach( $selectOptions as $propName => $pvalue ) {
  1580. } // end foreach( $this->components as $cix => $component3 ) {
  1581. if (! empty($output))
  1582. {
  1583. ksort($output);
  1584. $output = array_values($output);
  1585. }
  1586. return $output;
  1587. }
  1588. /**
  1589. * add calendar component to container
  1590. *
  1591. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  1592. * @since 2.8.8 - 2011-03-15
  1593. * @param object $component calendar component
  1594. * @param mixed $arg1 optional, ordno/component type/ component uid
  1595. * @param mixed $arg2 optional, ordno if arg1 = component type
  1596. * @return void
  1597. */
  1598. function setComponent($component, $arg1 = FALSE, $arg2 = FALSE)
  1599. {
  1600. $component->setConfig($this->getConfig(), FALSE, TRUE);
  1601. if (! in_array($component->objName, array('valarm', 'vtimezone')))
  1602. {
  1603. /* make sure dtstamp and uid is set */
  1604. $dummy1 = $component->getProperty('dtstamp');
  1605. $dummy2 = $component->getProperty('uid');
  1606. }
  1607. if (! $arg1)
  1608. { // plain insert, last in chain
  1609. $this->components[] = $component->copy();
  1610. return TRUE;
  1611. }
  1612. $argType = $index = null;
  1613. if (ctype_digit((string) $arg1))
  1614. { // index insert/replace
  1615. $argType = 'INDEX';
  1616. $index = (int) $arg1 - 1;
  1617. }
  1618. elseif (in_array(strtolower($arg1), array('vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone')))
  1619. {
  1620. $argType = strtolower($arg1);
  1621. $index = (ctype_digit((string) $arg2)) ? ((int) $arg2) - 1 : 0;
  1622. }
  1623. // else if arg1 is set, arg1 must be an UID
  1624. $cix1sC = 0;
  1625. foreach ($this->components as $cix => $component2)
  1626. {
  1627. if (empty($component2))
  1628. continue;
  1629. if (('INDEX' == $argType) && ($index == $cix))
  1630. { // index insert/replace
  1631. $this->components[$cix] = $component->copy();
  1632. return TRUE;
  1633. }
  1634. elseif ($argType == $component2->objName)
  1635. { // component Type index insert/replace
  1636. if ($index == $cix1sC)
  1637. {
  1638. $this->components[$cix] = $component->copy();
  1639. return TRUE;
  1640. }
  1641. $cix1sC ++;
  1642. }
  1643. elseif (! $argType && ($arg1 == $component2->getProperty('uid')))
  1644. { // UID insert/replace
  1645. $this->components[$cix] = $component->copy();
  1646. return TRUE;
  1647. }
  1648. }
  1649. /* arg1=index and not found.. . insert at index .. .*/
  1650. if ('INDEX' == $argType)
  1651. {
  1652. $this->components[$index] = $component->copy();
  1653. ksort($this->components, SORT_NUMERIC);
  1654. }
  1655. else /* not found.. . insert last in chain anyway .. .*/
  1656. $this->components[] = $component->copy();
  1657. return TRUE;
  1658. }
  1659. /**
  1660. * sort iCal compoments
  1661. *
  1662. * ascending sort on properties (if exist) x-current-dtstart, dtstart,
  1663. * x-current-dtend, dtend, x-current-due, due, duration, created, dtstamp, uid
  1664. * if no arguments, otherwise sorting on argument CATEGORIES, LOCATION, SUMMARY or RESOURCES
  1665. *
  1666. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  1667. * @since 2.8.4 - 2011-06-02
  1668. * @param string $sortArg, optional
  1669. * @return void
  1670. *
  1671. */
  1672. function sort($sortArg = FALSE)
  1673. {
  1674. if (is_array($this->components))
  1675. {
  1676. if ($sortArg)
  1677. {
  1678. $sortArg = strtoupper($sortArg);
  1679. if (! in_array($sortArg, array('ATTENDEE', 'CATEGORIES', 'DTSTAMP', 'LOCATION', 'ORGANIZER',
  1680. 'RESOURCES', 'PRIORITY', 'STATUS', 'SUMMARY')))
  1681. $sortArg = FALSE;
  1682. }
  1683. /* set sort parameters for each component */
  1684. foreach ($this->components as $cix => & $c)
  1685. {
  1686. $c->srtk = array('0', '0', '0', '0');
  1687. if ('vtimezone' == $c->objName)
  1688. {
  1689. if (FALSE === ($c->srtk[0] = $c->getProperty('tzid')))
  1690. $c->srtk[0] = 0;
  1691. continue;
  1692. }
  1693. elseif ($sortArg)
  1694. {
  1695. if (('ATTENDEE' == $sortArg) || ('CATEGORIES' == $sortArg) || ('RESOURCES' == $sortArg))
  1696. {
  1697. $propValues = array();
  1698. $c->_getProperties($sortArg, $propValues);
  1699. $c->srtk[0] = reset(array_keys($propValues));
  1700. }
  1701. elseif (FALSE !== ($d = $c->getProperty($sortArg)))
  1702. $c->srtk[0] = $d;
  1703. continue;
  1704. }
  1705. if (FALSE !== ($d = $c->getProperty('X-CURRENT-DTSTART')))
  1706. $c->srtk[0] = iCalUtilityFunctions :: _date_time_string($d[1]);
  1707. elseif (FALSE === ($c->srtk[0] = $c->getProperty('dtstart')))
  1708. $c->srtk[1] = 0; // sortkey 0 : dtstart
  1709. if (FALSE !== ($d = $c->getProperty('X-CURRENT-DTEND')))
  1710. $c->srtk[1] = iCalUtilityFunctions :: _date_time_string($d[1]); // sortkey 1 : dtend/due(/dtstart+duration)
  1711. elseif (FALSE === ($c->srtk[1] = $c->getProperty('dtend')))
  1712. {
  1713. if (FALSE !== ($d = $c->getProperty('X-CURRENT-DUE')))
  1714. $c->srtk[1] = iCalUtilityFunctions :: _date_time_string($d[1]);
  1715. elseif (FALSE === ($c->srtk[1] = $c->getProperty('due')))
  1716. if (FALSE === ($c->srtk[1] = $c->getProperty('duration', FALSE, FALSE, TRUE)))
  1717. $c->srtk[1] = 0;
  1718. }
  1719. if (FALSE === ($c->srtk[2] = $c->getProperty('created'))) // sortkey 2 : created/dtstamp
  1720. if (FALSE === ($c->srtk[2] = $c->getProperty('dtstamp')))
  1721. $c->srtk[2] = 0;
  1722. if (FALSE === ($c->srtk[3] = $c->getProperty('uid'))) // sortkey 3 : uid
  1723. $c->srtk[3] = 0;
  1724. } // end foreach( $this->components as & $c
  1725. /* sort */
  1726. usort($this->components, array($this, '_cmpfcn'));
  1727. }
  1728. }
  1729. function _cmpfcn($a, $b)
  1730. {
  1731. if (empty($a))
  1732. return - 1;
  1733. if (empty($b))
  1734. return 1;
  1735. if ('vtimezone' == $a->objName)
  1736. {
  1737. if ('vtimezone' != $b->objName)
  1738. return - 1;
  1739. elseif ($a->srtk[0] <= $b->srtk[0])
  1740. return - 1;
  1741. else
  1742. return 1;
  1743. }
  1744. elseif ('vtimezone' == $b->objName)
  1745. return 1;
  1746. $sortkeys = array('year', 'month', 'day', 'hour', 'min', 'sec');
  1747. for($k = 0; $k < 4; $k ++)
  1748. {
  1749. if (empty($a->srtk[$k]))
  1750. return - 1;
  1751. elseif (empty($b->srtk[$k]))
  1752. return 1;
  1753. if (is_array($a->srtk[$k]))
  1754. {
  1755. if (is_array($b->srtk[$k]))
  1756. {
  1757. foreach ($sortkeys as $key)
  1758. {
  1759. if (empty($a->srtk[$k][$key]))
  1760. return - 1;
  1761. elseif (empty($b->srtk[$k][$key]))
  1762. return 1;
  1763. if ($a->srtk[$k][$key] == $b->srtk[$k][$key])
  1764. continue;
  1765. if (((int) $a->srtk[$k][$key]) < ((int) $b->srtk[$k][$key]))
  1766. return - 1;
  1767. elseif (((int) $a->srtk[$k][$key]) > ((int) $b->srtk[$k][$key]))
  1768. return 1;
  1769. }
  1770. }
  1771. else
  1772. return - 1;
  1773. }
  1774. elseif (is_array($b->srtk[$k]))
  1775. return 1;
  1776. elseif ($a->srtk[$k] < $b->srtk[$k])
  1777. return - 1;
  1778. elseif ($a->srtk[$k] > $b->srtk[$k])
  1779. return 1;
  1780. }
  1781. return 0;
  1782. }
  1783. /**
  1784. * parse iCal text/file into vcalendar, components, properties and parameters
  1785. *
  1786. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  1787. * @since 2.8.2 - 2011-05-21
  1788. * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of property strings
  1789. * @return bool FALSE if error occurs during parsing
  1790. *
  1791. */
  1792. function parse($unparsedtext = FALSE)
  1793. {
  1794. $nl = $this->getConfig('nl');
  1795. if ((FALSE === $unparsedtext) || empty($unparsedtext))
  1796. {
  1797. /* directory+filename is set previously via setConfig directory+filename or url */
  1798. if (FALSE === ($filename = $this->getConfig('url')))
  1799. $filename = $this->getConfig('dirfile');
  1800. /* READ FILE */
  1801. if (FALSE === ($rows = file_get_contents($filename)))
  1802. return FALSE; /* err 1 */
  1803. }
  1804. elseif (is_array($unparsedtext))
  1805. $rows = implode('\n' . $nl, $unparsedtext);
  1806. else
  1807. $rows = & $unparsedtext;
  1808. /* identify BEGIN:VCALENDAR, MUST be first row */
  1809. if ('BEGIN:VCALENDAR' != strtoupper(substr($rows, 0, 15)))
  1810. return FALSE; /* err 8 */
  1811. /* fix line folding */
  1812. $eolchars = array("\r\n", "\n\r", "\n", "\r"); // check all line endings
  1813. $EOLmark = FALSE;
  1814. foreach ($eolchars as $eolchar)
  1815. {
  1816. if (! $EOLmark && (FALSE !== strpos($rows, $eolchar)))
  1817. {
  1818. $rows = str_replace($eolchar . " ", '', $rows);
  1819. $rows = str_replace($eolchar . "\t", '', $rows);
  1820. if ($eolchar != $nl)
  1821. $rows = str_replace($eolchar, $nl, $rows);
  1822. $EOLmark = TRUE;
  1823. }
  1824. }
  1825. $tmp = explode($nl, $rows);
  1826. $rows = array();
  1827. foreach ($tmp as $tmpr)
  1828. if (! empty($tmpr))
  1829. $rows[] = $tmpr;
  1830. /* skip trailing empty lines */
  1831. $lix = count($rows) - 1;
  1832. while (empty($rows[$lix]) && (0 < $lix))
  1833. $lix -= 1;
  1834. /* identify ending END:VCALENDAR row, MUST be last row */
  1835. if ('END:VCALENDAR' != strtoupper(substr($rows[$lix], 0, 13)))
  1836. return FALSE; /* err 9 */
  1837. if (3 > count($rows))
  1838. return FALSE; /* err 10 */
  1839. $comp = & $this;
  1840. $calsync = 0;
  1841. /* identify components and update unparsed data within component */
  1842. $config = $this->getConfig();
  1843. foreach ($rows as $line)
  1844. {
  1845. if ('' == trim($line))
  1846. continue;
  1847. if ('BEGIN:VCALENDAR' == strtoupper(substr($line, 0, 15)))
  1848. {
  1849. $calsync ++;
  1850. continue;
  1851. }
  1852. elseif ('END:VCALENDAR' == strtoupper(substr($line, 0, 13)))
  1853. {
  1854. $calsync --;
  1855. break;
  1856. }
  1857. elseif (1 != $calsync)
  1858. return FALSE; /* err 20 */
  1859. elseif (in_array(strtoupper(substr($line, 0, 6)), array('END:VE', 'END:VF', 'END:VJ', 'END:VT')))
  1860. {
  1861. $this->components[] = $comp->copy();
  1862. continue;
  1863. }
  1864. if ('BEGIN:VEVENT' == strtoupper(substr($line, 0, 12)))
  1865. $comp = new vevent($config);
  1866. elseif ('BEGIN:VFREEBUSY' == strtoupper(substr($line, 0, 15)))
  1867. $comp = new vfreebusy($config);
  1868. elseif ('BEGIN:VJOURNAL' == strtoupper(substr($line, 0, 14)))
  1869. $comp = new vjournal($config);
  1870. elseif ('BEGIN:VTODO' == strtoupper(substr($line, 0, 11)))
  1871. $comp = new vtodo($config);
  1872. elseif ('BEGIN:VTIMEZONE' == strtoupper(substr($line, 0, 15)))
  1873. $comp = new vtimezone($config);
  1874. else /* update component with unparsed data */
  1875. $comp->unparsed[] = $line;
  1876. } // end - foreach( rows.. .
  1877. unset($config);
  1878. /* parse data for calendar (this) object */
  1879. if (isset($this->unparsed) && is_array($this->unparsed) && (0 < count($this->unparsed)))
  1880. {
  1881. /* concatenate property values spread over several lines */
  1882. $lastix = - 1;
  1883. $propnames = array('calscale', 'method', 'prodid', 'version', 'x-');
  1884. $proprows = array();
  1885. foreach ($this->unparsed as $line)
  1886. {
  1887. if ('' == trim($line))
  1888. continue;
  1889. $newProp = FALSE;
  1890. foreach ($propnames as $propname)
  1891. {
  1892. if ($propname == strtolower(substr($line, 0, strlen($propname))))
  1893. {
  1894. $newProp = TRUE;
  1895. break;
  1896. }
  1897. }
  1898. if ($newProp)
  1899. {
  1900. $newProp = FALSE;
  1901. $lastix ++;
  1902. $proprows[$lastix] = $line;
  1903. }
  1904. else
  1905. $proprows[$lastix] .= '!"#¤%&/()=?' . $line;
  1906. }
  1907. foreach ($proprows as $line)
  1908. {
  1909. $line = str_replace('!"#¤%&/()=? ', '', $line);
  1910. $line = str_replace('!"#¤%&/()=?', '', $line);
  1911. if ('\n' == substr($line, - 2))
  1912. $line = substr($line, 0, strlen($line) - 2);
  1913. /* get property name */
  1914. $cix = $propname = null;
  1915. for($cix = 0, $clen = strlen($line); $cix < $clen; $cix ++)
  1916. {
  1917. if (in_array($line[$cix], array(':', ';')))
  1918. break;
  1919. else
  1920. $propname .= $line[$cix];
  1921. }
  1922. /* ignore version/prodid properties */
  1923. if (in_array(strtoupper($propname), array('VERSION', 'PRODID')))
  1924. continue;
  1925. $line = substr($line, $cix);
  1926. /* separate attributes from value */
  1927. $attr = array();
  1928. $attrix = - 1;
  1929. $strlen = strlen($line);
  1930. for($cix = 0; $cix < $strlen; $cix ++)
  1931. {
  1932. if ((':' == $line[$cix]) && ('://' != substr($line, $cix, 3)) && (! in_array(strtolower(substr($line, $cix - 3, 4)), array(
  1933. 'fax:', 'cid:', 'sms:', 'tel:', 'urn:'))) && (! in_array(strtolower(substr($line, $cix - 4, 5)), array(
  1934. 'crid:', 'news:', 'pres:'))) && ('mailto:' != strtolower(substr($line, $cix - 6, 7))))
  1935. {
  1936. $attrEnd = TRUE;
  1937. if (($cix < ($strlen - 4)) && ctype_digit(substr($line, $cix + 1, 4)))
  1938. { // an URI with a (4pos) portnr??
  1939. for($c2ix = $cix; 3 < $c2ix; $c2ix --)
  1940. {
  1941. if ('://' == substr($line, $c2ix - 2, 3))
  1942. {
  1943. $attrEnd = FALSE;
  1944. break; // an URI with a portnr!!
  1945. }
  1946. }
  1947. }
  1948. if ($attrEnd)
  1949. {
  1950. $line = substr($line, $cix + 1);
  1951. break;
  1952. }
  1953. }
  1954. if (';' == $line[$cix])
  1955. $attr[++ $attrix] = null;
  1956. else
  1957. $attr[$attrix] .= $line[$cix];
  1958. }
  1959. /* make attributes in array format */
  1960. $propattr = array();
  1961. foreach ($attr as $attribute)
  1962. {
  1963. $attrsplit = explode('=', $attribute, 2);
  1964. if (1 < count($attrsplit))
  1965. $propattr[$attrsplit[0]] = $attrsplit[1];
  1966. else
  1967. $propattr[] = $attribute;
  1968. }
  1969. /* update Property */
  1970. if (FALSE !== strpos($line, ','))
  1971. {
  1972. $content = explode(',', $line);
  1973. $clen = count($content);
  1974. for($cix = 0; $cix < $clen; $cix ++)
  1975. {
  1976. if ("\\" == substr($content[$cix], - 1))
  1977. {
  1978. $content[$cix] .= ',' . $content[$cix + 1];
  1979. unset($content[$cix + 1]);
  1980. $cix ++;
  1981. }
  1982. }
  1983. if (1 < count($content))
  1984. {
  1985. foreach ($content as $cix => $contentPart)
  1986. $content[$cix] = calendarComponent :: _strunrep($contentPart);
  1987. $this->setProperty($propname, $content, $propattr);
  1988. continue;
  1989. }
  1990. else
  1991. $line = reset($content);
  1992. $line = calendarComponent :: _strunrep($line);
  1993. }
  1994. $this->setProperty($propname, trim($line), $propattr);
  1995. } // end - foreach( $this->unparsed.. .
  1996. } // end - if( is_array( $this->unparsed.. .
  1997. unset($unparsedtext, $rows, $this->unparsed, $proprows);
  1998. /* parse Components */
  1999. if (is_array($this->components) && (0 < count($this->components)))
  2000. {
  2001. $ckeys = array_keys($this->components);
  2002. foreach ($ckeys as $ckey)
  2003. {
  2004. if (! empty($this->components[$ckey]) && ! empty($this->components[$ckey]->unparsed))
  2005. {
  2006. $this->components[$ckey]->parse();
  2007. }
  2008. }
  2009. }
  2010. else
  2011. return FALSE; /* err 91 or something.. . */
  2012. return TRUE;
  2013. }
  2014. /*********************************************************************************/
  2015. /**
  2016. * creates formatted output for calendar object instance
  2017. *
  2018. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2019. * @since 2.8.1 - 2011-03-12
  2020. * @return string
  2021. */
  2022. function createCalendar()
  2023. {
  2024. $calendarInit1 = $calendarInit2 = $calendarxCaldecl = $calendarStart = $calendar = null;
  2025. switch ($this->format)
  2026. {
  2027. case 'xcal' :
  2028. $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"';
  2029. $calendarInit2 = '>' . $this->nl;
  2030. $calendarStart = '<vcalendar';
  2031. break;
  2032. default :
  2033. $calendarStart = 'BEGIN:VCALENDAR' . $this->nl;
  2034. break;
  2035. }
  2036. $calendarStart .= $this->createVersion();
  2037. $calendarStart .= $this->createProdid();
  2038. $calendarStart .= $this->createCalscale();
  2039. $calendarStart .= $this->createMethod();
  2040. switch ($this->format)
  2041. {
  2042. case 'xcal' :
  2043. $nlstrlen = strlen($this->nl);
  2044. if ($this->nl == substr($calendarStart, (0 - $nlstrlen)))
  2045. $calendarStart = substr($calendarStart, 0, (strlen($calendarStart) - $nlstrlen));
  2046. $calendarStart .= '>' . $this->nl;
  2047. break;
  2048. default :
  2049. break;
  2050. }
  2051. $calendar .= $this->createXprop();
  2052. foreach ($this->components as $component)
  2053. {
  2054. if (empty($component))
  2055. continue;
  2056. $component->setConfig($this->getConfig(), FALSE, TRUE);
  2057. $calendar .= $component->createComponent($this->xcaldecl);
  2058. }
  2059. if ((0 < count($this->xcaldecl)) && ('xcal' == $this->format))
  2060. { // xCal only
  2061. $calendarInit1 .= $this->nl . '[' . $this->nl;
  2062. $old_xcaldecl = array();
  2063. foreach ($this->xcaldecl as $declix => $declPart)
  2064. {
  2065. if ((0 < count($old_xcaldecl)) && (in_array($declPart['uri'], $old_xcaldecl['uri'])) && (in_array($declPart['external'], $old_xcaldecl['external'])))
  2066. continue; // no duplicate uri and ext. references
  2067. $calendarxCaldecl .= '<!';
  2068. foreach ($declPart as $declKey => $declValue)
  2069. {
  2070. switch ($declKey)
  2071. { // index
  2072. case 'xmldecl' : // no 1
  2073. $calendarxCaldecl .= $declValue . ' ';
  2074. break;
  2075. case 'uri' : // no 2
  2076. $calendarxCaldecl .= $declValue . ' ';
  2077. $old_xcaldecl['uri'][] = $declValue;
  2078. break;
  2079. case 'ref' : // no 3
  2080. $calendarxCaldecl .= $declValue . ' ';
  2081. break;
  2082. case 'external' : // no 4
  2083. $calendarxCaldecl .= '"' . $declValue . '" ';
  2084. $old_xcaldecl['external'][] = $declValue;
  2085. break;
  2086. case 'type' : // no 5
  2087. $calendarxCaldecl .= $declValue . ' ';
  2088. break;
  2089. case 'type2' : // no 6
  2090. $calendarxCaldecl .= $declValue;
  2091. break;
  2092. }
  2093. }
  2094. $calendarxCaldecl .= '>' . $this->nl;
  2095. }
  2096. $calendarInit2 = ']' . $calendarInit2;
  2097. }
  2098. switch ($this->format)
  2099. {
  2100. case 'xcal' :
  2101. $calendar .= '</vcalendar>' . $this->nl;
  2102. break;
  2103. default :
  2104. $calendar .= 'END:VCALENDAR' . $this->nl;
  2105. break;
  2106. }
  2107. return $calendarInit1 . $calendarxCaldecl . $calendarInit2 . $calendarStart . $calendar;
  2108. }
  2109. /**
  2110. * a HTTP redirect header is sent with created, updated and/or parsed calendar
  2111. *
  2112. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2113. * @since 2.9.12 - 2011-07-13
  2114. * @param bool $utf8Encode
  2115. * @param bool $gzip
  2116. * @return redirect
  2117. */
  2118. function returnCalendar($utf8Encode = FALSE, $gzip = FALSE)
  2119. {
  2120. $filename = $this->getConfig('filename');
  2121. $output = $this->createCalendar();
  2122. if ($utf8Encode)
  2123. $output = utf8_encode($output);
  2124. if ($gzip)
  2125. {
  2126. $output = gzencode($output, 9);
  2127. header('Content-Encoding: gzip');
  2128. header('Vary: *');
  2129. }
  2130. $filesize = strlen($output);
  2131. if ('xcal' == $this->format)
  2132. header('Content-Type: application/calendar+xml; charset=utf-8');
  2133. else
  2134. header('Content-Type: text/calendar; charset=utf-8');
  2135. header('Content-Length: ' . $filesize);
  2136. header('Content-Disposition: attachment; filename="' . $filename . '"');
  2137. header('Cache-Control: max-age=10');
  2138. echo $output;
  2139. die();
  2140. }
  2141. /**
  2142. * save content in a file
  2143. *
  2144. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2145. * @since 2.2.12 - 2007-12-30
  2146. * @param string $directory optional
  2147. * @param string $filename optional
  2148. * @param string $delimiter optional
  2149. * @return bool
  2150. */
  2151. function saveCalendar($directory = FALSE, $filename = FALSE, $delimiter = FALSE)
  2152. {
  2153. if ($directory)
  2154. $this->setConfig('directory', $directory);
  2155. if ($filename)
  2156. $this->setConfig('filename', $filename);
  2157. if ($delimiter && ($delimiter != DIRECTORY_SEPARATOR))
  2158. $this->setConfig('delimiter', $delimiter);
  2159. if (FALSE === ($dirfile = $this->getConfig('url')))
  2160. $dirfile = $this->getConfig('dirfile');
  2161. $iCalFile = @fopen($dirfile, 'w');
  2162. if ($iCalFile)
  2163. {
  2164. if (FALSE === fwrite($iCalFile, $this->createCalendar()))
  2165. return FALSE;
  2166. fclose($iCalFile);
  2167. return TRUE;
  2168. }
  2169. else
  2170. return FALSE;
  2171. }
  2172. /**
  2173. * if recent version of calendar file exists (default one hour), an HTTP redirect header is sent
  2174. * else FALSE is returned
  2175. *
  2176. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2177. * @since 2.2.12 - 2007-10-28
  2178. * @param string $directory optional alt. int timeout
  2179. * @param string $filename optional
  2180. * @param string $delimiter optional
  2181. * @param int timeout optional, default 3600 sec
  2182. * @return redirect/FALSE
  2183. */
  2184. function useCachedCalendar($directory = FALSE, $filename = FALSE, $delimiter = FALSE, $timeout = 3600)
  2185. {
  2186. if ($directory && ctype_digit((string) $directory) && ! $filename)
  2187. {
  2188. $timeout = (int) $directory;
  2189. $directory = FALSE;
  2190. }
  2191. if ($directory)
  2192. $this->setConfig('directory', $directory);
  2193. if ($filename)
  2194. $this->setConfig('filename', $filename);
  2195. if ($delimiter && ($delimiter != DIRECTORY_SEPARATOR))
  2196. $this->setConfig('delimiter', $delimiter);
  2197. $filesize = $this->getConfig('filesize');
  2198. if (0 >= $filesize)
  2199. return FALSE;
  2200. $dirfile = $this->getConfig('dirfile');
  2201. if (time() - filemtime($dirfile) < $timeout)
  2202. {
  2203. clearstatcache();
  2204. $dirfile = $this->getConfig('dirfile');
  2205. $filename = $this->getConfig('filename');
  2206. // if( headers_sent( $filename, $linenum ))
  2207. // die( "Headers already sent in $filename on line $linenum\n" );
  2208. if ('xcal' == $this->format)
  2209. header('Content-Type: application/calendar+xml; charset=utf-8');
  2210. else
  2211. header('Content-Type: text/calendar; charset=utf-8');
  2212. header('Content-Length: ' . $filesize);
  2213. header('Content-Disposition: attachment; filename="' . $filename . '"');
  2214. header('Cache-Control: max-age=10');
  2215. $fp = @fopen($dirfile, 'r');
  2216. if ($fp)
  2217. {
  2218. fpassthru($fp);
  2219. fclose($fp);
  2220. }
  2221. die();
  2222. }
  2223. else
  2224. return FALSE;
  2225. }
  2226. }
  2227. /*********************************************************************************/
  2228. /*********************************************************************************/
  2229. /**
  2230. * abstract class for calendar components
  2231. *
  2232. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2233. * @since 2.9.6 - 2011-05-14
  2234. */
  2235. class calendarComponent
  2236. {
  2237. // component property variables
  2238. var $uid;
  2239. var $dtstamp;
  2240. // component config variables
  2241. var $allowEmpty;
  2242. var $language;
  2243. var $nl;
  2244. var $unique_id;
  2245. var $format;
  2246. var $objName; // created automatically at instance creation
  2247. var $dtzid; // default (local) timezone
  2248. // component internal variables
  2249. var $componentStart1;
  2250. var $componentStart2;
  2251. var $componentEnd1;
  2252. var $componentEnd2;
  2253. var $elementStart1;
  2254. var $elementStart2;
  2255. var $elementEnd1;
  2256. var $elementEnd2;
  2257. var $intAttrDelimiter;
  2258. var $attributeDelimiter;
  2259. var $valueInit;
  2260. // component xCal declaration container
  2261. var $xcaldecl;
  2262. /**
  2263. * constructor for calendar component object
  2264. *
  2265. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2266. * @since 2.9.6 - 2011-05-17
  2267. */
  2268. function calendarComponent()
  2269. {
  2270. $this->objName = (isset($this->timezonetype)) ? strtolower($this->timezonetype) : get_class($this);
  2271. $this->uid = array();
  2272. $this->dtstamp = array();
  2273. $this->language = null;
  2274. $this->nl = null;
  2275. $this->unique_id = null;
  2276. $this->format = null;
  2277. $this->dtzid = null;
  2278. $this->allowEmpty = TRUE;
  2279. $this->xcaldecl = array();
  2280. $this->_createFormat();
  2281. $this->_makeDtstamp();
  2282. }
  2283. /*********************************************************************************/
  2284. /**
  2285. * Property Name: ACTION
  2286. */
  2287. /**
  2288. * creates formatted output for calendar component property action
  2289. *
  2290. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2291. * @since 2.4.8 - 2008-10-22
  2292. * @return string
  2293. */
  2294. function createAction()
  2295. {
  2296. if (empty($this->action))
  2297. return FALSE;
  2298. if (empty($this->action['value']))
  2299. return ($this->getConfig('allowEmpty')) ? $this->_createElement('ACTION') : FALSE;
  2300. $attributes = $this->_createParams($this->action['params']);
  2301. return $this->_createElement('ACTION', $attributes, $this->action['value']);
  2302. }
  2303. /**
  2304. * set calendar component property action
  2305. *
  2306. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2307. * @since 2.4.8 - 2008-11-04
  2308. * @param string $value "AUDIO" / "DISPLAY" / "EMAIL" / "PROCEDURE"
  2309. * @param mixed $params
  2310. * @return bool
  2311. */
  2312. function setAction($value, $params = FALSE)
  2313. {
  2314. if (empty($value))
  2315. if ($this->getConfig('allowEmpty'))
  2316. $value = null;
  2317. else
  2318. return FALSE;
  2319. $this->action = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  2320. return TRUE;
  2321. }
  2322. /*********************************************************************************/
  2323. /**
  2324. * Property Name: ATTACH
  2325. */
  2326. /**
  2327. * creates formatted output for calendar component property attach
  2328. *
  2329. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2330. * @since 0.9.7 - 2006-11-23
  2331. * @return string
  2332. */
  2333. function createAttach()
  2334. {
  2335. if (empty($this->attach))
  2336. return FALSE;
  2337. $output = null;
  2338. foreach ($this->attach as $attachPart)
  2339. {
  2340. if (! empty($attachPart['value']))
  2341. {
  2342. $attributes = $this->_createParams($attachPart['params']);
  2343. $output .= $this->_createElement('ATTACH', $attributes, $attachPart['value']);
  2344. }
  2345. elseif ($this->getConfig('allowEmpty'))
  2346. $output .= $this->_createElement('ATTACH');
  2347. }
  2348. return $output;
  2349. }
  2350. /**
  2351. * set calendar component property attach
  2352. *
  2353. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2354. * @since 2.5.1 - 2008-11-06
  2355. * @param string $value
  2356. * @param array $params, optional
  2357. * @param integer $index, optional
  2358. * @return bool
  2359. */
  2360. function setAttach($value, $params = FALSE, $index = FALSE)
  2361. {
  2362. if (empty($value))
  2363. if ($this->getConfig('allowEmpty'))
  2364. $value = null;
  2365. else
  2366. return FALSE;
  2367. iCalUtilityFunctions :: _setMval($this->attach, $value, $params, FALSE, $index);
  2368. return TRUE;
  2369. }
  2370. /*********************************************************************************/
  2371. /**
  2372. * Property Name: ATTENDEE
  2373. */
  2374. /**
  2375. * creates formatted output for calendar component property attendee
  2376. *
  2377. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2378. * @since 2.9.8 - 2011-05-30
  2379. * @return string
  2380. */
  2381. function createAttendee()
  2382. {
  2383. if (empty($this->attendee))
  2384. return FALSE;
  2385. $output = null;
  2386. foreach ($this->attendee as $attendeePart)
  2387. { // start foreach 1
  2388. if (empty($attendeePart['value']))
  2389. {
  2390. if ($this->getConfig('allowEmpty'))
  2391. $output .= $this->_createElement('ATTENDEE');
  2392. continue;
  2393. }
  2394. $attendee1 = $attendee2 = null;
  2395. foreach ($attendeePart as $paramlabel => $paramvalue)
  2396. { // start foreach 2
  2397. if ('value' == $paramlabel)
  2398. $attendee2 .= $paramvalue;
  2399. elseif (('params' == $paramlabel) && (is_array($paramvalue)))
  2400. { // start elseif
  2401. // set attenddee parameters in rfc2445 order
  2402. if (isset($paramvalue['CUTYPE']))
  2403. $attendee1 .= $this->intAttrDelimiter . 'CUTYPE=' . $paramvalue['CUTYPE'];
  2404. if (isset($paramvalue['MEMBER']))
  2405. {
  2406. $attendee1 .= $this->intAttrDelimiter . 'MEMBER=';
  2407. foreach ($paramvalue['MEMBER'] as $cix => $opv)
  2408. $attendee1 .= ($cix) ? ', "' . $opv . '"' : '"' . $opv . '"';
  2409. }
  2410. if (isset($paramvalue['ROLE']))
  2411. $attendee1 .= $this->intAttrDelimiter . 'ROLE=' . $paramvalue['ROLE'];
  2412. if (isset($paramvalue['PARTSTAT']))
  2413. $attendee1 .= $this->intAttrDelimiter . 'PARTSTAT=' . $paramvalue['PARTSTAT'];
  2414. if (isset($paramvalue['RSVP']))
  2415. $attendee1 .= $this->intAttrDelimiter . 'RSVP=' . $paramvalue['RSVP'];
  2416. if (isset($paramvalue['DELEGATED-TO']))
  2417. {
  2418. $attendee1 .= $this->intAttrDelimiter . 'DELEGATED-TO=';
  2419. foreach ($paramvalue['DELEGATED-TO'] as $cix => $opv)
  2420. $attendee1 .= ($cix) ? ', "' . $opv . '"' : '"' . $opv . '"';
  2421. }
  2422. if (isset($paramvalue['DELEGATED-FROM']))
  2423. {
  2424. $attendee1 .= $this->intAttrDelimiter . 'DELEGATED-FROM=';
  2425. foreach ($paramvalue['DELEGATED-FROM'] as $cix => $opv)
  2426. $attendee1 .= ($cix) ? ', "' . $opv . '"' : '"' . $opv . '"';
  2427. }
  2428. if (isset($paramvalue['SENT-BY']))
  2429. $attendee1 .= $this->intAttrDelimiter . 'SENT-BY="' . $paramvalue['SENT-BY'] . '"';
  2430. if (isset($paramvalue['CN']))
  2431. $attendee1 .= $this->intAttrDelimiter . 'CN="' . $paramvalue['CN'] . '"';
  2432. if (isset($paramvalue['DIR']))
  2433. $attendee1 .= $this->intAttrDelimiter . 'DIR="' . $paramvalue['DIR'] . '"';
  2434. if (isset($paramvalue['LANGUAGE']))
  2435. $attendee1 .= $this->intAttrDelimiter . 'LANGUAGE=' . $paramvalue['LANGUAGE'];
  2436. $xparams = array();
  2437. foreach ($paramvalue as $optparamlabel => $optparamvalue)
  2438. { // start foreach 3
  2439. if (ctype_digit((string) $optparamlabel))
  2440. {
  2441. $xparams[] = $optparamvalue;
  2442. continue;
  2443. }
  2444. if (! in_array($optparamlabel, array('CUTYPE', 'MEMBER', 'ROLE', 'PARTSTAT', 'RSVP',
  2445. 'DELEGATED-TO', 'DELEGATED-FROM', 'SENT-BY', 'CN', 'DIR', 'LANGUAGE')))
  2446. $xparams[$optparamlabel] = $optparamvalue;
  2447. } // end foreach 3
  2448. ksort($xparams, SORT_STRING);
  2449. foreach ($xparams as $paramKey => $paramValue)
  2450. {
  2451. if (ctype_digit((string) $paramKey))
  2452. $attendee1 .= $this->intAttrDelimiter . $paramValue;
  2453. else
  2454. $attendee1 .= $this->intAttrDelimiter . "$paramKey=$paramValue";
  2455. } // end foreach 3
  2456. } // end elseif(( 'params' == $paramlabel ) && ( is_array( $paramvalue )))
  2457. } // end foreach 2
  2458. $output .= $this->_createElement('ATTENDEE', $attendee1, $attendee2);
  2459. } // end foreach 1
  2460. return $output;
  2461. }
  2462. /**
  2463. * set calendar component property attach
  2464. *
  2465. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2466. * @since 2.6.34 - 2010-12-18
  2467. * @param string $value
  2468. * @param array $params, optional
  2469. * @param integer $index, optional
  2470. * @return bool
  2471. */
  2472. function setAttendee($value, $params = FALSE, $index = FALSE)
  2473. {
  2474. if (empty($value))
  2475. if ($this->getConfig('allowEmpty'))
  2476. $value = null;
  2477. else
  2478. return FALSE;
  2479. // ftp://, http://, mailto:, file://, gopher://, news:, nntp://, telnet://, wais://, prospero:// may exist.. . also in params
  2480. if (FALSE !== ($pos = strpos(substr($value, 0, 9), ':')))
  2481. $value = strtoupper(substr($value, 0, $pos)) . substr($value, $pos);
  2482. elseif (! empty($value))
  2483. $value = 'MAILTO:' . $value;
  2484. $params2 = array();
  2485. if (is_array($params))
  2486. {
  2487. $optarrays = array();
  2488. foreach ($params as $optparamlabel => $optparamvalue)
  2489. {
  2490. $optparamlabel = strtoupper($optparamlabel);
  2491. switch ($optparamlabel)
  2492. {
  2493. case 'MEMBER' :
  2494. case 'DELEGATED-TO' :
  2495. case 'DELEGATED-FROM' :
  2496. if (! is_array($optparamvalue))
  2497. $optparamvalue = array($optparamvalue);
  2498. foreach ($optparamvalue as $part)
  2499. {
  2500. $part = trim($part);
  2501. if (('"' == substr($part, 0, 1)) && ('"' == substr($part, - 1)))
  2502. $part = substr($part, 1, (strlen($part) - 2));
  2503. if ('mailto:' != strtolower(substr($part, 0, 7)))
  2504. $part = "MAILTO:$part";
  2505. else
  2506. $part = 'MAILTO:' . substr($part, 7);
  2507. $optarrays[$optparamlabel][] = $part;
  2508. }
  2509. break;
  2510. default :
  2511. if (('"' == substr($optparamvalue, 0, 1)) && ('"' == substr($optparamvalue, - 1)))
  2512. $optparamvalue = substr($optparamvalue, 1, (strlen($optparamvalue) - 2));
  2513. if ('SENT-BY' == $optparamlabel)
  2514. {
  2515. if ('mailto:' != strtolower(substr($optparamvalue, 0, 7)))
  2516. $optparamvalue = "MAILTO:$optparamvalue";
  2517. else
  2518. $optparamvalue = 'MAILTO:' . substr($optparamvalue, 7);
  2519. }
  2520. $params2[$optparamlabel] = $optparamvalue;
  2521. break;
  2522. } // end switch( $optparamlabel.. .
  2523. } // end foreach( $optparam.. .
  2524. foreach ($optarrays as $optparamlabel => $optparams)
  2525. $params2[$optparamlabel] = $optparams;
  2526. }
  2527. // remove defaults
  2528. iCalUtilityFunctions :: _existRem($params2, 'CUTYPE', 'INDIVIDUAL');
  2529. iCalUtilityFunctions :: _existRem($params2, 'PARTSTAT', 'NEEDS-ACTION');
  2530. iCalUtilityFunctions :: _existRem($params2, 'ROLE', 'REQ-PARTICIPANT');
  2531. iCalUtilityFunctions :: _existRem($params2, 'RSVP', 'FALSE');
  2532. // check language setting
  2533. if (isset($params2['CN']))
  2534. {
  2535. $lang = $this->getConfig('language');
  2536. if (! isset($params2['LANGUAGE']) && ! empty($lang))
  2537. $params2['LANGUAGE'] = $lang;
  2538. }
  2539. iCalUtilityFunctions :: _setMval($this->attendee, $value, $params2, FALSE, $index);
  2540. return TRUE;
  2541. }
  2542. /*********************************************************************************/
  2543. /**
  2544. * Property Name: CATEGORIES
  2545. */
  2546. /**
  2547. * creates formatted output for calendar component property categories
  2548. *
  2549. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2550. * @since 2.4.8 - 2008-10-22
  2551. * @return string
  2552. */
  2553. function createCategories()
  2554. {
  2555. if (empty($this->categories))
  2556. return FALSE;
  2557. $output = null;
  2558. foreach ($this->categories as $category)
  2559. {
  2560. if (empty($category['value']))
  2561. {
  2562. if ($this->getConfig('allowEmpty'))
  2563. $output .= $this->_createElement('CATEGORIES');
  2564. continue;
  2565. }
  2566. $attributes = $this->_createParams($category['params'], array('LANGUAGE'));
  2567. if (is_array($category['value']))
  2568. {
  2569. foreach ($category['value'] as $cix => $categoryPart)
  2570. $category['value'][$cix] = $this->_strrep($categoryPart);
  2571. $content = implode(',', $category['value']);
  2572. }
  2573. else
  2574. $content = $this->_strrep($category['value']);
  2575. $output .= $this->_createElement('CATEGORIES', $attributes, $content);
  2576. }
  2577. return $output;
  2578. }
  2579. /**
  2580. * set calendar component property categories
  2581. *
  2582. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2583. * @since 2.5.1 - 2008-11-06
  2584. * @param mixed $value
  2585. * @param array $params, optional
  2586. * @param integer $index, optional
  2587. * @return bool
  2588. */
  2589. function setCategories($value, $params = FALSE, $index = FALSE)
  2590. {
  2591. if (empty($value))
  2592. if ($this->getConfig('allowEmpty'))
  2593. $value = null;
  2594. else
  2595. return FALSE;
  2596. iCalUtilityFunctions :: _setMval($this->categories, $value, $params, FALSE, $index);
  2597. return TRUE;
  2598. }
  2599. /*********************************************************************************/
  2600. /**
  2601. * Property Name: CLASS
  2602. */
  2603. /**
  2604. * creates formatted output for calendar component property class
  2605. *
  2606. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2607. * @since 0.9.7 - 2006-11-20
  2608. * @return string
  2609. */
  2610. function createClass()
  2611. {
  2612. if (empty($this->class))
  2613. return FALSE;
  2614. if (empty($this->class['value']))
  2615. return ($this->getConfig('allowEmpty')) ? $this->_createElement('CLASS') : FALSE;
  2616. $attributes = $this->_createParams($this->class['params']);
  2617. return $this->_createElement('CLASS', $attributes, $this->class['value']);
  2618. }
  2619. /**
  2620. * set calendar component property class
  2621. *
  2622. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2623. * @since 2.4.8 - 2008-11-04
  2624. * @param string $value "PUBLIC" / "PRIVATE" / "CONFIDENTIAL" / iana-token / x-name
  2625. * @param array $params optional
  2626. * @return bool
  2627. */
  2628. function setClass($value, $params = FALSE)
  2629. {
  2630. if (empty($value))
  2631. if ($this->getConfig('allowEmpty'))
  2632. $value = null;
  2633. else
  2634. return FALSE;
  2635. $this->class = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  2636. return TRUE;
  2637. }
  2638. /*********************************************************************************/
  2639. /**
  2640. * Property Name: COMMENT
  2641. */
  2642. /**
  2643. * creates formatted output for calendar component property comment
  2644. *
  2645. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2646. * @since 2.4.8 - 2008-10-22
  2647. * @return string
  2648. */
  2649. function createComment()
  2650. {
  2651. if (empty($this->comment))
  2652. return FALSE;
  2653. $output = null;
  2654. foreach ($this->comment as $commentPart)
  2655. {
  2656. if (empty($commentPart['value']))
  2657. {
  2658. if ($this->getConfig('allowEmpty'))
  2659. $output .= $this->_createElement('COMMENT');
  2660. continue;
  2661. }
  2662. $attributes = $this->_createParams($commentPart['params'], array('ALTREP', 'LANGUAGE'));
  2663. $content = $this->_strrep($commentPart['value']);
  2664. $output .= $this->_createElement('COMMENT', $attributes, $content);
  2665. }
  2666. return $output;
  2667. }
  2668. /**
  2669. * set calendar component property comment
  2670. *
  2671. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2672. * @since 2.5.1 - 2008-11-06
  2673. * @param string $value
  2674. * @param array $params, optional
  2675. * @param integer $index, optional
  2676. * @return bool
  2677. */
  2678. function setComment($value, $params = FALSE, $index = FALSE)
  2679. {
  2680. if (empty($value))
  2681. if ($this->getConfig('allowEmpty'))
  2682. $value = null;
  2683. else
  2684. return FALSE;
  2685. iCalUtilityFunctions :: _setMval($this->comment, $value, $params, FALSE, $index);
  2686. return TRUE;
  2687. }
  2688. /*********************************************************************************/
  2689. /**
  2690. * Property Name: COMPLETED
  2691. */
  2692. /**
  2693. * creates formatted output for calendar component property completed
  2694. *
  2695. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2696. * @since 2.4.8 - 2008-10-22
  2697. * @return string
  2698. */
  2699. function createCompleted()
  2700. {
  2701. if (empty($this->completed))
  2702. return FALSE;
  2703. 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']))
  2704. if ($this->getConfig('allowEmpty'))
  2705. return $this->_createElement('COMPLETED');
  2706. else
  2707. return FALSE;
  2708. $formatted = iCalUtilityFunctions :: _format_date_time($this->completed['value'], 7);
  2709. $attributes = $this->_createParams($this->completed['params']);
  2710. return $this->_createElement('COMPLETED', $attributes, $formatted);
  2711. }
  2712. /**
  2713. * set calendar component property completed
  2714. *
  2715. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2716. * @since 2.4.8 - 2008-10-23
  2717. * @param mixed $year
  2718. * @param mixed $month optional
  2719. * @param int $day optional
  2720. * @param int $hour optional
  2721. * @param int $min optional
  2722. * @param int $sec optional
  2723. * @param array $params optional
  2724. * @return bool
  2725. */
  2726. function setCompleted($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE)
  2727. {
  2728. if (empty($year))
  2729. {
  2730. if ($this->getConfig('allowEmpty'))
  2731. {
  2732. $this->completed = array('value' => null, 'params' => iCalUtilityFunctions :: _setParams($params));
  2733. return TRUE;
  2734. }
  2735. else
  2736. return FALSE;
  2737. }
  2738. $this->completed = iCalUtilityFunctions :: _setDate2($year, $month, $day, $hour, $min, $sec, $params);
  2739. return TRUE;
  2740. }
  2741. /*********************************************************************************/
  2742. /**
  2743. * Property Name: CONTACT
  2744. */
  2745. /**
  2746. * creates formatted output for calendar component property contact
  2747. *
  2748. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2749. * @since 2.4.8 - 2008-10-23
  2750. * @return string
  2751. */
  2752. function createContact()
  2753. {
  2754. if (empty($this->contact))
  2755. return FALSE;
  2756. $output = null;
  2757. foreach ($this->contact as $contact)
  2758. {
  2759. if (! empty($contact['value']))
  2760. {
  2761. $attributes = $this->_createParams($contact['params'], array('ALTREP', 'LANGUAGE'));
  2762. $content = $this->_strrep($contact['value']);
  2763. $output .= $this->_createElement('CONTACT', $attributes, $content);
  2764. }
  2765. elseif ($this->getConfig('allowEmpty'))
  2766. $output .= $this->_createElement('CONTACT');
  2767. }
  2768. return $output;
  2769. }
  2770. /**
  2771. * set calendar component property contact
  2772. *
  2773. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2774. * @since 2.5.1 - 2008-11-05
  2775. * @param string $value
  2776. * @param array $params, optional
  2777. * @param integer $index, optional
  2778. * @return bool
  2779. */
  2780. function setContact($value, $params = FALSE, $index = FALSE)
  2781. {
  2782. if (empty($value))
  2783. if ($this->getConfig('allowEmpty'))
  2784. $value = null;
  2785. else
  2786. return FALSE;
  2787. iCalUtilityFunctions :: _setMval($this->contact, $value, $params, FALSE, $index);
  2788. return TRUE;
  2789. }
  2790. /*********************************************************************************/
  2791. /**
  2792. * Property Name: CREATED
  2793. */
  2794. /**
  2795. * creates formatted output for calendar component property created
  2796. *
  2797. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2798. * @since 2.4.8 - 2008-10-21
  2799. * @return string
  2800. */
  2801. function createCreated()
  2802. {
  2803. if (empty($this->created))
  2804. return FALSE;
  2805. $formatted = iCalUtilityFunctions :: _format_date_time($this->created['value'], 7);
  2806. $attributes = $this->_createParams($this->created['params']);
  2807. return $this->_createElement('CREATED', $attributes, $formatted);
  2808. }
  2809. /**
  2810. * set calendar component property created
  2811. *
  2812. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2813. * @since 2.4.8 - 2008-10-23
  2814. * @param mixed $year optional
  2815. * @param mixed $month optional
  2816. * @param int $day optional
  2817. * @param int $hour optional
  2818. * @param int $min optional
  2819. * @param int $sec optional
  2820. * @param mixed $params optional
  2821. * @return bool
  2822. */
  2823. function setCreated($year = FALSE, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE)
  2824. {
  2825. if (! isset($year))
  2826. {
  2827. $year = date('Ymd\THis', mktime(date('H'), date('i'), date('s') - date('Z'), date('m'), date('d'), date('Y')));
  2828. }
  2829. $this->created = iCalUtilityFunctions :: _setDate2($year, $month, $day, $hour, $min, $sec, $params);
  2830. return TRUE;
  2831. }
  2832. /*********************************************************************************/
  2833. /**
  2834. * Property Name: DESCRIPTION
  2835. */
  2836. /**
  2837. * creates formatted output for calendar component property description
  2838. *
  2839. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2840. * @since 2.4.8 - 2008-10-22
  2841. * @return string
  2842. */
  2843. function createDescription()
  2844. {
  2845. if (empty($this->description))
  2846. return FALSE;
  2847. $output = null;
  2848. foreach ($this->description as $description)
  2849. {
  2850. if (! empty($description['value']))
  2851. {
  2852. $attributes = $this->_createParams($description['params'], array('ALTREP', 'LANGUAGE'));
  2853. $content = $this->_strrep($description['value']);
  2854. $output .= $this->_createElement('DESCRIPTION', $attributes, $content);
  2855. }
  2856. elseif ($this->getConfig('allowEmpty'))
  2857. $output .= $this->_createElement('DESCRIPTION');
  2858. }
  2859. return $output;
  2860. }
  2861. /**
  2862. * set calendar component property description
  2863. *
  2864. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2865. * @since 2.6.24 - 2010-11-06
  2866. * @param string $value
  2867. * @param array $params, optional
  2868. * @param integer $index, optional
  2869. * @return bool
  2870. */
  2871. function setDescription($value, $params = FALSE, $index = FALSE)
  2872. {
  2873. if (empty($value))
  2874. {
  2875. if ($this->getConfig('allowEmpty'))
  2876. $value = null;
  2877. else
  2878. return FALSE;
  2879. }
  2880. if ('vjournal' != $this->objName)
  2881. $index = 1;
  2882. iCalUtilityFunctions :: _setMval($this->description, $value, $params, FALSE, $index);
  2883. return TRUE;
  2884. }
  2885. /*********************************************************************************/
  2886. /**
  2887. * Property Name: DTEND
  2888. */
  2889. /**
  2890. * creates formatted output for calendar component property dtend
  2891. *
  2892. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2893. * @since 2.9.6 - 2011-05-14
  2894. * @return string
  2895. */
  2896. function createDtend()
  2897. {
  2898. if (empty($this->dtend))
  2899. return FALSE;
  2900. 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']))
  2901. if ($this->getConfig('allowEmpty'))
  2902. return $this->_createElement('DTEND');
  2903. else
  2904. return FALSE;
  2905. $formatted = iCalUtilityFunctions :: _format_date_time($this->dtend['value']);
  2906. if ((FALSE !== ($tzid = $this->getConfig('TZID'))) && (! isset($this->dtend['params']['VALUE']) || ($this->dtend['params']['VALUE'] != 'DATE')) && ! isset($this->dtend['params']['TZID']))
  2907. $this->dtend['params']['TZID'] = $tzid;
  2908. $attributes = $this->_createParams($this->dtend['params']);
  2909. return $this->_createElement('DTEND', $attributes, $formatted);
  2910. }
  2911. /**
  2912. * set calendar component property dtend
  2913. *
  2914. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2915. * @since 2.9.6 - 2011-05-14
  2916. * @param mixed $year
  2917. * @param mixed $month optional
  2918. * @param int $day optional
  2919. * @param int $hour optional
  2920. * @param int $min optional
  2921. * @param int $sec optional
  2922. * @param string $tz optional
  2923. * @param array params optional
  2924. * @return bool
  2925. */
  2926. function setDtend($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE)
  2927. {
  2928. if (empty($year))
  2929. {
  2930. if ($this->getConfig('allowEmpty'))
  2931. {
  2932. $this->dtend = array('value' => null, 'params' => iCalUtilityFunctions :: _setParams($params));
  2933. return TRUE;
  2934. }
  2935. else
  2936. return FALSE;
  2937. }
  2938. $this->dtend = iCalUtilityFunctions :: _setDate($year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig('TZID'));
  2939. return TRUE;
  2940. }
  2941. /*********************************************************************************/
  2942. /**
  2943. * Property Name: DTSTAMP
  2944. */
  2945. /**
  2946. * creates formatted output for calendar component property dtstamp
  2947. *
  2948. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2949. * @since 2.4.4 - 2008-03-07
  2950. * @return string
  2951. */
  2952. function createDtstamp()
  2953. {
  2954. 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']))
  2955. $this->_makeDtstamp();
  2956. $formatted = iCalUtilityFunctions :: _format_date_time($this->dtstamp['value'], 7);
  2957. $attributes = $this->_createParams($this->dtstamp['params']);
  2958. return $this->_createElement('DTSTAMP', $attributes, $formatted);
  2959. }
  2960. /**
  2961. * computes datestamp for calendar component object instance dtstamp
  2962. *
  2963. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2964. * @since 2.6.25 - 2010-11-09
  2965. * @return void
  2966. */
  2967. function _makeDtstamp()
  2968. {
  2969. $d = mktime(date('H'), date('m'), (date('s') - date('Z')), date('m'), date('d'), date('Y'));
  2970. $this->dtstamp['value'] = array('year' => date('Y', $d), 'month' => date('m', $d), 'day' => date('d', $d),
  2971. 'hour' => date('H', $d), 'min' => date('i', $d), 'sec' => date('s', $d));
  2972. $this->dtstamp['params'] = null;
  2973. }
  2974. /**
  2975. * set calendar component property dtstamp
  2976. *
  2977. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  2978. * @since 2.4.8 - 2008-10-23
  2979. * @param mixed $year
  2980. * @param mixed $month optional
  2981. * @param int $day optional
  2982. * @param int $hour optional
  2983. * @param int $min optional
  2984. * @param int $sec optional
  2985. * @param array $params optional
  2986. * @return TRUE
  2987. */
  2988. function setDtstamp($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE)
  2989. {
  2990. if (empty($year))
  2991. $this->_makeDtstamp();
  2992. else
  2993. $this->dtstamp = iCalUtilityFunctions :: _setDate2($year, $month, $day, $hour, $min, $sec, $params);
  2994. return TRUE;
  2995. }
  2996. /*********************************************************************************/
  2997. /**
  2998. * Property Name: DTSTART
  2999. */
  3000. /**
  3001. * creates formatted output for calendar component property dtstart
  3002. *
  3003. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3004. * @since 2.9.6 - 2011-05-15
  3005. * @return string
  3006. */
  3007. function createDtstart()
  3008. {
  3009. if (empty($this->dtstart))
  3010. return FALSE;
  3011. 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']))
  3012. {
  3013. if ($this->getConfig('allowEmpty'))
  3014. return $this->_createElement('DTSTART');
  3015. else
  3016. return FALSE;
  3017. }
  3018. if (in_array($this->objName, array('vtimezone', 'standard', 'daylight')))
  3019. unset($this->dtstart['value']['tz'], $this->dtstart['params']['TZID']);
  3020. elseif ((FALSE !== ($tzid = $this->getConfig('TZID'))) && (! isset($this->dtstart['params']['VALUE']) || ($this->dtstart['params']['VALUE'] != 'DATE')) && ! isset($this->dtstart['params']['TZID']))
  3021. $this->dtstart['params']['TZID'] = $tzid;
  3022. $formatted = iCalUtilityFunctions :: _format_date_time($this->dtstart['value']);
  3023. $attributes = $this->_createParams($this->dtstart['params']);
  3024. return $this->_createElement('DTSTART', $attributes, $formatted);
  3025. }
  3026. /**
  3027. * set calendar component property dtstart
  3028. *
  3029. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3030. * @since 2.6.22 - 2010-09-22
  3031. * @param mixed $year
  3032. * @param mixed $month optional
  3033. * @param int $day optional
  3034. * @param int $hour optional
  3035. * @param int $min optional
  3036. * @param int $sec optional
  3037. * @param string $tz optional
  3038. * @param array $params optional
  3039. * @return bool
  3040. */
  3041. function setDtstart($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE)
  3042. {
  3043. if (empty($year))
  3044. {
  3045. if ($this->getConfig('allowEmpty'))
  3046. {
  3047. $this->dtstart = array('value' => null, 'params' => iCalUtilityFunctions :: _setParams($params));
  3048. return TRUE;
  3049. }
  3050. else
  3051. return FALSE;
  3052. }
  3053. $this->dtstart = iCalUtilityFunctions :: _setDate($year, $month, $day, $hour, $min, $sec, $tz, $params, 'dtstart', $this->objName, $this->getConfig('TZID'));
  3054. return TRUE;
  3055. }
  3056. /*********************************************************************************/
  3057. /**
  3058. * Property Name: DUE
  3059. */
  3060. /**
  3061. * creates formatted output for calendar component property due
  3062. *
  3063. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3064. * @since 2.4.8 - 2008-10-22
  3065. * @return string
  3066. */
  3067. function createDue()
  3068. {
  3069. if (empty($this->due))
  3070. return FALSE;
  3071. 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']))
  3072. {
  3073. if ($this->getConfig('allowEmpty'))
  3074. return $this->_createElement('DUE');
  3075. else
  3076. return FALSE;
  3077. }
  3078. $formatted = iCalUtilityFunctions :: _format_date_time($this->due['value']);
  3079. if ((FALSE !== ($tzid = $this->getConfig('TZID'))) && (! isset($this->due['params']['VALUE']) || ($this->due['params']['VALUE'] != 'DATE')) && ! isset($this->due['params']['TZID']))
  3080. $this->due['params']['TZID'] = $tzid;
  3081. $attributes = $this->_createParams($this->due['params']);
  3082. return $this->_createElement('DUE', $attributes, $formatted);
  3083. }
  3084. /**
  3085. * set calendar component property due
  3086. *
  3087. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3088. * @since 2.4.8 - 2008-11-04
  3089. * @param mixed $year
  3090. * @param mixed $month optional
  3091. * @param int $day optional
  3092. * @param int $hour optional
  3093. * @param int $min optional
  3094. * @param int $sec optional
  3095. * @param array $params optional
  3096. * @return bool
  3097. */
  3098. function setDue($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE)
  3099. {
  3100. if (empty($year))
  3101. {
  3102. if ($this->getConfig('allowEmpty'))
  3103. {
  3104. $this->due = array('value' => null, 'params' => iCalUtilityFunctions :: _setParams($params));
  3105. return TRUE;
  3106. }
  3107. else
  3108. return FALSE;
  3109. }
  3110. $this->due = iCalUtilityFunctions :: _setDate($year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig('TZID'));
  3111. return TRUE;
  3112. }
  3113. /*********************************************************************************/
  3114. /**
  3115. * Property Name: DURATION
  3116. */
  3117. /**
  3118. * creates formatted output for calendar component property duration
  3119. *
  3120. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3121. * @since 2.4.8 - 2008-10-21
  3122. * @return string
  3123. */
  3124. function createDuration()
  3125. {
  3126. if (empty($this->duration))
  3127. return FALSE;
  3128. 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']))
  3129. if ($this->getConfig('allowEmpty'))
  3130. return $this->_createElement('DURATION', array(), null);
  3131. else
  3132. return FALSE;
  3133. $attributes = $this->_createParams($this->duration['params']);
  3134. return $this->_createElement('DURATION', $attributes, iCalUtilityFunctions :: _format_duration($this->duration['value']));
  3135. }
  3136. /**
  3137. * set calendar component property duration
  3138. *
  3139. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3140. * @since 2.4.8 - 2008-11-04
  3141. * @param mixed $week
  3142. * @param mixed $day optional
  3143. * @param int $hour optional
  3144. * @param int $min optional
  3145. * @param int $sec optional
  3146. * @param array $params optional
  3147. * @return bool
  3148. */
  3149. function setDuration($week, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE)
  3150. {
  3151. if (empty($week))
  3152. if ($this->getConfig('allowEmpty'))
  3153. $week = null;
  3154. else
  3155. return FALSE;
  3156. if (is_array($week) && (1 <= count($week)))
  3157. $this->duration = array('value' => iCalUtilityFunctions :: _duration_array($week),
  3158. 'params' => iCalUtilityFunctions :: _setParams($day));
  3159. elseif (is_string($week) && (3 <= strlen(trim($week))))
  3160. {
  3161. $week = trim($week);
  3162. if (in_array(substr($week, 0, 1), array('+', '-')))
  3163. $week = substr($week, 1);
  3164. $this->duration = array('value' => iCalUtilityFunctions :: _duration_string($week),
  3165. 'params' => iCalUtilityFunctions :: _setParams($day));
  3166. }
  3167. elseif (empty($week) && empty($day) && empty($hour) && empty($min) && empty($sec))
  3168. return FALSE;
  3169. else
  3170. $this->duration = array(
  3171. 'value' => iCalUtilityFunctions :: _duration_array(array($week, $day, $hour, $min, $sec)),
  3172. 'params' => iCalUtilityFunctions :: _setParams($params));
  3173. return TRUE;
  3174. }
  3175. /*********************************************************************************/
  3176. /**
  3177. * Property Name: EXDATE
  3178. */
  3179. /**
  3180. * creates formatted output for calendar component property exdate
  3181. *
  3182. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3183. * @since 2.4.8 - 2008-10-22
  3184. * @return string
  3185. */
  3186. function createExdate()
  3187. {
  3188. if (empty($this->exdate))
  3189. return FALSE;
  3190. $output = null;
  3191. foreach ($this->exdate as $ex => $theExdate)
  3192. {
  3193. if (empty($theExdate['value']))
  3194. {
  3195. if ($this->getConfig('allowEmpty'))
  3196. $output .= $this->_createElement('EXDATE');
  3197. continue;
  3198. }
  3199. $content = $attributes = null;
  3200. foreach ($theExdate['value'] as $eix => $exdatePart)
  3201. {
  3202. $parno = count($exdatePart);
  3203. $formatted = iCalUtilityFunctions :: _format_date_time($exdatePart, $parno);
  3204. if (isset($theExdate['params']['TZID']))
  3205. $formatted = str_replace('Z', '', $formatted);
  3206. if (0 < $eix)
  3207. {
  3208. if (isset($theExdate['value'][0]['tz']))
  3209. {
  3210. if (ctype_digit(substr($theExdate['value'][0]['tz'], - 4)) || ('Z' == $theExdate['value'][0]['tz']))
  3211. {
  3212. if ('Z' != substr($formatted, - 1))
  3213. $formatted .= 'Z';
  3214. }
  3215. else
  3216. $formatted = str_replace('Z', '', $formatted);
  3217. }
  3218. else
  3219. $formatted = str_replace('Z', '', $formatted);
  3220. }
  3221. $content .= (0 < $eix) ? ',' . $formatted : $formatted;
  3222. }
  3223. $attributes .= $this->_createParams($theExdate['params']);
  3224. $output .= $this->_createElement('EXDATE', $attributes, $content);
  3225. }
  3226. return $output;
  3227. }
  3228. /**
  3229. * set calendar component property exdate
  3230. *
  3231. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3232. * @since 2.5.1 - 2008-11-05
  3233. * @param array exdates
  3234. * @param array $params, optional
  3235. * @param integer $index, optional
  3236. * @return bool
  3237. */
  3238. function setExdate($exdates, $params = FALSE, $index = FALSE)
  3239. {
  3240. if (empty($exdates))
  3241. {
  3242. if ($this->getConfig('allowEmpty'))
  3243. {
  3244. iCalUtilityFunctions :: _setMval($this->exdate, null, $params, FALSE, $index);
  3245. return TRUE;
  3246. }
  3247. else
  3248. return FALSE;
  3249. }
  3250. $input = array('params' => iCalUtilityFunctions :: _setParams($params, array('VALUE' => 'DATE-TIME')));
  3251. /* ev. check 1:st date and save ev. timezone **/
  3252. iCalUtilityFunctions :: _chkdatecfg(reset($exdates), $parno, $input['params']);
  3253. iCalUtilityFunctions :: _existRem($input['params'], 'VALUE', 'DATE-TIME'); // remove default parameter
  3254. foreach ($exdates as $eix => $theExdate)
  3255. {
  3256. if (iCalUtilityFunctions :: _isArrayTimestampDate($theExdate))
  3257. $exdatea = iCalUtilityFunctions :: _timestamp2date($theExdate, $parno);
  3258. elseif (is_array($theExdate))
  3259. $exdatea = iCalUtilityFunctions :: _date_time_array($theExdate, $parno);
  3260. elseif (8 <= strlen(trim($theExdate))) // ex. 2006-08-03 10:12:18
  3261. $exdatea = iCalUtilityFunctions :: _date_time_string($theExdate, $parno);
  3262. if (3 == $parno)
  3263. unset($exdatea['hour'], $exdatea['min'], $exdatea['sec'], $exdatea['tz']);
  3264. elseif (isset($exdatea['tz']))
  3265. $exdatea['tz'] = (string) $exdatea['tz'];
  3266. if (isset($input['params']['TZID']) || (isset($exdatea['tz']) && ! iCalUtilityFunctions :: _isOffset($exdatea['tz'])) || (isset($input['value'][0]) && (! isset($input['value'][0]['tz']))) || (isset($input['value'][0]['tz']) && ! iCalUtilityFunctions :: _isOffset($input['value'][0]['tz'])))
  3267. unset($exdatea['tz']);
  3268. $input['value'][] = $exdatea;
  3269. }
  3270. if (0 >= count($input['value']))
  3271. return FALSE;
  3272. if (3 == $parno)
  3273. {
  3274. $input['params']['VALUE'] = 'DATE';
  3275. unset($input['params']['TZID']);
  3276. }
  3277. iCalUtilityFunctions :: _setMval($this->exdate, $input['value'], $input['params'], FALSE, $index);
  3278. return TRUE;
  3279. }
  3280. /*********************************************************************************/
  3281. /**
  3282. * Property Name: EXRULE
  3283. */
  3284. /**
  3285. * creates formatted output for calendar component property exrule
  3286. *
  3287. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3288. * @since 2.4.8 - 2008-10-22
  3289. * @return string
  3290. */
  3291. function createExrule()
  3292. {
  3293. if (empty($this->exrule))
  3294. return FALSE;
  3295. return $this->_format_recur('EXRULE', $this->exrule);
  3296. }
  3297. /**
  3298. * set calendar component property exdate
  3299. *
  3300. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3301. * @since 2.5.1 - 2008-11-05
  3302. * @param array $exruleset
  3303. * @param array $params, optional
  3304. * @param integer $index, optional
  3305. * @return bool
  3306. */
  3307. function setExrule($exruleset, $params = FALSE, $index = FALSE)
  3308. {
  3309. if (empty($exruleset))
  3310. if ($this->getConfig('allowEmpty'))
  3311. $exruleset = null;
  3312. else
  3313. return FALSE;
  3314. iCalUtilityFunctions :: _setMval($this->exrule, iCalUtilityFunctions :: _setRexrule($exruleset), $params, FALSE, $index);
  3315. return TRUE;
  3316. }
  3317. /*********************************************************************************/
  3318. /**
  3319. * Property Name: FREEBUSY
  3320. */
  3321. /**
  3322. * creates formatted output for calendar component property freebusy
  3323. *
  3324. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3325. * @since 2.4.8 - 2008-10-22
  3326. * @return string
  3327. */
  3328. function createFreebusy()
  3329. {
  3330. if (empty($this->freebusy))
  3331. return FALSE;
  3332. $output = null;
  3333. foreach ($this->freebusy as $freebusyPart)
  3334. {
  3335. if (empty($freebusyPart['value']))
  3336. {
  3337. if ($this->getConfig('allowEmpty'))
  3338. $output .= $this->_createElement('FREEBUSY');
  3339. continue;
  3340. }
  3341. $attributes = $content = null;
  3342. if (isset($freebusyPart['value']['fbtype']))
  3343. {
  3344. $attributes .= $this->intAttrDelimiter . 'FBTYPE=' . $freebusyPart['value']['fbtype'];
  3345. unset($freebusyPart['value']['fbtype']);
  3346. $freebusyPart['value'] = array_values($freebusyPart['value']);
  3347. }
  3348. else
  3349. $attributes .= $this->intAttrDelimiter . 'FBTYPE=BUSY';
  3350. $attributes .= $this->_createParams($freebusyPart['params']);
  3351. $fno = 1;
  3352. $cnt = count($freebusyPart['value']);
  3353. foreach ($freebusyPart['value'] as $periodix => $freebusyPeriod)
  3354. {
  3355. $formatted = iCalUtilityFunctions :: _format_date_time($freebusyPeriod[0]);
  3356. $content .= $formatted;
  3357. $content .= '/';
  3358. $cnt2 = count($freebusyPeriod[1]);
  3359. if (array_key_exists('year', $freebusyPeriod[1])) // date-time
  3360. $cnt2 = 7;
  3361. elseif (array_key_exists('week', $freebusyPeriod[1])) // duration
  3362. $cnt2 = 5;
  3363. if ((7 == $cnt2) && // period= -> date-time
  3364. isset($freebusyPeriod[1]['year']) && isset($freebusyPeriod[1]['month']) && isset($freebusyPeriod[1]['day']))
  3365. {
  3366. $content .= iCalUtilityFunctions :: _format_date_time($freebusyPeriod[1]);
  3367. }
  3368. else
  3369. { // period= -> dur-time
  3370. $content .= iCalUtilityFunctions :: _format_duration($freebusyPeriod[1]);
  3371. }
  3372. if ($fno < $cnt)
  3373. $content .= ',';
  3374. $fno ++;
  3375. }
  3376. $output .= $this->_createElement('FREEBUSY', $attributes, $content);
  3377. }
  3378. return $output;
  3379. }
  3380. /**
  3381. * set calendar component property freebusy
  3382. *
  3383. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3384. * @since 2.8.10 - 2011-03-24
  3385. * @param string $fbType
  3386. * @param array $fbValues
  3387. * @param array $params, optional
  3388. * @param integer $index, optional
  3389. * @return bool
  3390. */
  3391. function setFreebusy($fbType, $fbValues, $params = FALSE, $index = FALSE)
  3392. {
  3393. if (empty($fbValues))
  3394. {
  3395. if ($this->getConfig('allowEmpty'))
  3396. {
  3397. iCalUtilityFunctions :: _setMval($this->freebusy, null, $params, FALSE, $index);
  3398. return TRUE;
  3399. }
  3400. else
  3401. return FALSE;
  3402. }
  3403. $fbType = strtoupper($fbType);
  3404. if ((! in_array($fbType, array('FREE', 'BUSY', 'BUSY-UNAVAILABLE', 'BUSY-TENTATIVE'))) && ('X-' != substr($fbType, 0, 2)))
  3405. $fbType = 'BUSY';
  3406. $input = array('fbtype' => $fbType);
  3407. foreach ($fbValues as $fbPeriod)
  3408. { // periods => period
  3409. if (empty($fbPeriod))
  3410. continue;
  3411. $freebusyPeriod = array();
  3412. foreach ($fbPeriod as $fbMember)
  3413. { // pairs => singlepart
  3414. $freebusyPairMember = array();
  3415. if (is_array($fbMember))
  3416. {
  3417. if (iCalUtilityFunctions :: _isArrayDate($fbMember))
  3418. { // date-time value
  3419. $freebusyPairMember = iCalUtilityFunctions :: _date_time_array($fbMember, 7);
  3420. $freebusyPairMember['tz'] = 'Z';
  3421. }
  3422. elseif (iCalUtilityFunctions :: _isArrayTimestampDate($fbMember))
  3423. { // timestamp value
  3424. $freebusyPairMember = iCalUtilityFunctions :: _timestamp2date($fbMember['timestamp'], 7);
  3425. $freebusyPairMember['tz'] = 'Z';
  3426. }
  3427. else
  3428. { // array format duration
  3429. $freebusyPairMember = iCalUtilityFunctions :: _duration_array($fbMember);
  3430. }
  3431. }
  3432. elseif ((3 <= strlen(trim($fbMember))) && // string format duration
  3433. (in_array($fbMember{0}, array('P', '+', '-'))))
  3434. {
  3435. if ('P' != $fbMember{0})
  3436. $fbmember = substr($fbMember, 1);
  3437. $freebusyPairMember = iCalUtilityFunctions :: _duration_string($fbMember);
  3438. }
  3439. elseif (8 <= strlen(trim($fbMember)))
  3440. { // text date ex. 2006-08-03 10:12:18
  3441. $freebusyPairMember = iCalUtilityFunctions :: _date_time_string($fbMember, 7);
  3442. $freebusyPairMember['tz'] = 'Z';
  3443. }
  3444. $freebusyPeriod[] = $freebusyPairMember;
  3445. }
  3446. $input[] = $freebusyPeriod;
  3447. }
  3448. iCalUtilityFunctions :: _setMval($this->freebusy, $input, $params, FALSE, $index);
  3449. return TRUE;
  3450. }
  3451. /*********************************************************************************/
  3452. /**
  3453. * Property Name: GEO
  3454. */
  3455. /**
  3456. * creates formatted output for calendar component property geo
  3457. *
  3458. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3459. * @since 2.4.8 - 2008-10-21
  3460. * @return string
  3461. */
  3462. function createGeo()
  3463. {
  3464. if (empty($this->geo))
  3465. return FALSE;
  3466. if (empty($this->geo['value']))
  3467. return ($this->getConfig('allowEmpty')) ? $this->_createElement('GEO') : FALSE;
  3468. $attributes = $this->_createParams($this->geo['params']);
  3469. $content = null;
  3470. $content .= number_format((float) $this->geo['value']['latitude'], 6, '.', '');
  3471. $content .= ';';
  3472. $content .= number_format((float) $this->geo['value']['longitude'], 6, '.', '');
  3473. return $this->_createElement('GEO', $attributes, $content);
  3474. }
  3475. /**
  3476. * set calendar component property geo
  3477. *
  3478. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3479. * @since 2.4.8 - 2008-11-04
  3480. * @param float $latitude
  3481. * @param float $longitude
  3482. * @param array $params optional
  3483. * @return bool
  3484. */
  3485. function setGeo($latitude, $longitude, $params = FALSE)
  3486. {
  3487. if (! empty($latitude) && ! empty($longitude))
  3488. {
  3489. if (! is_array($this->geo))
  3490. $this->geo = array();
  3491. $this->geo['value']['latitude'] = $latitude;
  3492. $this->geo['value']['longitude'] = $longitude;
  3493. $this->geo['params'] = iCalUtilityFunctions :: _setParams($params);
  3494. }
  3495. elseif ($this->getConfig('allowEmpty'))
  3496. $this->geo = array('value' => null, 'params' => iCalUtilityFunctions :: _setParams($params));
  3497. else
  3498. return FALSE;
  3499. return TRUE;
  3500. }
  3501. /*********************************************************************************/
  3502. /**
  3503. * Property Name: LAST-MODIFIED
  3504. */
  3505. /**
  3506. * creates formatted output for calendar component property last-modified
  3507. *
  3508. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3509. * @since 2.4.8 - 2008-10-21
  3510. * @return string
  3511. */
  3512. function createLastModified()
  3513. {
  3514. if (empty($this->lastmodified))
  3515. return FALSE;
  3516. $attributes = $this->_createParams($this->lastmodified['params']);
  3517. $formatted = iCalUtilityFunctions :: _format_date_time($this->lastmodified['value'], 7);
  3518. return $this->_createElement('LAST-MODIFIED', $attributes, $formatted);
  3519. }
  3520. /**
  3521. * set calendar component property completed
  3522. *
  3523. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3524. * @since 2.4.8 - 2008-10-23
  3525. * @param mixed $year optional
  3526. * @param mixed $month optional
  3527. * @param int $day optional
  3528. * @param int $hour optional
  3529. * @param int $min optional
  3530. * @param int $sec optional
  3531. * @param array $params optional
  3532. * @return boll
  3533. */
  3534. function setLastModified($year = FALSE, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $params = FALSE)
  3535. {
  3536. if (empty($year))
  3537. $year = date('Ymd\THis', mktime(date('H'), date('i'), date('s') - date('Z'), date('m'), date('d'), date('Y')));
  3538. $this->lastmodified = iCalUtilityFunctions :: _setDate2($year, $month, $day, $hour, $min, $sec, $params);
  3539. return TRUE;
  3540. }
  3541. /*********************************************************************************/
  3542. /**
  3543. * Property Name: LOCATION
  3544. */
  3545. /**
  3546. * creates formatted output for calendar component property location
  3547. *
  3548. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3549. * @since 2.4.8 - 2008-10-22
  3550. * @return string
  3551. */
  3552. function createLocation()
  3553. {
  3554. if (empty($this->location))
  3555. return FALSE;
  3556. if (empty($this->location['value']))
  3557. return ($this->getConfig('allowEmpty')) ? $this->_createElement('LOCATION') : FALSE;
  3558. $attributes = $this->_createParams($this->location['params'], array('ALTREP', 'LANGUAGE'));
  3559. $content = $this->_strrep($this->location['value']);
  3560. return $this->_createElement('LOCATION', $attributes, $content);
  3561. }
  3562. /**
  3563. * set calendar component property location
  3564. '
  3565. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3566. * @since 2.4.8 - 2008-11-04
  3567. * @param string $value
  3568. * @param array params optional
  3569. * @return bool
  3570. */
  3571. function setLocation($value, $params = FALSE)
  3572. {
  3573. if (empty($value))
  3574. if ($this->getConfig('allowEmpty'))
  3575. $value = null;
  3576. else
  3577. return FALSE;
  3578. $this->location = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  3579. return TRUE;
  3580. }
  3581. /*********************************************************************************/
  3582. /**
  3583. * Property Name: ORGANIZER
  3584. */
  3585. /**
  3586. * creates formatted output for calendar component property organizer
  3587. *
  3588. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3589. * @since 2.6.33 - 2010-12-17
  3590. * @return string
  3591. */
  3592. function createOrganizer()
  3593. {
  3594. if (empty($this->organizer))
  3595. return FALSE;
  3596. if (empty($this->organizer['value']))
  3597. return ($this->getConfig('allowEmpty')) ? $this->_createElement('ORGANIZER') : FALSE;
  3598. $attributes = $this->_createParams($this->organizer['params'], array('CN', 'DIR', 'SENT-BY', 'LANGUAGE'));
  3599. return $this->_createElement('ORGANIZER', $attributes, $this->organizer['value']);
  3600. }
  3601. /**
  3602. * set calendar component property organizer
  3603. *
  3604. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3605. * @since 2.6.27 - 2010-11-29
  3606. * @param string $value
  3607. * @param array params optional
  3608. * @return bool
  3609. */
  3610. function setOrganizer($value, $params = FALSE)
  3611. {
  3612. if (empty($value))
  3613. if ($this->getConfig('allowEmpty'))
  3614. $value = null;
  3615. else
  3616. return FALSE;
  3617. if (FALSE === ($pos = strpos(substr($value, 0, 9), ':')))
  3618. $value = 'MAILTO:' . $value;
  3619. else
  3620. $value = strtolower(substr($value, 0, $pos)) . substr($value, $pos);
  3621. $value = str_replace('mailto:', 'MAILTO:', $value);
  3622. $this->organizer = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  3623. if (isset($this->organizer['params']['SENT-BY']))
  3624. {
  3625. if ('mailto:' !== strtolower(substr($this->organizer['params']['SENT-BY'], 0, 7)))
  3626. $this->organizer['params']['SENT-BY'] = 'MAILTO:' . $this->organizer['params']['SENT-BY'];
  3627. else
  3628. $this->organizer['params']['SENT-BY'] = 'MAILTO:' . substr($this->organizer['params']['SENT-BY'], 7);
  3629. }
  3630. return TRUE;
  3631. }
  3632. /*********************************************************************************/
  3633. /**
  3634. * Property Name: PERCENT-COMPLETE
  3635. */
  3636. /**
  3637. * creates formatted output for calendar component property percent-complete
  3638. *
  3639. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3640. * @since 2.9.3 - 2011-05-14
  3641. * @return string
  3642. */
  3643. function createPercentComplete()
  3644. {
  3645. if (! isset($this->percentcomplete) || (empty($this->percentcomplete) && ! is_numeric($this->percentcomplete)))
  3646. return FALSE;
  3647. if (! isset($this->percentcomplete['value']) || (empty($this->percentcomplete['value']) && ! is_numeric($this->percentcomplete['value'])))
  3648. return ($this->getConfig('allowEmpty')) ? $this->_createElement('PERCENT-COMPLETE') : FALSE;
  3649. $attributes = $this->_createParams($this->percentcomplete['params']);
  3650. return $this->_createElement('PERCENT-COMPLETE', $attributes, $this->percentcomplete['value']);
  3651. }
  3652. /**
  3653. * set calendar component property percent-complete
  3654. *
  3655. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3656. * @since 2.9.3 - 2011-05-14
  3657. * @param int $value
  3658. * @param array $params optional
  3659. * @return bool
  3660. */
  3661. function setPercentComplete($value, $params = FALSE)
  3662. {
  3663. if (empty($value) && ! is_numeric($value))
  3664. if ($this->getConfig('allowEmpty'))
  3665. $value = null;
  3666. else
  3667. return FALSE;
  3668. $this->percentcomplete = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  3669. return TRUE;
  3670. }
  3671. /*********************************************************************************/
  3672. /**
  3673. * Property Name: PRIORITY
  3674. */
  3675. /**
  3676. * creates formatted output for calendar component property priority
  3677. *
  3678. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3679. * @since 2.9.3 - 2011-05-14
  3680. * @return string
  3681. */
  3682. function createPriority()
  3683. {
  3684. if (! isset($this->priority) || (empty($this->priority) && ! is_numeric($this->priority)))
  3685. return FALSE;
  3686. if (! isset($this->priority['value']) || (empty($this->priority['value']) && ! is_numeric($this->priority['value'])))
  3687. return ($this->getConfig('allowEmpty')) ? $this->_createElement('PRIORITY') : FALSE;
  3688. $attributes = $this->_createParams($this->priority['params']);
  3689. return $this->_createElement('PRIORITY', $attributes, $this->priority['value']);
  3690. }
  3691. /**
  3692. * set calendar component property priority
  3693. *
  3694. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3695. * @since 2.9.3 - 2011-05-14
  3696. * @param int $value
  3697. * @param array $params optional
  3698. * @return bool
  3699. */
  3700. function setPriority($value, $params = FALSE)
  3701. {
  3702. if (empty($value) && ! is_numeric($value))
  3703. if ($this->getConfig('allowEmpty'))
  3704. $value = null;
  3705. else
  3706. return FALSE;
  3707. $this->priority = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  3708. return TRUE;
  3709. }
  3710. /*********************************************************************************/
  3711. /**
  3712. * Property Name: RDATE
  3713. */
  3714. /**
  3715. * creates formatted output for calendar component property rdate
  3716. *
  3717. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3718. * @since 2.4.16 - 2008-10-26
  3719. * @return string
  3720. */
  3721. function createRdate()
  3722. {
  3723. if (empty($this->rdate))
  3724. return FALSE;
  3725. $utctime = (in_array($this->objName, array('vtimezone', 'standard', 'daylight'))) ? TRUE : FALSE;
  3726. $output = null;
  3727. if ($utctime)
  3728. unset($this->rdate['params']['TZID']);
  3729. foreach ($this->rdate as $theRdate)
  3730. {
  3731. if (empty($theRdate['value']))
  3732. {
  3733. if ($this->getConfig('allowEmpty'))
  3734. $output .= $this->_createElement('RDATE');
  3735. continue;
  3736. }
  3737. if ($utctime)
  3738. unset($theRdate['params']['TZID']);
  3739. $attributes = $this->_createParams($theRdate['params']);
  3740. $cnt = count($theRdate['value']);
  3741. $content = null;
  3742. $rno = 1;
  3743. foreach ($theRdate['value'] as $rpix => $rdatePart)
  3744. {
  3745. $contentPart = null;
  3746. if (is_array($rdatePart) && isset($theRdate['params']['VALUE']) && ('PERIOD' == $theRdate['params']['VALUE']))
  3747. { // PERIOD
  3748. if ($utctime)
  3749. unset($rdatePart[0]['tz']);
  3750. $formatted = iCalUtilityFunctions :: _format_date_time($rdatePart[0]); // PERIOD part 1
  3751. if ($utctime || ! empty($theRdate['params']['TZID']))
  3752. $formatted = str_replace('Z', '', $formatted);
  3753. if (0 < $rpix)
  3754. {
  3755. if (! empty($rdatePart[0]['tz']) && iCalUtilityFunctions :: _isOffset($rdatePart[0]['tz']))
  3756. {
  3757. if ('Z' != substr($formatted, - 1))
  3758. $formatted .= 'Z';
  3759. }
  3760. else
  3761. $formatted = str_replace('Z', '', $formatted);
  3762. }
  3763. $contentPart .= $formatted;
  3764. $contentPart .= '/';
  3765. $cnt2 = count($rdatePart[1]);
  3766. if (array_key_exists('year', $rdatePart[1]))
  3767. {
  3768. if (array_key_exists('hour', $rdatePart[1]))
  3769. $cnt2 = 7; // date-time
  3770. else
  3771. $cnt2 = 3; // date
  3772. }
  3773. elseif (array_key_exists('week', $rdatePart[1])) // duration
  3774. $cnt2 = 5;
  3775. if ((7 == $cnt2) && // period= -> date-time
  3776. isset($rdatePart[1]['year']) && isset($rdatePart[1]['month']) && isset($rdatePart[1]['day']))
  3777. {
  3778. if ($utctime)
  3779. unset($rdatePart[1]['tz']);
  3780. $formatted = iCalUtilityFunctions :: _format_date_time($rdatePart[1]); // PERIOD part 2
  3781. if ($utctime || ! empty($theRdate['params']['TZID']))
  3782. $formatted = str_replace('Z', '', $formatted);
  3783. if (! empty($rdatePart[0]['tz']) && iCalUtilityFunctions :: _isOffset($rdatePart[0]['tz']))
  3784. {
  3785. if ('Z' != substr($formatted, - 1))
  3786. $formatted .= 'Z';
  3787. }
  3788. else
  3789. $formatted = str_replace('Z', '', $formatted);
  3790. $contentPart .= $formatted;
  3791. }
  3792. else
  3793. { // period= -> dur-time
  3794. $contentPart .= iCalUtilityFunctions :: _format_duration($rdatePart[1]);
  3795. }
  3796. } // PERIOD end
  3797. else
  3798. { // SINGLE date start
  3799. if ($utctime)
  3800. unset($rdatePart['tz']);
  3801. $formatted = iCalUtilityFunctions :: _format_date_time($rdatePart);
  3802. if ($utctime || ! empty($theRdate['params']['TZID']))
  3803. $formatted = str_replace('Z', '', $formatted);
  3804. if (! $utctime && (0 < $rpix))
  3805. {
  3806. if (! empty($theRdate['value'][0]['tz']) && iCalUtilityFunctions :: _isOffset($theRdate['value'][0]['tz']))
  3807. {
  3808. if ('Z' != substr($formatted, - 1))
  3809. $formatted .= 'Z';
  3810. }
  3811. else
  3812. $formatted = str_replace('Z', '', $formatted);
  3813. }
  3814. $contentPart .= $formatted;
  3815. }
  3816. $content .= $contentPart;
  3817. if ($rno < $cnt)
  3818. $content .= ',';
  3819. $rno ++;
  3820. }
  3821. $output .= $this->_createElement('RDATE', $attributes, $content);
  3822. }
  3823. return $output;
  3824. }
  3825. /**
  3826. * set calendar component property rdate
  3827. *
  3828. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3829. * @since 2.5.1 - 2008-11-07
  3830. * @param array $rdates
  3831. * @param array $params, optional
  3832. * @param integer $index, optional
  3833. * @return bool
  3834. */
  3835. function setRdate($rdates, $params = FALSE, $index = FALSE)
  3836. {
  3837. if (empty($rdates))
  3838. {
  3839. if ($this->getConfig('allowEmpty'))
  3840. {
  3841. iCalUtilityFunctions :: _setMval($this->rdate, null, $params, FALSE, $index);
  3842. return TRUE;
  3843. }
  3844. else
  3845. return FALSE;
  3846. }
  3847. $input = array('params' => iCalUtilityFunctions :: _setParams($params, array('VALUE' => 'DATE-TIME')));
  3848. if (in_array($this->objName, array('vtimezone', 'standard', 'daylight')))
  3849. {
  3850. unset($input['params']['TZID']);
  3851. $input['params']['VALUE'] = 'DATE-TIME';
  3852. }
  3853. /* check if PERIOD, if not set */
  3854. 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']) || iCalUtilityFunctions :: _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]))))))
  3855. $input['params']['VALUE'] = 'PERIOD';
  3856. /* check 1:st date, upd. $parno (opt) and save ev. timezone **/
  3857. $date = reset($rdates);
  3858. if (isset($input['params']['VALUE']) && ('PERIOD' == $input['params']['VALUE'])) // PERIOD
  3859. $date = reset($date);
  3860. iCalUtilityFunctions :: _chkdatecfg($date, $parno, $input['params']);
  3861. if (in_array($this->objName, array('vtimezone', 'standard', 'daylight')))
  3862. unset($input['params']['TZID']);
  3863. iCalUtilityFunctions :: _existRem($input['params'], 'VALUE', 'DATE-TIME'); // remove default
  3864. foreach ($rdates as $rpix => $theRdate)
  3865. {
  3866. $inputa = null;
  3867. if (is_array($theRdate))
  3868. {
  3869. if (isset($input['params']['VALUE']) && ('PERIOD' == $input['params']['VALUE']))
  3870. { // PERIOD
  3871. foreach ($theRdate as $rix => $rPeriod)
  3872. {
  3873. if (is_array($rPeriod))
  3874. {
  3875. if (iCalUtilityFunctions :: _isArrayTimestampDate($rPeriod)) // timestamp
  3876. $inputab = (isset($rPeriod['tz'])) ? iCalUtilityFunctions :: _timestamp2date($rPeriod, $parno) : iCalUtilityFunctions :: _timestamp2date($rPeriod, 6);
  3877. elseif (iCalUtilityFunctions :: _isArrayDate($rPeriod))
  3878. $inputab = (3 < count($rPeriod)) ? iCalUtilityFunctions :: _date_time_array($rPeriod, $parno) : iCalUtilityFunctions :: _date_time_array($rPeriod, 6);
  3879. elseif ((1 == count($rPeriod)) && (8 <= strlen(reset($rPeriod)))) // text-date
  3880. $inputab = iCalUtilityFunctions :: _date_time_string(reset($rPeriod), $parno);
  3881. else // array format duration
  3882. $inputab = iCalUtilityFunctions :: _duration_array($rPeriod);
  3883. }
  3884. elseif ((3 <= strlen(trim($rPeriod))) && // string format duration
  3885. (in_array($rPeriod[0], array('P', '+', '-'))))
  3886. {
  3887. if ('P' != $rPeriod[0])
  3888. $rPeriod = substr($rPeriod, 1);
  3889. $inputab = iCalUtilityFunctions :: _duration_string($rPeriod);
  3890. }
  3891. elseif (8 <= strlen(trim($rPeriod))) // text date ex. 2006-08-03 10:12:18
  3892. $inputab = iCalUtilityFunctions :: _date_time_string($rPeriod, $parno);
  3893. if (isset($input['params']['TZID']) || (isset($inputab['tz']) && ! iCalUtilityFunctions :: _isOffset($inputab['tz'])) || (isset($inputa[0]) && (! isset($inputa[0]['tz']))) || (isset($inputa[0]['tz']) && ! iCalUtilityFunctions :: _isOffset($inputa[0]['tz'])))
  3894. unset($inputab['tz']);
  3895. $inputa[] = $inputab;
  3896. }
  3897. } // PERIOD end
  3898. elseif (iCalUtilityFunctions :: _isArrayTimestampDate($theRdate)) // timestamp
  3899. $inputa = iCalUtilityFunctions :: _timestamp2date($theRdate, $parno);
  3900. else // date[-time]
  3901. $inputa = iCalUtilityFunctions :: _date_time_array($theRdate, $parno);
  3902. }
  3903. elseif (8 <= strlen(trim($theRdate))) // text date ex. 2006-08-03 10:12:18
  3904. $inputa = iCalUtilityFunctions :: _date_time_string($theRdate, $parno);
  3905. if (! isset($input['params']['VALUE']) || ('PERIOD' != $input['params']['VALUE']))
  3906. { // no PERIOD
  3907. if (3 == $parno)
  3908. unset($inputa['hour'], $inputa['min'], $inputa['sec'], $inputa['tz']);
  3909. elseif (isset($inputa['tz']))
  3910. $inputa['tz'] = (string) $inputa['tz'];
  3911. if (isset($input['params']['TZID']) || (isset($inputa['tz']) && ! iCalUtilityFunctions :: _isOffset($inputa['tz'])) || (isset($input['value'][0]) && (! isset($input['value'][0]['tz']))) || (isset($input['value'][0]['tz']) && ! iCalUtilityFunctions :: _isOffset($input['value'][0]['tz'])))
  3912. unset($inputa['tz']);
  3913. }
  3914. $input['value'][] = $inputa;
  3915. }
  3916. if (3 == $parno)
  3917. {
  3918. $input['params']['VALUE'] = 'DATE';
  3919. unset($input['params']['TZID']);
  3920. }
  3921. iCalUtilityFunctions :: _setMval($this->rdate, $input['value'], $input['params'], FALSE, $index);
  3922. return TRUE;
  3923. }
  3924. /*********************************************************************************/
  3925. /**
  3926. * Property Name: RECURRENCE-ID
  3927. */
  3928. /**
  3929. * creates formatted output for calendar component property recurrence-id
  3930. *
  3931. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3932. * @since 2.9.6 - 2011-05-15
  3933. * @return string
  3934. */
  3935. function createRecurrenceid()
  3936. {
  3937. if (empty($this->recurrenceid))
  3938. return FALSE;
  3939. if (empty($this->recurrenceid['value']))
  3940. return ($this->getConfig('allowEmpty')) ? $this->_createElement('RECURRENCE-ID') : FALSE;
  3941. $formatted = iCalUtilityFunctions :: _format_date_time($this->recurrenceid['value']);
  3942. if ((FALSE !== ($tzid = $this->getConfig('TZID'))) && (! isset($this->recurrenceid['params']['VALUE']) || ($this->recurrenceid['params']['VALUE'] != 'DATE')) && ! isset($this->recurrenceid['params']['TZID']))
  3943. $this->recurrenceid['params']['TZID'] = $tzid;
  3944. $attributes = $this->_createParams($this->recurrenceid['params']);
  3945. return $this->_createElement('RECURRENCE-ID', $attributes, $formatted);
  3946. }
  3947. /**
  3948. * set calendar component property recurrence-id
  3949. *
  3950. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3951. * @since 2.9.6 - 2011-05-15
  3952. * @param mixed $year
  3953. * @param mixed $month optional
  3954. * @param int $day optional
  3955. * @param int $hour optional
  3956. * @param int $min optional
  3957. * @param int $sec optional
  3958. * @param array $params optional
  3959. * @return bool
  3960. */
  3961. function setRecurrenceid($year, $month = FALSE, $day = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $tz = FALSE, $params = FALSE)
  3962. {
  3963. if (empty($year))
  3964. {
  3965. if ($this->getConfig('allowEmpty'))
  3966. {
  3967. $this->recurrenceid = array('value' => null, 'params' => null);
  3968. return TRUE;
  3969. }
  3970. else
  3971. return FALSE;
  3972. }
  3973. $this->recurrenceid = iCalUtilityFunctions :: _setDate($year, $month, $day, $hour, $min, $sec, $tz, $params, null, null, $this->getConfig('TZID'));
  3974. return TRUE;
  3975. }
  3976. /*********************************************************************************/
  3977. /**
  3978. * Property Name: RELATED-TO
  3979. */
  3980. /**
  3981. * creates formatted output for calendar component property related-to
  3982. *
  3983. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  3984. * @since 2.4.8 - 2008-10-23
  3985. * @return string
  3986. */
  3987. function createRelatedTo()
  3988. {
  3989. if (empty($this->relatedto))
  3990. return FALSE;
  3991. $output = null;
  3992. foreach ($this->relatedto as $relation)
  3993. {
  3994. if (empty($relation['value']))
  3995. {
  3996. if ($this->getConfig('allowEmpty'))
  3997. $output .= $this->_createElement('RELATED-TO', $this->_createParams($relation['params']));
  3998. continue;
  3999. }
  4000. $attributes = $this->_createParams($relation['params']);
  4001. $content = ('xcal' != $this->format) ? '<' : '';
  4002. $content .= $this->_strrep($relation['value']);
  4003. $content .= ('xcal' != $this->format) ? '>' : '';
  4004. $output .= $this->_createElement('RELATED-TO', $attributes, $content);
  4005. }
  4006. return $output;
  4007. }
  4008. /**
  4009. * set calendar component property related-to
  4010. *
  4011. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4012. * @since 2.5.1 - 2008-11-07
  4013. * @param float $relid
  4014. * @param array $params, optional
  4015. * @param index $index, optional
  4016. * @return bool
  4017. */
  4018. function setRelatedTo($value, $params = FALSE, $index = FALSE)
  4019. {
  4020. if (empty($value))
  4021. if ($this->getConfig('allowEmpty'))
  4022. $value = null;
  4023. else
  4024. return FALSE;
  4025. if (('<' == substr($value, 0, 1)) && ('>' == substr($value, - 1)))
  4026. $value = substr($value, 1, (strlen($value) - 2));
  4027. iCalUtilityFunctions :: _existRem($params, 'RELTYPE', 'PARENT', TRUE); // remove default
  4028. iCalUtilityFunctions :: _setMval($this->relatedto, $value, $params, FALSE, $index);
  4029. return TRUE;
  4030. }
  4031. /*********************************************************************************/
  4032. /**
  4033. * Property Name: REPEAT
  4034. */
  4035. /**
  4036. * creates formatted output for calendar component property repeat
  4037. *
  4038. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4039. * @since 2.9.3 - 2011-05-14
  4040. * @return string
  4041. */
  4042. function createRepeat()
  4043. {
  4044. if (! isset($this->repeat) || (empty($this->repeat) && ! is_numeric($this->repeat)))
  4045. return FALSE;
  4046. if (! isset($this->repeat['value']) || (empty($this->repeat['value']) && ! is_numeric($this->repeat['value'])))
  4047. return ($this->getConfig('allowEmpty')) ? $this->_createElement('REPEAT') : FALSE;
  4048. $attributes = $this->_createParams($this->repeat['params']);
  4049. return $this->_createElement('REPEAT', $attributes, $this->repeat['value']);
  4050. }
  4051. /**
  4052. * set calendar component property transp
  4053. *
  4054. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4055. * @since 2.9.3 - 2011-05-14
  4056. * @param string $value
  4057. * @param array $params optional
  4058. * @return void
  4059. */
  4060. function setRepeat($value, $params = FALSE)
  4061. {
  4062. if (empty($value) && ! is_numeric($value))
  4063. if ($this->getConfig('allowEmpty'))
  4064. $value = null;
  4065. else
  4066. return FALSE;
  4067. $this->repeat = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4068. return TRUE;
  4069. }
  4070. /*********************************************************************************/
  4071. /**
  4072. * Property Name: REQUEST-STATUS
  4073. */
  4074. /**
  4075. * creates formatted output for calendar component property request-status
  4076. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4077. * @since 2.4.8 - 2008-10-23
  4078. * @return string
  4079. */
  4080. function createRequestStatus()
  4081. {
  4082. if (empty($this->requeststatus))
  4083. return FALSE;
  4084. $output = null;
  4085. foreach ($this->requeststatus as $rstat)
  4086. {
  4087. if (empty($rstat['value']['statcode']))
  4088. {
  4089. if ($this->getConfig('allowEmpty'))
  4090. $output .= $this->_createElement('REQUEST-STATUS');
  4091. continue;
  4092. }
  4093. $attributes = $this->_createParams($rstat['params'], array('LANGUAGE'));
  4094. $content = number_format((float) $rstat['value']['statcode'], 2, '.', '');
  4095. $content .= ';' . $this->_strrep($rstat['value']['text']);
  4096. if (isset($rstat['value']['extdata']))
  4097. $content .= ';' . $this->_strrep($rstat['value']['extdata']);
  4098. $output .= $this->_createElement('REQUEST-STATUS', $attributes, $content);
  4099. }
  4100. return $output;
  4101. }
  4102. /**
  4103. * set calendar component property request-status
  4104. *
  4105. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4106. * @since 2.5.1 - 2008-11-05
  4107. * @param float $statcode
  4108. * @param string $text
  4109. * @param string $extdata, optional
  4110. * @param array $params, optional
  4111. * @param integer $index, optional
  4112. * @return bool
  4113. */
  4114. function setRequestStatus($statcode, $text, $extdata = FALSE, $params = FALSE, $index = FALSE)
  4115. {
  4116. if (empty($statcode) || empty($text))
  4117. if ($this->getConfig('allowEmpty'))
  4118. $statcode = $text = null;
  4119. else
  4120. return FALSE;
  4121. $input = array('statcode' => $statcode, 'text' => $text);
  4122. if ($extdata)
  4123. $input['extdata'] = $extdata;
  4124. iCalUtilityFunctions :: _setMval($this->requeststatus, $input, $params, FALSE, $index);
  4125. return TRUE;
  4126. }
  4127. /*********************************************************************************/
  4128. /**
  4129. * Property Name: RESOURCES
  4130. */
  4131. /**
  4132. * creates formatted output for calendar component property resources
  4133. *
  4134. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4135. * @since 2.4.8 - 2008-10-23
  4136. * @return string
  4137. */
  4138. function createResources()
  4139. {
  4140. if (empty($this->resources))
  4141. return FALSE;
  4142. $output = null;
  4143. foreach ($this->resources as $resource)
  4144. {
  4145. if (empty($resource['value']))
  4146. {
  4147. if ($this->getConfig('allowEmpty'))
  4148. $output .= $this->_createElement('RESOURCES');
  4149. continue;
  4150. }
  4151. $attributes = $this->_createParams($resource['params'], array('ALTREP', 'LANGUAGE'));
  4152. if (is_array($resource['value']))
  4153. {
  4154. foreach ($resource['value'] as $rix => $resourcePart)
  4155. $resource['value'][$rix] = $this->_strrep($resourcePart);
  4156. $content = implode(',', $resource['value']);
  4157. }
  4158. else
  4159. $content = $this->_strrep($resource['value']);
  4160. $output .= $this->_createElement('RESOURCES', $attributes, $content);
  4161. }
  4162. return $output;
  4163. }
  4164. /**
  4165. * set calendar component property recources
  4166. *
  4167. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4168. * @since 2.5.1 - 2008-11-05
  4169. * @param mixed $value
  4170. * @param array $params, optional
  4171. * @param integer $index, optional
  4172. * @return bool
  4173. */
  4174. function setResources($value, $params = FALSE, $index = FALSE)
  4175. {
  4176. if (empty($value))
  4177. if ($this->getConfig('allowEmpty'))
  4178. $value = null;
  4179. else
  4180. return FALSE;
  4181. iCalUtilityFunctions :: _setMval($this->resources, $value, $params, FALSE, $index);
  4182. return TRUE;
  4183. }
  4184. /*********************************************************************************/
  4185. /**
  4186. * Property Name: RRULE
  4187. */
  4188. /**
  4189. * creates formatted output for calendar component property rrule
  4190. *
  4191. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4192. * @since 2.4.8 - 2008-10-21
  4193. * @return string
  4194. */
  4195. function createRrule()
  4196. {
  4197. if (empty($this->rrule))
  4198. return FALSE;
  4199. return $this->_format_recur('RRULE', $this->rrule);
  4200. }
  4201. /**
  4202. * set calendar component property rrule
  4203. *
  4204. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4205. * @since 2.5.1 - 2008-11-05
  4206. * @param array $rruleset
  4207. * @param array $params, optional
  4208. * @param integer $index, optional
  4209. * @return void
  4210. */
  4211. function setRrule($rruleset, $params = FALSE, $index = FALSE)
  4212. {
  4213. if (empty($rruleset))
  4214. if ($this->getConfig('allowEmpty'))
  4215. $rruleset = null;
  4216. else
  4217. return FALSE;
  4218. iCalUtilityFunctions :: _setMval($this->rrule, iCalUtilityFunctions :: _setRexrule($rruleset), $params, FALSE, $index);
  4219. return TRUE;
  4220. }
  4221. /*********************************************************************************/
  4222. /**
  4223. * Property Name: SEQUENCE
  4224. */
  4225. /**
  4226. * creates formatted output for calendar component property sequence
  4227. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4228. * @since 2.9.3 - 2011-05-14
  4229. * @return string
  4230. */
  4231. function createSequence()
  4232. {
  4233. if (! isset($this->sequence) || (empty($this->sequence) && ! is_numeric($this->sequence)))
  4234. return FALSE;
  4235. if ((! isset($this->sequence['value']) || (empty($this->sequence['value']) && ! is_numeric($this->sequence['value']))) && ('0' != $this->sequence['value']))
  4236. return ($this->getConfig('allowEmpty')) ? $this->_createElement('SEQUENCE') : FALSE;
  4237. $attributes = $this->_createParams($this->sequence['params']);
  4238. return $this->_createElement('SEQUENCE', $attributes, $this->sequence['value']);
  4239. }
  4240. /**
  4241. * set calendar component property sequence
  4242. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4243. * @since 2.9.3 - 2011-05-14
  4244. * @param int $value optional
  4245. * @param array $params optional
  4246. * @return bool
  4247. */
  4248. function setSequence($value = FALSE, $params = FALSE)
  4249. {
  4250. if ((empty($value) && ! is_numeric($value)) && ('0' != $value))
  4251. $value = (isset($this->sequence['value']) && (0 < $this->sequence['value'])) ? $this->sequence['value'] + 1 : 1;
  4252. $this->sequence = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4253. return TRUE;
  4254. }
  4255. /*********************************************************************************/
  4256. /**
  4257. * Property Name: STATUS
  4258. */
  4259. /**
  4260. * creates formatted output for calendar component property status
  4261. *
  4262. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4263. * @since 2.4.8 - 2008-10-21
  4264. * @return string
  4265. */
  4266. function createStatus()
  4267. {
  4268. if (empty($this->status))
  4269. return FALSE;
  4270. if (empty($this->status['value']))
  4271. return ($this->getConfig('allowEmpty')) ? $this->_createElement('STATUS') : FALSE;
  4272. $attributes = $this->_createParams($this->status['params']);
  4273. return $this->_createElement('STATUS', $attributes, $this->status['value']);
  4274. }
  4275. /**
  4276. * set calendar component property status
  4277. *
  4278. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4279. * @since 2.4.8 - 2008-11-04
  4280. * @param string $value
  4281. * @param array $params optional
  4282. * @return bool
  4283. */
  4284. function setStatus($value, $params = FALSE)
  4285. {
  4286. if (empty($value))
  4287. if ($this->getConfig('allowEmpty'))
  4288. $value = null;
  4289. else
  4290. return FALSE;
  4291. $this->status = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4292. return TRUE;
  4293. }
  4294. /*********************************************************************************/
  4295. /**
  4296. * Property Name: SUMMARY
  4297. */
  4298. /**
  4299. * creates formatted output for calendar component property summary
  4300. *
  4301. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4302. * @since 2.4.8 - 2008-10-21
  4303. * @return string
  4304. */
  4305. function createSummary()
  4306. {
  4307. if (empty($this->summary))
  4308. return FALSE;
  4309. if (empty($this->summary['value']))
  4310. return ($this->getConfig('allowEmpty')) ? $this->_createElement('SUMMARY') : FALSE;
  4311. $attributes = $this->_createParams($this->summary['params'], array('ALTREP', 'LANGUAGE'));
  4312. $content = $this->_strrep($this->summary['value']);
  4313. return $this->_createElement('SUMMARY', $attributes, $content);
  4314. }
  4315. /**
  4316. * set calendar component property summary
  4317. *
  4318. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4319. * @since 2.4.8 - 2008-11-04
  4320. * @param string $value
  4321. * @param string $params optional
  4322. * @return bool
  4323. */
  4324. function setSummary($value, $params = FALSE)
  4325. {
  4326. if (empty($value))
  4327. if ($this->getConfig('allowEmpty'))
  4328. $value = null;
  4329. else
  4330. return FALSE;
  4331. $this->summary = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4332. return TRUE;
  4333. }
  4334. /*********************************************************************************/
  4335. /**
  4336. * Property Name: TRANSP
  4337. */
  4338. /**
  4339. * creates formatted output for calendar component property transp
  4340. *
  4341. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4342. * @since 2.4.8 - 2008-10-21
  4343. * @return string
  4344. */
  4345. function createTransp()
  4346. {
  4347. if (empty($this->transp))
  4348. return FALSE;
  4349. if (empty($this->transp['value']))
  4350. return ($this->getConfig('allowEmpty')) ? $this->_createElement('TRANSP') : FALSE;
  4351. $attributes = $this->_createParams($this->transp['params']);
  4352. return $this->_createElement('TRANSP', $attributes, $this->transp['value']);
  4353. }
  4354. /**
  4355. * set calendar component property transp
  4356. *
  4357. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4358. * @since 2.4.8 - 2008-11-04
  4359. * @param string $value
  4360. * @param string $params optional
  4361. * @return bool
  4362. */
  4363. function setTransp($value, $params = FALSE)
  4364. {
  4365. if (empty($value))
  4366. if ($this->getConfig('allowEmpty'))
  4367. $value = null;
  4368. else
  4369. return FALSE;
  4370. $this->transp = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4371. return TRUE;
  4372. }
  4373. /*********************************************************************************/
  4374. /**
  4375. * Property Name: TRIGGER
  4376. */
  4377. /**
  4378. * creates formatted output for calendar component property trigger
  4379. *
  4380. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4381. * @since 2.4.16 - 2008-10-21
  4382. * @return string
  4383. */
  4384. function createTrigger()
  4385. {
  4386. if (empty($this->trigger))
  4387. return FALSE;
  4388. if (empty($this->trigger['value']))
  4389. return ($this->getConfig('allowEmpty')) ? $this->_createElement('TRIGGER') : FALSE;
  4390. $content = $attributes = null;
  4391. if (isset($this->trigger['value']['year']) && isset($this->trigger['value']['month']) && isset($this->trigger['value']['day']))
  4392. $content .= iCalUtilityFunctions :: _format_date_time($this->trigger['value']);
  4393. else
  4394. {
  4395. if (TRUE !== $this->trigger['value']['relatedStart'])
  4396. $attributes .= $this->intAttrDelimiter . 'RELATED=END';
  4397. if ($this->trigger['value']['before'])
  4398. $content .= '-';
  4399. $content .= iCalUtilityFunctions :: _format_duration($this->trigger['value']);
  4400. }
  4401. $attributes .= $this->_createParams($this->trigger['params']);
  4402. return $this->_createElement('TRIGGER', $attributes, $content);
  4403. }
  4404. /**
  4405. * set calendar component property trigger
  4406. *
  4407. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4408. * @since 2.9.9 - 2011-06-17
  4409. * @param mixed $year
  4410. * @param mixed $month optional
  4411. * @param int $day optional
  4412. * @param int $week optional
  4413. * @param int $hour optional
  4414. * @param int $min optional
  4415. * @param int $sec optional
  4416. * @param bool $relatedStart optional
  4417. * @param bool $before optional
  4418. * @param array $params optional
  4419. * @return bool
  4420. */
  4421. function setTrigger($year, $month = null, $day = null, $week = FALSE, $hour = FALSE, $min = FALSE, $sec = FALSE, $relatedStart = TRUE, $before = TRUE, $params = FALSE)
  4422. {
  4423. if (empty($year) && empty($month) && empty($day) && empty($week) && empty($hour) && empty($min) && empty($sec))
  4424. if ($this->getConfig('allowEmpty'))
  4425. {
  4426. $this->trigger = array('value' => null, 'params' => iCalUtilityFunctions :: _setParams($params));
  4427. return TRUE;
  4428. }
  4429. else
  4430. return FALSE;
  4431. if (iCalUtilityFunctions :: _isArrayTimestampDate($year))
  4432. { // timestamp
  4433. $params = iCalUtilityFunctions :: _setParams($month);
  4434. $date = iCalUtilityFunctions :: _timestamp2date($year, 7);
  4435. foreach ($date as $k => $v)
  4436. $$k = $v;
  4437. }
  4438. elseif (is_array($year) && (is_array($month) || empty($month)))
  4439. {
  4440. $params = iCalUtilityFunctions :: _setParams($month);
  4441. if (! (array_key_exists('year', $year) && // exclude date-time
  4442. array_key_exists('month', $year) && array_key_exists('day', $year)))
  4443. { // when this must be a duration
  4444. if (isset($params['RELATED']) && ('END' == strtoupper($params['RELATED'])))
  4445. $relatedStart = FALSE;
  4446. else
  4447. $relatedStart = (array_key_exists('relatedStart', $year) && (TRUE !== $year['relatedStart'])) ? FALSE : TRUE;
  4448. $before = (array_key_exists('before', $year) && (TRUE !== $year['before'])) ? FALSE : TRUE;
  4449. }
  4450. $SSYY = (array_key_exists('year', $year)) ? $year['year'] : null;
  4451. $month = (array_key_exists('month', $year)) ? $year['month'] : null;
  4452. $day = (array_key_exists('day', $year)) ? $year['day'] : null;
  4453. $week = (array_key_exists('week', $year)) ? $year['week'] : null;
  4454. $hour = (array_key_exists('hour', $year)) ? $year['hour'] : 0; //null;
  4455. $min = (array_key_exists('min', $year)) ? $year['min'] : 0; //null;
  4456. $sec = (array_key_exists('sec', $year)) ? $year['sec'] : 0; //null;
  4457. $year = $SSYY;
  4458. }
  4459. elseif (is_string($year) && (is_array($month) || empty($month)))
  4460. { // duration or date in a string
  4461. $params = iCalUtilityFunctions :: _setParams($month);
  4462. if (in_array($year[0], array('P', '+', '-')))
  4463. { // duration
  4464. $relatedStart = (isset($params['RELATED']) && ('END' == strtoupper($params['RELATED']))) ? FALSE : TRUE;
  4465. $before = ('-' == $year[0]) ? TRUE : FALSE;
  4466. if ('P' != $year[0])
  4467. $year = substr($year, 1);
  4468. $date = iCalUtilityFunctions :: _duration_string($year);
  4469. }
  4470. else // date
  4471. $date = iCalUtilityFunctions :: _date_time_string($year, 7);
  4472. unset($year, $month, $day);
  4473. if (empty($date))
  4474. $sec = 0;
  4475. else
  4476. foreach ($date as $k => $v)
  4477. $$k = $v;
  4478. }
  4479. else // single values in function input parameters
  4480. $params = iCalUtilityFunctions :: _setParams($params);
  4481. if (! empty($year) && ! empty($month) && ! empty($day))
  4482. { // date
  4483. $params['VALUE'] = 'DATE-TIME';
  4484. $hour = ($hour) ? $hour : 0;
  4485. $min = ($min) ? $min : 0;
  4486. $sec = ($sec) ? $sec : 0;
  4487. $this->trigger = array('params' => $params);
  4488. $this->trigger['value'] = array('year' => $year, 'month' => $month, 'day' => $day, 'hour' => $hour,
  4489. 'min' => $min, 'sec' => $sec, 'tz' => 'Z');
  4490. return TRUE;
  4491. }
  4492. elseif ((empty($year) && empty($month)) && // duration
  4493. ((! empty($week) || (0 == $week)) || (! empty($day) || (0 == $day)) || (! empty($hour) || (0 == $hour)) || (! empty($min) || (0 == $min)) || (! empty($sec) || (0 == $sec))))
  4494. {
  4495. unset($params['RELATED']); // set at output creation (END only)
  4496. unset($params['VALUE']); // 'DURATION' default
  4497. $this->trigger = array('params' => $params);
  4498. $this->trigger['value'] = array();
  4499. if (! empty($week))
  4500. $this->trigger['value']['week'] = $week;
  4501. if (! empty($day))
  4502. $this->trigger['value']['day'] = $day;
  4503. if (! empty($hour))
  4504. $this->trigger['value']['hour'] = $hour;
  4505. if (! empty($min))
  4506. $this->trigger['value']['min'] = $min;
  4507. if (! empty($sec))
  4508. $this->trigger['value']['sec'] = $sec;
  4509. if (empty($this->trigger['value']))
  4510. {
  4511. $this->trigger['value']['sec'] = 0;
  4512. $before = FALSE;
  4513. }
  4514. $relatedStart = (FALSE !== $relatedStart) ? TRUE : FALSE;
  4515. $before = (FALSE !== $before) ? TRUE : FALSE;
  4516. $this->trigger['value']['relatedStart'] = $relatedStart;
  4517. $this->trigger['value']['before'] = $before;
  4518. return TRUE;
  4519. }
  4520. return FALSE;
  4521. }
  4522. /*********************************************************************************/
  4523. /**
  4524. * Property Name: TZID
  4525. */
  4526. /**
  4527. * creates formatted output for calendar component property tzid
  4528. *
  4529. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4530. * @since 2.4.8 - 2008-10-21
  4531. * @return string
  4532. */
  4533. function createTzid()
  4534. {
  4535. if (empty($this->tzid))
  4536. return FALSE;
  4537. if (empty($this->tzid['value']))
  4538. return ($this->getConfig('allowEmpty')) ? $this->_createElement('TZID') : FALSE;
  4539. $attributes = $this->_createParams($this->tzid['params']);
  4540. return $this->_createElement('TZID', $attributes, $this->_strrep($this->tzid['value']));
  4541. }
  4542. /**
  4543. * set calendar component property tzid
  4544. *
  4545. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4546. * @since 2.4.8 - 2008-11-04
  4547. * @param string $value
  4548. * @param array $params optional
  4549. * @return bool
  4550. */
  4551. function setTzid($value, $params = FALSE)
  4552. {
  4553. if (empty($value))
  4554. if ($this->getConfig('allowEmpty'))
  4555. $value = null;
  4556. else
  4557. return FALSE;
  4558. $this->tzid = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4559. return TRUE;
  4560. }
  4561. /*********************************************************************************/
  4562. /**
  4563. * .. .
  4564. * Property Name: TZNAME
  4565. */
  4566. /**
  4567. * creates formatted output for calendar component property tzname
  4568. *
  4569. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4570. * @since 2.4.8 - 2008-10-21
  4571. * @return string
  4572. */
  4573. function createTzname()
  4574. {
  4575. if (empty($this->tzname))
  4576. return FALSE;
  4577. $output = null;
  4578. foreach ($this->tzname as $theName)
  4579. {
  4580. if (! empty($theName['value']))
  4581. {
  4582. $attributes = $this->_createParams($theName['params'], array('LANGUAGE'));
  4583. $output .= $this->_createElement('TZNAME', $attributes, $this->_strrep($theName['value']));
  4584. }
  4585. elseif ($this->getConfig('allowEmpty'))
  4586. $output .= $this->_createElement('TZNAME');
  4587. }
  4588. return $output;
  4589. }
  4590. /**
  4591. * set calendar component property tzname
  4592. *
  4593. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4594. * @since 2.5.1 - 2008-11-05
  4595. * @param string $value
  4596. * @param string $params, optional
  4597. * @param integer $index, optional
  4598. * @return bool
  4599. */
  4600. function setTzname($value, $params = FALSE, $index = FALSE)
  4601. {
  4602. if (empty($value))
  4603. if ($this->getConfig('allowEmpty'))
  4604. $value = null;
  4605. else
  4606. return FALSE;
  4607. iCalUtilityFunctions :: _setMval($this->tzname, $value, $params, FALSE, $index);
  4608. return TRUE;
  4609. }
  4610. /*********************************************************************************/
  4611. /**
  4612. * Property Name: TZOFFSETFROM
  4613. */
  4614. /**
  4615. * creates formatted output for calendar component property tzoffsetfrom
  4616. *
  4617. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4618. * @since 2.4.8 - 2008-10-21
  4619. * @return string
  4620. */
  4621. function createTzoffsetfrom()
  4622. {
  4623. if (empty($this->tzoffsetfrom))
  4624. return FALSE;
  4625. if (empty($this->tzoffsetfrom['value']))
  4626. return ($this->getConfig('allowEmpty')) ? $this->_createElement('TZOFFSETFROM') : FALSE;
  4627. $attributes = $this->_createParams($this->tzoffsetfrom['params']);
  4628. return $this->_createElement('TZOFFSETFROM', $attributes, $this->tzoffsetfrom['value']);
  4629. }
  4630. /**
  4631. * set calendar component property tzoffsetfrom
  4632. *
  4633. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4634. * @since 2.4.8 - 2008-11-04
  4635. * @param string $value
  4636. * @param string $params optional
  4637. * @return bool
  4638. */
  4639. function setTzoffsetfrom($value, $params = FALSE)
  4640. {
  4641. if (empty($value))
  4642. if ($this->getConfig('allowEmpty'))
  4643. $value = null;
  4644. else
  4645. return FALSE;
  4646. $this->tzoffsetfrom = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4647. return TRUE;
  4648. }
  4649. /*********************************************************************************/
  4650. /**
  4651. * Property Name: TZOFFSETTO
  4652. */
  4653. /**
  4654. * creates formatted output for calendar component property tzoffsetto
  4655. *
  4656. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4657. * @since 2.4.8 - 2008-10-21
  4658. * @return string
  4659. */
  4660. function createTzoffsetto()
  4661. {
  4662. if (empty($this->tzoffsetto))
  4663. return FALSE;
  4664. if (empty($this->tzoffsetto['value']))
  4665. return ($this->getConfig('allowEmpty')) ? $this->_createElement('TZOFFSETTO') : FALSE;
  4666. $attributes = $this->_createParams($this->tzoffsetto['params']);
  4667. return $this->_createElement('TZOFFSETTO', $attributes, $this->tzoffsetto['value']);
  4668. }
  4669. /**
  4670. * set calendar component property tzoffsetto
  4671. *
  4672. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4673. * @since 2.4.8 - 2008-11-04
  4674. * @param string $value
  4675. * @param string $params optional
  4676. * @return bool
  4677. */
  4678. function setTzoffsetto($value, $params = FALSE)
  4679. {
  4680. if (empty($value))
  4681. if ($this->getConfig('allowEmpty'))
  4682. $value = null;
  4683. else
  4684. return FALSE;
  4685. $this->tzoffsetto = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4686. return TRUE;
  4687. }
  4688. /*********************************************************************************/
  4689. /**
  4690. * Property Name: TZURL
  4691. */
  4692. /**
  4693. * creates formatted output for calendar component property tzurl
  4694. *
  4695. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4696. * @since 2.4.8 - 2008-10-21
  4697. * @return string
  4698. */
  4699. function createTzurl()
  4700. {
  4701. if (empty($this->tzurl))
  4702. return FALSE;
  4703. if (empty($this->tzurl['value']))
  4704. return ($this->getConfig('allowEmpty')) ? $this->_createElement('TZURL') : FALSE;
  4705. $attributes = $this->_createParams($this->tzurl['params']);
  4706. return $this->_createElement('TZURL', $attributes, $this->tzurl['value']);
  4707. }
  4708. /**
  4709. * set calendar component property tzurl
  4710. *
  4711. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4712. * @since 2.4.8 - 2008-11-04
  4713. * @param string $value
  4714. * @param string $params optional
  4715. * @return boll
  4716. */
  4717. function setTzurl($value, $params = FALSE)
  4718. {
  4719. if (empty($value))
  4720. if ($this->getConfig('allowEmpty'))
  4721. $value = null;
  4722. else
  4723. return FALSE;
  4724. $this->tzurl = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4725. return TRUE;
  4726. }
  4727. /*********************************************************************************/
  4728. /**
  4729. * Property Name: UID
  4730. */
  4731. /**
  4732. * creates formatted output for calendar component property uid
  4733. *
  4734. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4735. * @since 0.9.7 - 2006-11-20
  4736. * @return string
  4737. */
  4738. function createUid()
  4739. {
  4740. if (0 >= count($this->uid))
  4741. $this->_makeuid();
  4742. $attributes = $this->_createParams($this->uid['params']);
  4743. return $this->_createElement('UID', $attributes, $this->uid['value']);
  4744. }
  4745. /**
  4746. * create an unique id for this calendar component object instance
  4747. *
  4748. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4749. * @since 2.2.7 - 2007-09-04
  4750. * @return void
  4751. */
  4752. function _makeUid()
  4753. {
  4754. $date = date('Ymd\THisT');
  4755. $unique = substr(microtime(), 2, 4);
  4756. $base = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPrRsStTuUvVxXuUvVwWzZ1234567890';
  4757. $start = 0;
  4758. $end = strlen($base) - 1;
  4759. $length = 6;
  4760. $str = null;
  4761. for($p = 0; $p < $length; $p ++)
  4762. $unique .= $base{mt_rand($start, $end)};
  4763. $this->uid = array('params' => null);
  4764. $this->uid['value'] = $date . '-' . $unique . '@' . $this->getConfig('unique_id');
  4765. }
  4766. /**
  4767. * set calendar component property uid
  4768. *
  4769. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4770. * @since 2.4.8 - 2008-11-04
  4771. * @param string $value
  4772. * @param string $params optional
  4773. * @return bool
  4774. */
  4775. function setUid($value, $params = FALSE)
  4776. {
  4777. if (empty($value))
  4778. return FALSE; // no allowEmpty check here !!!!
  4779. $this->uid = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4780. return TRUE;
  4781. }
  4782. /*********************************************************************************/
  4783. /**
  4784. * Property Name: URL
  4785. */
  4786. /**
  4787. * creates formatted output for calendar component property url
  4788. *
  4789. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4790. * @since 2.4.8 - 2008-10-21
  4791. * @return string
  4792. */
  4793. function createUrl()
  4794. {
  4795. if (empty($this->url))
  4796. return FALSE;
  4797. if (empty($this->url['value']))
  4798. return ($this->getConfig('allowEmpty')) ? $this->_createElement('URL') : FALSE;
  4799. $attributes = $this->_createParams($this->url['params']);
  4800. return $this->_createElement('URL', $attributes, $this->url['value']);
  4801. }
  4802. /**
  4803. * set calendar component property url
  4804. *
  4805. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4806. * @since 2.4.8 - 2008-11-04
  4807. * @param string $value
  4808. * @param string $params optional
  4809. * @return bool
  4810. */
  4811. function setUrl($value, $params = FALSE)
  4812. {
  4813. if (empty($value))
  4814. if ($this->getConfig('allowEmpty'))
  4815. $value = null;
  4816. else
  4817. return FALSE;
  4818. $this->url = array('value' => $value, 'params' => iCalUtilityFunctions :: _setParams($params));
  4819. return TRUE;
  4820. }
  4821. /*********************************************************************************/
  4822. /**
  4823. * Property Name: x-prop
  4824. */
  4825. /**
  4826. * creates formatted output for calendar component property x-prop
  4827. *
  4828. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4829. * @since 2.9.3 - 2011-05-14
  4830. * @return string
  4831. */
  4832. function createXprop()
  4833. {
  4834. if (empty($this->xprop))
  4835. return FALSE;
  4836. $output = null;
  4837. foreach ($this->xprop as $label => $xpropPart)
  4838. {
  4839. if (! isset($xpropPart['value']) || (empty($xpropPart['value']) && ! is_numeric($xpropPart['value'])))
  4840. {
  4841. if ($this->getConfig('allowEmpty'))
  4842. $output .= $this->_createElement($label);
  4843. continue;
  4844. }
  4845. $attributes = $this->_createParams($xpropPart['params'], array('LANGUAGE'));
  4846. if (is_array($xpropPart['value']))
  4847. {
  4848. foreach ($xpropPart['value'] as $pix => $theXpart)
  4849. $xpropPart['value'][$pix] = $this->_strrep($theXpart);
  4850. $xpropPart['value'] = implode(',', $xpropPart['value']);
  4851. }
  4852. else
  4853. $xpropPart['value'] = $this->_strrep($xpropPart['value']);
  4854. $output .= $this->_createElement($label, $attributes, $xpropPart['value']);
  4855. }
  4856. return $output;
  4857. }
  4858. /**
  4859. * set calendar component property x-prop
  4860. *
  4861. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4862. * @since 2.9.3 - 2011-05-14
  4863. * @param string $label
  4864. * @param mixed $value
  4865. * @param array $params optional
  4866. * @return bool
  4867. */
  4868. function setXprop($label, $value, $params = FALSE)
  4869. {
  4870. if (empty($label))
  4871. return;
  4872. if (empty($value) && ! is_numeric($value))
  4873. if ($this->getConfig('allowEmpty'))
  4874. $value = null;
  4875. else
  4876. return FALSE;
  4877. $xprop = array('value' => $value);
  4878. $xprop['params'] = iCalUtilityFunctions :: _setParams($params);
  4879. if (! is_array($this->xprop))
  4880. $this->xprop = array();
  4881. $this->xprop[strtoupper($label)] = $xprop;
  4882. return TRUE;
  4883. }
  4884. /*********************************************************************************/
  4885. /*********************************************************************************/
  4886. /**
  4887. * create element format parts
  4888. *
  4889. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4890. * @since 2.0.6 - 2006-06-20
  4891. * @return string
  4892. */
  4893. function _createFormat()
  4894. {
  4895. $objectname = null;
  4896. switch ($this->format)
  4897. {
  4898. case 'xcal' :
  4899. $objectname = (isset($this->timezonetype)) ? strtolower($this->timezonetype) : strtolower($this->objName);
  4900. $this->componentStart1 = $this->elementStart1 = '<';
  4901. $this->componentStart2 = $this->elementStart2 = '>';
  4902. $this->componentEnd1 = $this->elementEnd1 = '</';
  4903. $this->componentEnd2 = $this->elementEnd2 = '>' . $this->nl;
  4904. $this->intAttrDelimiter = '<!-- -->';
  4905. $this->attributeDelimiter = $this->nl;
  4906. $this->valueInit = null;
  4907. break;
  4908. default :
  4909. $objectname = (isset($this->timezonetype)) ? strtoupper($this->timezonetype) : strtoupper($this->objName);
  4910. $this->componentStart1 = 'BEGIN:';
  4911. $this->componentStart2 = null;
  4912. $this->componentEnd1 = 'END:';
  4913. $this->componentEnd2 = $this->nl;
  4914. $this->elementStart1 = null;
  4915. $this->elementStart2 = null;
  4916. $this->elementEnd1 = null;
  4917. $this->elementEnd2 = $this->nl;
  4918. $this->intAttrDelimiter = '<!-- -->';
  4919. $this->attributeDelimiter = ';';
  4920. $this->valueInit = ':';
  4921. break;
  4922. }
  4923. return $objectname;
  4924. }
  4925. /**
  4926. * creates formatted output for calendar component property
  4927. *
  4928. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  4929. * @since 2.6.22 - 2010-12-06
  4930. * @param string $label property name
  4931. * @param string $attributes property attributes
  4932. * @param string $content property content (optional)
  4933. * @return string
  4934. */
  4935. function _createElement($label, $attributes = null, $content = FALSE)
  4936. {
  4937. switch ($this->format)
  4938. {
  4939. case 'xcal' :
  4940. $label = strtolower($label);
  4941. break;
  4942. default :
  4943. $label = strtoupper($label);
  4944. break;
  4945. }
  4946. $output = $this->elementStart1 . $label;
  4947. $categoriesAttrLang = null;
  4948. $attachInlineBinary = FALSE;
  4949. $attachfmttype = null;
  4950. if (! empty($attributes))
  4951. {
  4952. $attributes = trim($attributes);
  4953. if ('xcal' == $this->format)
  4954. {
  4955. $attributes2 = explode($this->intAttrDelimiter, $attributes);
  4956. $attributes = null;
  4957. foreach ($attributes2 as $attribute)
  4958. {
  4959. $attrKVarr = explode('=', $attribute);
  4960. if (empty($attrKVarr[0]))
  4961. continue;
  4962. if (! isset($attrKVarr[1]))
  4963. {
  4964. $attrValue = $attrKVarr[0];
  4965. $attrKey = null;
  4966. }
  4967. elseif (2 == count($attrKVarr))
  4968. {
  4969. $attrKey = strtolower($attrKVarr[0]);
  4970. $attrValue = $attrKVarr[1];
  4971. }
  4972. else
  4973. {
  4974. $attrKey = strtolower($attrKVarr[0]);
  4975. unset($attrKVarr[0]);
  4976. $attrValue = implode('=', $attrKVarr);
  4977. }
  4978. if (('attach' == $label) && (in_array($attrKey, array('fmttype', 'encoding', 'value'))))
  4979. {
  4980. $attachInlineBinary = TRUE;
  4981. if ('fmttype' == $attrKey)
  4982. $attachfmttype = $attrKey . '=' . $attrValue;
  4983. continue;
  4984. }
  4985. elseif (('categories' == $label) && ('language' == $attrKey))
  4986. $categoriesAttrLang = $attrKey . '=' . $attrValue;
  4987. else
  4988. {
  4989. $attributes .= (empty($attributes)) ? ' ' : $this->attributeDelimiter . ' ';
  4990. $attributes .= (! empty($attrKey)) ? $attrKey . '=' : null;
  4991. if (('"' == substr($attrValue, 0, 1)) && ('"' == substr($attrValue, - 1)))
  4992. {
  4993. $attrValue = substr($attrValue, 1, (strlen($attrValue) - 2));
  4994. $attrValue = str_replace('"', '', $attrValue);
  4995. }
  4996. $attributes .= '"' . htmlspecialchars($attrValue) . '"';
  4997. }
  4998. }
  4999. }
  5000. else
  5001. {
  5002. $attributes = str_replace($this->intAttrDelimiter, $this->attributeDelimiter, $attributes);
  5003. }
  5004. }
  5005. if (((('attach' == $label) && ! $attachInlineBinary) || (in_array($label, array('tzurl', 'url')))) && ('xcal' == $this->format))
  5006. {
  5007. $pos = strrpos($content, "/");
  5008. $docname = ($pos !== false) ? substr($content, (1 - strlen($content) + $pos)) : $content;
  5009. $this->xcaldecl[] = array('xmldecl' => 'ENTITY', 'uri' => $docname, 'ref' => 'SYSTEM',
  5010. 'external' => $content, 'type' => 'NDATA', 'type2' => 'BINERY');
  5011. $attributes .= (empty($attributes)) ? ' ' : $this->attributeDelimiter . ' ';
  5012. $attributes .= 'uri="' . $docname . '"';
  5013. $content = null;
  5014. if ('attach' == $label)
  5015. {
  5016. $attributes = str_replace($this->attributeDelimiter, $this->intAttrDelimiter, $attributes);
  5017. $content = $this->_createElement('extref', $attributes, null);
  5018. $attributes = null;
  5019. }
  5020. }
  5021. elseif (('attach' == $label) && $attachInlineBinary && ('xcal' == $this->format))
  5022. {
  5023. $content = $this->nl . $this->_createElement('b64bin', $attachfmttype, $content); // max one attribute
  5024. }
  5025. $output .= $attributes;
  5026. if (! $content && ('0' != $content))
  5027. {
  5028. switch ($this->format)
  5029. {
  5030. case 'xcal' :
  5031. $output .= ' /';
  5032. $output .= $this->elementStart2;
  5033. return $output;
  5034. break;
  5035. default :
  5036. $output .= $this->elementStart2 . $this->valueInit;
  5037. return $this->_size75($output);
  5038. break;
  5039. }
  5040. }
  5041. $output .= $this->elementStart2;
  5042. $output .= $this->valueInit . $content;
  5043. switch ($this->format)
  5044. {
  5045. case 'xcal' :
  5046. return $output . $this->elementEnd1 . $label . $this->elementEnd2;
  5047. break;
  5048. default :
  5049. return $this->_size75($output);
  5050. break;
  5051. }
  5052. }
  5053. /**
  5054. * creates formatted output for calendar component property parameters
  5055. *
  5056. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  5057. * @since 2.6.33 - 2010-12-18
  5058. * @param array $params optional
  5059. * @param array $ctrKeys optional
  5060. * @return string
  5061. */
  5062. function _createParams($params = array(), $ctrKeys = array())
  5063. {
  5064. if (! is_array($params) || empty($params))
  5065. $params = array();
  5066. $attrLANG = $attr1 = $attr2 = $lang = null;
  5067. $CNattrKey = (in_array('CN', $ctrKeys)) ? TRUE : FALSE;
  5068. $LANGattrKey = (in_array('LANGUAGE', $ctrKeys)) ? TRUE : FALSE;
  5069. $CNattrExist = $LANGattrExist = FALSE;
  5070. $xparams = array();
  5071. foreach ($params as $paramKey => $paramValue)
  5072. {
  5073. if (ctype_digit((string) $paramKey))
  5074. {
  5075. $xparams[] = $paramValue;
  5076. continue;
  5077. }
  5078. $paramKey = strtoupper($paramKey);
  5079. if (! in_array($paramKey, array('ALTREP', 'CN', 'DIR', 'ENCODING', 'FMTTYPE', 'LANGUAGE', 'RANGE',
  5080. 'RELTYPE', 'SENT-BY', 'TZID', 'VALUE')))
  5081. $xparams[$paramKey] = $paramValue;
  5082. else
  5083. $params[$paramKey] = $paramValue;
  5084. }
  5085. ksort($xparams, SORT_STRING);
  5086. foreach ($xparams as $paramKey => $paramValue)
  5087. {
  5088. if (ctype_digit((string) $paramKey))
  5089. $attr2 .= $this->intAttrDelimiter . $paramValue;
  5090. else
  5091. $attr2 .= $this->intAttrDelimiter . "$paramKey=$paramValue";
  5092. }
  5093. if (isset($params['FMTTYPE']) && ! in_array('FMTTYPE', $ctrKeys))
  5094. {
  5095. $attr1 .= $this->intAttrDelimiter . 'FMTTYPE=' . $params['FMTTYPE'] . $attr2;
  5096. $attr2 = null;
  5097. }
  5098. if (isset($params['ENCODING']) && ! in_array('ENCODING', $ctrKeys))
  5099. {
  5100. if (! empty($attr2))
  5101. {
  5102. $attr1 .= $attr2;
  5103. $attr2 = null;
  5104. }
  5105. $attr1 .= $this->intAttrDelimiter . 'ENCODING=' . $params['ENCODING'];
  5106. }
  5107. if (isset($params['VALUE']) && ! in_array('VALUE', $ctrKeys))
  5108. $attr1 .= $this->intAttrDelimiter . 'VALUE=' . $params['VALUE'];
  5109. if (isset($params['TZID']) && ! in_array('TZID', $ctrKeys))
  5110. $attr1 .= $this->intAttrDelimiter . 'TZID=' . $params['TZID'];
  5111. if (isset($params['RANGE']) && ! in_array('RANGE', $ctrKeys))
  5112. $attr1 .= $this->intAttrDelimiter . 'RANGE=' . $params['RANGE'];
  5113. if (isset($params['RELTYPE']) && ! in_array('RELTYPE', $ctrKeys))
  5114. $attr1 .= $this->intAttrDelimiter . 'RELTYPE=' . $params['RELTYPE'];
  5115. if (isset($params['CN']) && $CNattrKey)
  5116. {
  5117. $attr1 = $this->intAttrDelimiter . 'CN="' . $params['CN'] . '"';
  5118. $CNattrExist = TRUE;
  5119. }
  5120. if (isset($params['DIR']) && in_array('DIR', $ctrKeys))
  5121. $attr1 .= $this->intAttrDelimiter . 'DIR="' . $params['DIR'] . '"';
  5122. if (isset($params['SENT-BY']) && in_array('SENT-BY', $ctrKeys))
  5123. $attr1 .= $this->intAttrDelimiter . 'SENT-BY="' . $params['SENT-BY'] . '"';
  5124. if (isset($params['ALTREP']) && in_array('ALTREP', $ctrKeys))
  5125. $attr1 .= $this->intAttrDelimiter . 'ALTREP="' . $params['ALTREP'] . '"';
  5126. if (isset($params['LANGUAGE']) && $LANGattrKey)
  5127. {
  5128. $attrLANG .= $this->intAttrDelimiter . 'LANGUAGE=' . $params['LANGUAGE'];
  5129. $LANGattrExist = TRUE;
  5130. }
  5131. if (! $LANGattrExist)
  5132. {
  5133. $lang = $this->getConfig('language');
  5134. if (($CNattrExist || $LANGattrKey) && $lang)
  5135. $attrLANG .= $this->intAttrDelimiter . 'LANGUAGE=' . $lang;
  5136. }
  5137. return $attr1 . $attrLANG . $attr2;
  5138. }
  5139. /**
  5140. * creates formatted output for calendar component property data value type recur
  5141. *
  5142. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  5143. * @since 2.4.8 - 2008-10-22
  5144. * @param array $recurlabel
  5145. * @param array $recurdata
  5146. * @return string
  5147. */
  5148. function _format_recur($recurlabel, $recurdata)
  5149. {
  5150. $output = null;
  5151. foreach ($recurdata as $therule)
  5152. {
  5153. if (empty($therule['value']))
  5154. {
  5155. if ($this->getConfig('allowEmpty'))
  5156. $output .= $this->_createElement($recurlabel);
  5157. continue;
  5158. }
  5159. $attributes = (isset($therule['params'])) ? $this->_createParams($therule['params']) : null;
  5160. $content1 = $content2 = null;
  5161. foreach ($therule['value'] as $rulelabel => $rulevalue)
  5162. {
  5163. switch ($rulelabel)
  5164. {
  5165. case 'FREQ' :
  5166. {
  5167. $content1 .= "FREQ=$rulevalue";
  5168. break;
  5169. }
  5170. case 'UNTIL' :
  5171. {
  5172. $content2 .= ";UNTIL=";
  5173. $content2 .= iCalUtilityFunctions :: _format_date_time($rulevalue);
  5174. break;
  5175. }
  5176. case 'COUNT' :
  5177. case 'INTERVAL' :
  5178. case 'WKST' :
  5179. {
  5180. $content2 .= ";$rulelabel=$rulevalue";
  5181. break;
  5182. }
  5183. case 'BYSECOND' :
  5184. case 'BYMINUTE' :
  5185. case 'BYHOUR' :
  5186. case 'BYMONTHDAY' :
  5187. case 'BYYEARDAY' :
  5188. case 'BYWEEKNO' :
  5189. case 'BYMONTH' :
  5190. case 'BYSETPOS' :
  5191. {
  5192. $content2 .= ";$rulelabel=";
  5193. if (is_array($rulevalue))
  5194. {
  5195. foreach ($rulevalue as $vix => $valuePart)
  5196. {
  5197. $content2 .= ($vix) ? ',' : null;
  5198. $content2 .= $valuePart;
  5199. }
  5200. }
  5201. else
  5202. $content2 .= $rulevalue;
  5203. break;
  5204. }
  5205. case 'BYDAY' :
  5206. {
  5207. $content2 .= ";$rulelabel=";
  5208. $bydaycnt = 0;
  5209. foreach ($rulevalue as $vix => $valuePart)
  5210. {
  5211. $content21 = $content22 = null;
  5212. if (is_array($valuePart))
  5213. {
  5214. $content2 .= ($bydaycnt) ? ',' : null;
  5215. foreach ($valuePart as $vix2 => $valuePart2)
  5216. {
  5217. if ('DAY' != strtoupper($vix2))
  5218. $content21 .= $valuePart2;
  5219. else
  5220. $content22 .= $valuePart2;
  5221. }
  5222. $content2 .= $content21 . $content22;
  5223. $bydaycnt ++;
  5224. }
  5225. else
  5226. {
  5227. $content2 .= ($bydaycnt) ? ',' : null;
  5228. if ('DAY' != strtoupper($vix))
  5229. $content21 .= $valuePart;
  5230. else
  5231. {
  5232. $content22 .= $valuePart;
  5233. $bydaycnt ++;
  5234. }
  5235. $content2 .= $content21 . $content22;
  5236. }
  5237. }
  5238. break;
  5239. }
  5240. default :
  5241. {
  5242. $content2 .= ";$rulelabel=$rulevalue";
  5243. break;
  5244. }
  5245. }
  5246. }
  5247. $output .= $this->_createElement($recurlabel, $attributes, $content1 . $content2);
  5248. }
  5249. return $output;
  5250. }
  5251. /**
  5252. * check if property not exists within component
  5253. *
  5254. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  5255. * @since 2.5.1 - 2008-10-15
  5256. * @param string $propName
  5257. * @return bool
  5258. */
  5259. function _notExistProp($propName)
  5260. {
  5261. if (empty($propName))
  5262. return FALSE; // when deleting x-prop, an empty propName may be used=allowed
  5263. $propName = strtolower($propName);
  5264. if ('last-modified' == $propName)
  5265. {
  5266. if (! isset($this->lastmodified))
  5267. return TRUE;
  5268. }
  5269. elseif ('percent-complete' == $propName)
  5270. {
  5271. if (! isset($this->percentcomplete))
  5272. return TRUE;
  5273. }
  5274. elseif ('recurrence-id' == $propName)
  5275. {
  5276. if (! isset($this->recurrenceid))
  5277. return TRUE;
  5278. }
  5279. elseif ('related-to' == $propName)
  5280. {
  5281. if (! isset($this->relatedto))
  5282. return TRUE;
  5283. }
  5284. elseif ('request-status' == $propName)
  5285. {
  5286. if (! isset($this->requeststatus))
  5287. return TRUE;
  5288. }
  5289. elseif (('x-' != substr($propName, 0, 2)) && ! isset($this->$propName))
  5290. return TRUE;
  5291. return FALSE;
  5292. }
  5293. /*********************************************************************************/
  5294. /*********************************************************************************/
  5295. /**
  5296. * get general component config variables or info about subcomponents
  5297. *
  5298. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  5299. * @since 2.9.6 - 2011-05-14
  5300. * @param mixed $config
  5301. * @return value
  5302. */
  5303. function getConfig($config = FALSE)
  5304. {
  5305. if (! $config)
  5306. {
  5307. $return = array();
  5308. $return['ALLOWEMPTY'] = $this->getConfig('ALLOWEMPTY');
  5309. $return['FORMAT'] = $this->getConfig('FORMAT');
  5310. if (FALSE !== ($lang = $this->getConfig('LANGUAGE')))
  5311. $return['LANGUAGE'] = $lang;
  5312. $return['NEWLINECHAR'] = $this->getConfig('NEWLINECHAR');
  5313. $return['TZTD'] = $this->getConfig('TZID');
  5314. $return['UNIQUE_ID'] = $this->getConfig('UNIQUE_ID');
  5315. return $return;
  5316. }
  5317. switch (strtoupper($config))
  5318. {
  5319. case 'ALLOWEMPTY' :
  5320. return $this->allowEmpty;
  5321. break;
  5322. case 'COMPSINFO' :
  5323. unset($this->compix);
  5324. $info = array();
  5325. if (isset($this->components))
  5326. {
  5327. foreach ($this->components as $cix => $component)
  5328. {
  5329. if (empty($component))
  5330. continue;
  5331. $info[$cix]['ordno'] = $cix + 1;
  5332. $info[$cix]['type'] = $component->objName;
  5333. $info[$cix]['uid'] = $component->getProperty('uid');
  5334. $info[$cix]['props'] = $component->getConfig('propinfo');
  5335. $info[$cix]['sub'] = $component->getConfig('compsinfo');
  5336. }
  5337. }
  5338. return $info;
  5339. break;
  5340. case 'FORMAT' :
  5341. return $this->format;
  5342. break;
  5343. case 'LANGUAGE' :
  5344. // get language for calendar component as defined in [RFC 1766]
  5345. return $this->language;
  5346. break;
  5347. case 'NL' :
  5348. case 'NEWLINECHAR' :
  5349. return $this->nl;
  5350. break;
  5351. case 'PROPINFO' :
  5352. $output = array();
  5353. if (! in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight')))
  5354. {
  5355. if (empty($this->uid['value']))
  5356. $this->_makeuid();
  5357. $output['UID'] = 1;
  5358. }
  5359. if (! empty($this->dtstamp))
  5360. $output['DTSTAMP'] = 1;
  5361. if (! empty($this->summary))
  5362. $output['SUMMARY'] = 1;
  5363. if (! empty($this->description))
  5364. $output['DESCRIPTION'] = count($this->description);
  5365. if (! empty($this->dtstart))
  5366. $output['DTSTART'] = 1;
  5367. if (! empty($this->dtend))
  5368. $output['DTEND'] = 1;
  5369. if (! empty($this->due))
  5370. $output['DUE'] = 1;
  5371. if (! empty($this->duration))
  5372. $output['DURATION'] = 1;
  5373. if (! empty($this->rrule))
  5374. $output['RRULE'] = count($this->rrule);
  5375. if (! empty($this->rdate))
  5376. $output['RDATE'] = count($this->rdate);
  5377. if (! empty($this->exdate))
  5378. $output['EXDATE'] = count($this->exdate);
  5379. if (! empty($this->exrule))
  5380. $output['EXRULE'] = count($this->exrule);
  5381. if (! empty($this->action))
  5382. $output['ACTION'] = 1;
  5383. if (! empty($this->attach))
  5384. $output['ATTACH'] = count($this->attach);
  5385. if (! empty($this->attendee))
  5386. $output['ATTENDEE'] = count($this->attendee);
  5387. if (! empty($this->categories))
  5388. $output['CATEGORIES'] = count($this->categories);
  5389. if (! empty($this->class))
  5390. $output['CLASS'] = 1;
  5391. if (! empty($this->comment))
  5392. $output['COMMENT'] = count($this->comment);
  5393. if (! empty($this->completed))
  5394. $output['COMPLETED'] = 1;
  5395. if (! empty($this->contact))
  5396. $output['CONTACT'] = count($this->contact);
  5397. if (! empty($this->created))
  5398. $output['CREATED'] = 1;
  5399. if (! empty($this->freebusy))
  5400. $output['FREEBUSY'] = count($this->freebusy);
  5401. if (! empty($this->geo))
  5402. $output['GEO'] = 1;
  5403. if (! empty($this->lastmodified))
  5404. $output['LAST-MODIFIED'] = 1;
  5405. if (! empty($this->location))
  5406. $output['LOCATION'] = 1;
  5407. if (! empty($this->organizer))
  5408. $output['ORGANIZER'] = 1;
  5409. if (! empty($this->percentcomplete))
  5410. $output['PERCENT-COMPLETE'] = 1;
  5411. if (! empty($this->priority))
  5412. $output['PRIORITY'] = 1;
  5413. if (! empty($this->recurrenceid))
  5414. $output['RECURRENCE-ID'] = 1;
  5415. if (! empty($this->relatedto))
  5416. $output['RELATED-TO'] = count($this->relatedto);
  5417. if (! empty($this->repeat))
  5418. $output['REPEAT'] = 1;
  5419. if (! empty($this->requeststatus))
  5420. $output['REQUEST-STATUS'] = count($this->requeststatus);
  5421. if (! empty($this->resources))
  5422. $output['RESOURCES'] = count($this->resources);
  5423. if (! empty($this->sequence))
  5424. $output['SEQUENCE'] = 1;
  5425. if (! empty($this->sequence))
  5426. $output['SEQUENCE'] = 1;
  5427. if (! empty($this->status))
  5428. $output['STATUS'] = 1;
  5429. if (! empty($this->transp))
  5430. $output['TRANSP'] = 1;
  5431. if (! empty($this->trigger))
  5432. $output['TRIGGER'] = 1;
  5433. if (! empty($this->tzid))
  5434. $output['TZID'] = 1;
  5435. if (! empty($this->tzname))
  5436. $output['TZNAME'] = count($this->tzname);
  5437. if (! empty($this->tzoffsetfrom))
  5438. $output['TZOFFSETFROM'] = 1;
  5439. if (! empty($this->tzoffsetto))
  5440. $output['TZOFFSETTO'] = 1;
  5441. if (! empty($this->tzurl))
  5442. $output['TZURL'] = 1;
  5443. if (! empty($this->url))
  5444. $output['URL'] = 1;
  5445. if (! empty($this->xprop))
  5446. $output['X-PROP'] = count($this->xprop);
  5447. return $output;
  5448. break;
  5449. case 'TZID' :
  5450. return $this->dtzid;
  5451. break;
  5452. case 'UNIQUE_ID' :
  5453. if (empty($this->unique_id))
  5454. $this->unique_id = (isset($_SERVER['SERVER_NAME'])) ? gethostbyname($_SERVER['SERVER_NAME']) : 'localhost';
  5455. return $this->unique_id;
  5456. break;
  5457. }
  5458. }
  5459. /**
  5460. * general component config setting
  5461. *
  5462. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  5463. * @since 2.9.6 - 2011-05-14
  5464. * @param mixed $config
  5465. * @param string $value
  5466. * @param bool $softUpdate
  5467. * @return void
  5468. */
  5469. function setConfig($config, $value = FALSE, $softUpdate = FALSE)
  5470. {
  5471. if (is_array($config))
  5472. {
  5473. foreach ($config as $cKey => $cValue)
  5474. {
  5475. if (FALSE === $this->setConfig($cKey, $cValue, $softUpdate))
  5476. return FALSE;
  5477. }
  5478. return TRUE;
  5479. }
  5480. $res = FALSE;
  5481. switch (strtoupper($config))
  5482. {
  5483. case 'ALLOWEMPTY' :
  5484. $this->allowEmpty = $value;
  5485. $subcfg = array('ALLOWEMPTY' => $value);
  5486. $res = TRUE;
  5487. break;
  5488. case 'FORMAT' :
  5489. $value = trim(strtolower($value));
  5490. $this->format = $value;
  5491. $this->_createFormat();
  5492. $subcfg = array('FORMAT' => $value);
  5493. $res = TRUE;
  5494. break;
  5495. case 'LANGUAGE' :
  5496. // set language for calendar component as defined in [RFC 1766]
  5497. $value = trim($value);
  5498. if (empty($this->language) || ! $softUpdate)
  5499. $this->language = $value;
  5500. $subcfg = array('LANGUAGE' => $value);
  5501. $res = TRUE;
  5502. break;
  5503. case 'NL' :
  5504. case 'NEWLINECHAR' :
  5505. $this->nl = $value;
  5506. $subcfg = array('NL' => $value);
  5507. $res = TRUE;
  5508. break;
  5509. case 'TZID' :
  5510. $this->dtzid = $value;
  5511. $subcfg = array('TZID' => $value);
  5512. $res = TRUE;
  5513. break;
  5514. case 'UNIQUE_ID' :
  5515. $value = trim($value);
  5516. $this->unique_id = $value;
  5517. $subcfg = array('UNIQUE_ID' => $value);
  5518. $res = TRUE;
  5519. break;
  5520. default : // any unvalid config key.. .
  5521. return TRUE;
  5522. }
  5523. if (! $res)
  5524. return FALSE;
  5525. if (isset($subcfg) && ! empty($this->components))
  5526. {
  5527. foreach ($subcfg as $cfgkey => $cfgvalue)
  5528. {
  5529. foreach ($this->components as $cix => $component)
  5530. {
  5531. $res = $component->setConfig($cfgkey, $cfgvalue, $softUpdate);
  5532. if (! $res)
  5533. break 2;
  5534. $this->components[$cix] = $component->copy(); // PHP4 compliant
  5535. }
  5536. }
  5537. }
  5538. return $res;
  5539. }
  5540. /*********************************************************************************/
  5541. /**
  5542. * delete component property value
  5543. *
  5544. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  5545. * @since 2.8.8 - 2011-03-15
  5546. * @param mixed $propName, bool FALSE => X-property
  5547. * @param int $propix, optional, if specific property is wanted in case of multiply occurences
  5548. * @return bool, if successfull delete TRUE
  5549. */
  5550. function deleteProperty($propName = FALSE, $propix = FALSE)
  5551. {
  5552. if ($this->_notExistProp($propName))
  5553. return FALSE;
  5554. $propName = strtoupper($propName);
  5555. if (in_array($propName, array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION',
  5556. 'EXDATE', 'EXRULE', 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME',
  5557. 'X-PROP')))
  5558. {
  5559. if (! $propix)
  5560. $propix = (isset($this->propdelix[$propName]) && ('X-PROP' != $propName)) ? $this->propdelix[$propName] + 2 : 1;
  5561. $this->propdelix[$propName] = -- $propix;
  5562. }
  5563. $return = FALSE;
  5564. switch ($propName)
  5565. {
  5566. case 'ACTION' :
  5567. if (! empty($this->action))
  5568. {
  5569. $this->action = '';
  5570. $return = TRUE;
  5571. }
  5572. break;
  5573. case 'ATTACH' :
  5574. return $this->deletePropertyM($this->attach, $this->propdelix[$propName]);
  5575. break;
  5576. case 'ATTENDEE' :
  5577. return $this->deletePropertyM($this->attendee, $this->propdelix[$propName]);
  5578. break;
  5579. case 'CATEGORIES' :
  5580. return $this->deletePropertyM($this->categories, $this->propdelix[$propName]);
  5581. break;
  5582. case 'CLASS' :
  5583. if (! empty($this->class))
  5584. {
  5585. $this->class = '';
  5586. $return = TRUE;
  5587. }
  5588. break;
  5589. case 'COMMENT' :
  5590. return $this->deletePropertyM($this->comment, $this->propdelix[$propName]);
  5591. break;
  5592. case 'COMPLETED' :
  5593. if (! empty($this->completed))
  5594. {
  5595. $this->completed = '';
  5596. $return = TRUE;
  5597. }
  5598. break;
  5599. case 'CONTACT' :
  5600. return $this->deletePropertyM($this->contact, $this->propdelix[$propName]);
  5601. break;
  5602. case 'CREATED' :
  5603. if (! empty($this->created))
  5604. {
  5605. $this->created = '';
  5606. $return = TRUE;
  5607. }
  5608. break;
  5609. case 'DESCRIPTION' :
  5610. return $this->deletePropertyM($this->description, $this->propdelix[$propName]);
  5611. break;
  5612. case 'DTEND' :
  5613. if (! empty($this->dtend))
  5614. {
  5615. $this->dtend = '';
  5616. $return = TRUE;
  5617. }
  5618. break;
  5619. case 'DTSTAMP' :
  5620. if (in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight')))
  5621. return FALSE;
  5622. if (! empty($this->dtstamp))
  5623. {
  5624. $this->dtstamp = '';
  5625. $return = TRUE;
  5626. }
  5627. break;
  5628. case 'DTSTART' :
  5629. if (! empty($this->dtstart))
  5630. {
  5631. $this->dtstart = '';
  5632. $return = TRUE;
  5633. }
  5634. break;
  5635. case 'DUE' :
  5636. if (! empty($this->due))
  5637. {
  5638. $this->due = '';
  5639. $return = TRUE;
  5640. }
  5641. break;
  5642. case 'DURATION' :
  5643. if (! empty($this->duration))
  5644. {
  5645. $this->duration = '';
  5646. $return = TRUE;
  5647. }
  5648. break;
  5649. case 'EXDATE' :
  5650. return $this->deletePropertyM($this->exdate, $this->propdelix[$propName]);
  5651. break;
  5652. case 'EXRULE' :
  5653. return $this->deletePropertyM($this->exrule, $this->propdelix[$propName]);
  5654. break;
  5655. case 'FREEBUSY' :
  5656. return $this->deletePropertyM($this->freebusy, $this->propdelix[$propName]);
  5657. break;
  5658. case 'GEO' :
  5659. if (! empty($this->geo))
  5660. {
  5661. $this->geo = '';
  5662. $return = TRUE;
  5663. }
  5664. break;
  5665. case 'LAST-MODIFIED' :
  5666. if (! empty($this->lastmodified))
  5667. {
  5668. $this->lastmodified = '';
  5669. $return = TRUE;
  5670. }
  5671. break;
  5672. case 'LOCATION' :
  5673. if (! empty($this->location))
  5674. {
  5675. $this->location = '';
  5676. $return = TRUE;
  5677. }
  5678. break;
  5679. case 'ORGANIZER' :
  5680. if (! empty($this->organizer))
  5681. {
  5682. $this->organizer = '';
  5683. $return = TRUE;
  5684. }
  5685. break;
  5686. case 'PERCENT-COMPLETE' :
  5687. if (! empty($this->percentcomplete))
  5688. {
  5689. $this->percentcomplete = '';
  5690. $return = TRUE;
  5691. }
  5692. break;
  5693. case 'PRIORITY' :
  5694. if (! empty($this->priority))
  5695. {
  5696. $this->priority = '';
  5697. $return = TRUE;
  5698. }
  5699. break;
  5700. case 'RDATE' :
  5701. return $this->deletePropertyM($this->rdate, $this->propdelix[$propName]);
  5702. break;
  5703. case 'RECURRENCE-ID' :
  5704. if (! empty($this->recurrenceid))
  5705. {
  5706. $this->recurrenceid = '';
  5707. $return = TRUE;
  5708. }
  5709. break;
  5710. case 'RELATED-TO' :
  5711. return $this->deletePropertyM($this->relatedto, $this->propdelix[$propName]);
  5712. break;
  5713. case 'REPEAT' :
  5714. if (! empty($this->repeat))
  5715. {
  5716. $this->repeat = '';
  5717. $return = TRUE;
  5718. }
  5719. break;
  5720. case 'REQUEST-STATUS' :
  5721. return $this->deletePropertyM($this->requeststatus, $this->propdelix[$propName]);
  5722. break;
  5723. case 'RESOURCES' :
  5724. return $this->deletePropertyM($this->resources, $this->propdelix[$propName]);
  5725. break;
  5726. case 'RRULE' :
  5727. return $this->deletePropertyM($this->rrule, $this->propdelix[$propName]);
  5728. break;
  5729. case 'SEQUENCE' :
  5730. if (! empty($this->sequence))
  5731. {
  5732. $this->sequence = '';
  5733. $return = TRUE;
  5734. }
  5735. break;
  5736. case 'STATUS' :
  5737. if (! empty($this->status))
  5738. {
  5739. $this->status = '';
  5740. $return = TRUE;
  5741. }
  5742. break;
  5743. case 'SUMMARY' :
  5744. if (! empty($this->summary))
  5745. {
  5746. $this->summary = '';
  5747. $return = TRUE;
  5748. }
  5749. break;
  5750. case 'TRANSP' :
  5751. if (! empty($this->transp))
  5752. {
  5753. $this->transp = '';
  5754. $return = TRUE;
  5755. }
  5756. break;
  5757. case 'TRIGGER' :
  5758. if (! empty($this->trigger))
  5759. {
  5760. $this->trigger = '';
  5761. $return = TRUE;
  5762. }
  5763. break;
  5764. case 'TZID' :
  5765. if (! empty($this->tzid))
  5766. {
  5767. $this->tzid = '';
  5768. $return = TRUE;
  5769. }
  5770. break;
  5771. case 'TZNAME' :
  5772. return $this->deletePropertyM($this->tzname, $this->propdelix[$propName]);
  5773. break;
  5774. case 'TZOFFSETFROM' :
  5775. if (! empty($this->tzoffsetfrom))
  5776. {
  5777. $this->tzoffsetfrom = '';
  5778. $return = TRUE;
  5779. }
  5780. break;
  5781. case 'TZOFFSETTO' :
  5782. if (! empty($this->tzoffsetto))
  5783. {
  5784. $this->tzoffsetto = '';
  5785. $return = TRUE;
  5786. }
  5787. break;
  5788. case 'TZURL' :
  5789. if (! empty($this->tzurl))
  5790. {
  5791. $this->tzurl = '';
  5792. $return = TRUE;
  5793. }
  5794. break;
  5795. case 'UID' :
  5796. if (in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight')))
  5797. return FALSE;
  5798. if (! empty($this->uid))
  5799. {
  5800. $this->uid = '';
  5801. $return = TRUE;
  5802. }
  5803. break;
  5804. case 'URL' :
  5805. if (! empty($this->url))
  5806. {
  5807. $this->url = '';
  5808. $return = TRUE;
  5809. }
  5810. break;
  5811. default :
  5812. $reduced = '';
  5813. if ($propName != 'X-PROP')
  5814. {
  5815. if (! isset($this->xprop[$propName]))
  5816. return FALSE;
  5817. foreach ($this->xprop as $k => $a)
  5818. {
  5819. if (($k != $propName) && ! empty($a))
  5820. $reduced[$k] = $a;
  5821. }
  5822. }
  5823. else
  5824. {
  5825. if (count($this->xprop) <= $propix)
  5826. {
  5827. unset($this->propdelix[$propName]);
  5828. return FALSE;
  5829. }
  5830. $xpropno = 0;
  5831. foreach ($this->xprop as $xpropkey => $xpropvalue)
  5832. {
  5833. if ($propix != $xpropno)
  5834. $reduced[$xpropkey] = $xpropvalue;
  5835. $xpropno ++;
  5836. }
  5837. }
  5838. $this->xprop = $reduced;
  5839. if (empty($this->xprop))
  5840. {
  5841. unset($this->propdelix[$propName]);
  5842. return FALSE;
  5843. }
  5844. return TRUE;
  5845. }
  5846. return $return;
  5847. }
  5848. /*********************************************************************************/
  5849. /**
  5850. * delete component property value, fixing components with multiple occurencies
  5851. *
  5852. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  5853. * @since 2.8.8 - 2011-03-15
  5854. * @param array $multiprop, reference to a component property
  5855. * @param int $propix, reference to removal counter
  5856. * @return bool TRUE
  5857. */
  5858. function deletePropertyM(& $multiprop, & $propix)
  5859. {
  5860. if (isset($multiprop[$propix]))
  5861. unset($multiprop[$propix]);
  5862. if (empty($multiprop))
  5863. {
  5864. $multiprop = '';
  5865. unset($propix);
  5866. return FALSE;
  5867. }
  5868. else
  5869. return TRUE;
  5870. }
  5871. /**
  5872. * get component property value/params
  5873. *
  5874. * if property has multiply values, consequtive function calls are needed
  5875. *
  5876. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  5877. * @since 2.10.1 - 2011-07-16
  5878. * @param string $propName, optional
  5879. * @param int @propix, optional, if specific property is wanted in case of multiply occurences
  5880. * @param bool $inclParam=FALSE
  5881. * @param bool $specform=FALSE
  5882. * @return mixed
  5883. */
  5884. function getProperty($propName = FALSE, $propix = FALSE, $inclParam = FALSE, $specform = FALSE)
  5885. {
  5886. if ($this->_notExistProp($propName))
  5887. return FALSE;
  5888. $propName = ($propName) ? strtoupper($propName) : 'X-PROP';
  5889. if (in_array($propName, array('ATTACH', 'ATTENDEE', 'CATEGORIES', 'COMMENT', 'CONTACT', 'DESCRIPTION',
  5890. 'EXDATE', 'EXRULE', 'FREEBUSY', 'RDATE', 'RELATED-TO', 'RESOURCES', 'RRULE', 'REQUEST-STATUS', 'TZNAME',
  5891. 'X-PROP')))
  5892. {
  5893. if (! $propix)
  5894. $propix = (isset($this->propix[$propName])) ? $this->propix[$propName] + 2 : 1;
  5895. $this->propix[$propName] = -- $propix;
  5896. }
  5897. switch ($propName)
  5898. {
  5899. case 'ACTION' :
  5900. if (! empty($this->action['value']))
  5901. return ($inclParam) ? $this->action : $this->action['value'];
  5902. break;
  5903. case 'ATTACH' :
  5904. $ak = (is_array($this->attach)) ? array_keys($this->attach) : array();
  5905. while (is_array($this->attach) && ! isset($this->attach[$propix]) && (0 < count($this->attach)) && ($propix < end($ak)))
  5906. $propix ++;
  5907. if (! isset($this->attach[$propix]))
  5908. {
  5909. unset($this->propix[$propName]);
  5910. return FALSE;
  5911. }
  5912. return ($inclParam) ? $this->attach[$propix] : $this->attach[$propix]['value'];
  5913. break;
  5914. case 'ATTENDEE' :
  5915. $ak = (is_array($this->attendee)) ? array_keys($this->attendee) : array();
  5916. while (is_array($this->attendee) && ! isset($this->attendee[$propix]) && (0 < count($this->attendee)) && ($propix < end($ak)))
  5917. $propix ++;
  5918. if (! isset($this->attendee[$propix]))
  5919. {
  5920. unset($this->propix[$propName]);
  5921. return FALSE;
  5922. }
  5923. return ($inclParam) ? $this->attendee[$propix] : $this->attendee[$propix]['value'];
  5924. break;
  5925. case 'CATEGORIES' :
  5926. $ak = (is_array($this->categories)) ? array_keys($this->categories) : array();
  5927. while (is_array($this->categories) && ! isset($this->categories[$propix]) && (0 < count($this->categories)) && ($propix < end($ak)))
  5928. $propix ++;
  5929. if (! isset($this->categories[$propix]))
  5930. {
  5931. unset($this->propix[$propName]);
  5932. return FALSE;
  5933. }
  5934. return ($inclParam) ? $this->categories[$propix] : $this->categories[$propix]['value'];
  5935. break;
  5936. case 'CLASS' :
  5937. if (! empty($this->class['value']))
  5938. return ($inclParam) ? $this->class : $this->class['value'];
  5939. break;
  5940. case 'COMMENT' :
  5941. $ak = (is_array($this->comment)) ? array_keys($this->comment) : array();
  5942. while (is_array($this->comment) && ! isset($this->comment[$propix]) && (0 < count($this->comment)) && ($propix < end($ak)))
  5943. $propix ++;
  5944. if (! isset($this->comment[$propix]))
  5945. {
  5946. unset($this->propix[$propName]);
  5947. return FALSE;
  5948. }
  5949. return ($inclParam) ? $this->comment[$propix] : $this->comment[$propix]['value'];
  5950. break;
  5951. case 'COMPLETED' :
  5952. if (! empty($this->completed['value']))
  5953. return ($inclParam) ? $this->completed : $this->completed['value'];
  5954. break;
  5955. case 'CONTACT' :
  5956. $ak = (is_array($this->contact)) ? array_keys($this->contact) : array();
  5957. while (is_array($this->contact) && ! isset($this->contact[$propix]) && (0 < count($this->contact)) && ($propix < end($ak)))
  5958. $propix ++;
  5959. if (! isset($this->contact[$propix]))
  5960. {
  5961. unset($this->propix[$propName]);
  5962. return FALSE;
  5963. }
  5964. return ($inclParam) ? $this->contact[$propix] : $this->contact[$propix]['value'];
  5965. break;
  5966. case 'CREATED' :
  5967. if (! empty($this->created['value']))
  5968. return ($inclParam) ? $this->created : $this->created['value'];
  5969. break;
  5970. case 'DESCRIPTION' :
  5971. $ak = (is_array($this->description)) ? array_keys($this->description) : array();
  5972. while (is_array($this->description) && ! isset($this->description[$propix]) && (0 < count($this->description)) && ($propix < end($ak)))
  5973. $propix ++;
  5974. if (! isset($this->description[$propix]))
  5975. {
  5976. unset($this->propix[$propName]);
  5977. return FALSE;
  5978. }
  5979. return ($inclParam) ? $this->description[$propix] : $this->description[$propix]['value'];
  5980. break;
  5981. case 'DTEND' :
  5982. if (! empty($this->dtend['value']))
  5983. return ($inclParam) ? $this->dtend : $this->dtend['value'];
  5984. break;
  5985. case 'DTSTAMP' :
  5986. if (in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight')))
  5987. return;
  5988. if (! isset($this->dtstamp['value']))
  5989. $this->_makeDtstamp();
  5990. return ($inclParam) ? $this->dtstamp : $this->dtstamp['value'];
  5991. break;
  5992. case 'DTSTART' :
  5993. if (! empty($this->dtstart['value']))
  5994. return ($inclParam) ? $this->dtstart : $this->dtstart['value'];
  5995. break;
  5996. case 'DUE' :
  5997. if (! empty($this->due['value']))
  5998. return ($inclParam) ? $this->due : $this->due['value'];
  5999. break;
  6000. case 'DURATION' :
  6001. if (! isset($this->duration['value']))
  6002. return FALSE;
  6003. $value = ($specform && isset($this->dtstart['value']) && isset($this->duration['value'])) ? iCalUtilityFunctions :: _duration2date($this->dtstart['value'], $this->duration['value']) : $this->duration['value'];
  6004. return ($inclParam) ? array('value' => $value, 'params' => $this->duration['params']) : $value;
  6005. break;
  6006. case 'EXDATE' :
  6007. $ak = (is_array($this->exdate)) ? array_keys($this->exdate) : array();
  6008. while (is_array($this->exdate) && ! isset($this->exdate[$propix]) && (0 < count($this->exdate)) && ($propix < end($ak)))
  6009. $propix ++;
  6010. if (! isset($this->exdate[$propix]))
  6011. {
  6012. unset($this->propix[$propName]);
  6013. return FALSE;
  6014. }
  6015. return ($inclParam) ? $this->exdate[$propix] : $this->exdate[$propix]['value'];
  6016. break;
  6017. case 'EXRULE' :
  6018. $ak = (is_array($this->exrule)) ? array_keys($this->exrule) : array();
  6019. while (is_array($this->exrule) && ! isset($this->exrule[$propix]) && (0 < count($this->exrule)) && ($propix < end($ak)))
  6020. $propix ++;
  6021. if (! isset($this->exrule[$propix]))
  6022. {
  6023. unset($this->propix[$propName]);
  6024. return FALSE;
  6025. }
  6026. return ($inclParam) ? $this->exrule[$propix] : $this->exrule[$propix]['value'];
  6027. break;
  6028. case 'FREEBUSY' :
  6029. $ak = (is_array($this->freebusy)) ? array_keys($this->freebusy) : array();
  6030. while (is_array($this->freebusy) && ! isset($this->freebusy[$propix]) && (0 < count($this->freebusy)) && ($propix < end($ak)))
  6031. $propix ++;
  6032. if (! isset($this->freebusy[$propix]))
  6033. {
  6034. unset($this->propix[$propName]);
  6035. return FALSE;
  6036. }
  6037. return ($inclParam) ? $this->freebusy[$propix] : $this->freebusy[$propix]['value'];
  6038. break;
  6039. case 'GEO' :
  6040. if (! empty($this->geo['value']))
  6041. return ($inclParam) ? $this->geo : $this->geo['value'];
  6042. break;
  6043. case 'LAST-MODIFIED' :
  6044. if (! empty($this->lastmodified['value']))
  6045. return ($inclParam) ? $this->lastmodified : $this->lastmodified['value'];
  6046. break;
  6047. case 'LOCATION' :
  6048. if (! empty($this->location['value']))
  6049. return ($inclParam) ? $this->location : $this->location['value'];
  6050. break;
  6051. case 'ORGANIZER' :
  6052. if (! empty($this->organizer['value']))
  6053. return ($inclParam) ? $this->organizer : $this->organizer['value'];
  6054. break;
  6055. case 'PERCENT-COMPLETE' :
  6056. if (! empty($this->percentcomplete['value']) || (isset($this->percentcomplete['value']) && ('0' == $this->percentcomplete['value'])))
  6057. return ($inclParam) ? $this->percentcomplete : $this->percentcomplete['value'];
  6058. break;
  6059. case 'PRIORITY' :
  6060. if (! empty($this->priority['value']) || (isset($this->priority['value']) && ('0' == $this->priority['value'])))
  6061. return ($inclParam) ? $this->priority : $this->priority['value'];
  6062. break;
  6063. case 'RDATE' :
  6064. $ak = (is_array($this->rdate)) ? array_keys($this->rdate) : array();
  6065. while (is_array($this->rdate) && ! isset($this->rdate[$propix]) && (0 < count($this->rdate)) && ($propix < end($ak)))
  6066. $propix ++;
  6067. if (! isset($this->rdate[$propix]))
  6068. {
  6069. unset($this->propix[$propName]);
  6070. return FALSE;
  6071. }
  6072. return ($inclParam) ? $this->rdate[$propix] : $this->rdate[$propix]['value'];
  6073. break;
  6074. case 'RECURRENCE-ID' :
  6075. if (! empty($this->recurrenceid['value']))
  6076. return ($inclParam) ? $this->recurrenceid : $this->recurrenceid['value'];
  6077. break;
  6078. case 'RELATED-TO' :
  6079. $ak = (is_array($this->relatedto)) ? array_keys($this->relatedto) : array();
  6080. while (is_array($this->relatedto) && ! isset($this->relatedto[$propix]) && (0 < count($this->relatedto)) && ($propix < end($ak)))
  6081. $propix ++;
  6082. if (! isset($this->relatedto[$propix]))
  6083. {
  6084. unset($this->propix[$propName]);
  6085. return FALSE;
  6086. }
  6087. return ($inclParam) ? $this->relatedto[$propix] : $this->relatedto[$propix]['value'];
  6088. break;
  6089. case 'REPEAT' :
  6090. if (! empty($this->repeat['value']) || (isset($this->repeat['value']) && ('0' == $this->repeat['value'])))
  6091. return ($inclParam) ? $this->repeat : $this->repeat['value'];
  6092. break;
  6093. case 'REQUEST-STATUS' :
  6094. $ak = (is_array($this->requeststatus)) ? array_keys($this->requeststatus) : array();
  6095. while (is_array($this->requeststatus) && ! isset($this->requeststatus[$propix]) && (0 < count($this->requeststatus)) && ($propix < end($ak)))
  6096. $propix ++;
  6097. if (! isset($this->requeststatus[$propix]))
  6098. {
  6099. unset($this->propix[$propName]);
  6100. return FALSE;
  6101. }
  6102. return ($inclParam) ? $this->requeststatus[$propix] : $this->requeststatus[$propix]['value'];
  6103. break;
  6104. case 'RESOURCES' :
  6105. $ak = (is_array($this->resources)) ? array_keys($this->resources) : array();
  6106. while (is_array($this->resources) && ! isset($this->resources[$propix]) && (0 < count($this->resources)) && ($propix < end($ak)))
  6107. $propix ++;
  6108. if (! isset($this->resources[$propix]))
  6109. {
  6110. unset($this->propix[$propName]);
  6111. return FALSE;
  6112. }
  6113. return ($inclParam) ? $this->resources[$propix] : $this->resources[$propix]['value'];
  6114. break;
  6115. case 'RRULE' :
  6116. $ak = (is_array($this->rrule)) ? array_keys($this->rrule) : array();
  6117. while (is_array($this->rrule) && ! isset($this->rrule[$propix]) && (0 < count($this->rrule)) && ($propix < end($ak)))
  6118. $propix ++;
  6119. if (! isset($this->rrule[$propix]))
  6120. {
  6121. unset($this->propix[$propName]);
  6122. return FALSE;
  6123. }
  6124. return ($inclParam) ? $this->rrule[$propix] : $this->rrule[$propix]['value'];
  6125. break;
  6126. case 'SEQUENCE' :
  6127. if (isset($this->sequence['value']) && (isset($this->sequence['value']) && ('0' <= $this->sequence['value'])))
  6128. return ($inclParam) ? $this->sequence : $this->sequence['value'];
  6129. break;
  6130. case 'STATUS' :
  6131. if (! empty($this->status['value']))
  6132. return ($inclParam) ? $this->status : $this->status['value'];
  6133. break;
  6134. case 'SUMMARY' :
  6135. if (! empty($this->summary['value']))
  6136. return ($inclParam) ? $this->summary : $this->summary['value'];
  6137. break;
  6138. case 'TRANSP' :
  6139. if (! empty($this->transp['value']))
  6140. return ($inclParam) ? $this->transp : $this->transp['value'];
  6141. break;
  6142. case 'TRIGGER' :
  6143. if (! empty($this->trigger['value']))
  6144. return ($inclParam) ? $this->trigger : $this->trigger['value'];
  6145. break;
  6146. case 'TZID' :
  6147. if (! empty($this->tzid['value']))
  6148. return ($inclParam) ? $this->tzid : $this->tzid['value'];
  6149. break;
  6150. case 'TZNAME' :
  6151. $ak = (is_array($this->tzname)) ? array_keys($this->tzname) : array();
  6152. while (is_array($this->tzname) && ! isset($this->tzname[$propix]) && (0 < count($this->tzname)) && ($propix < end($ak)))
  6153. $propix ++;
  6154. if (! isset($this->tzname[$propix]))
  6155. {
  6156. unset($this->propix[$propName]);
  6157. return FALSE;
  6158. }
  6159. return ($inclParam) ? $this->tzname[$propix] : $this->tzname[$propix]['value'];
  6160. break;
  6161. case 'TZOFFSETFROM' :
  6162. if (! empty($this->tzoffsetfrom['value']))
  6163. return ($inclParam) ? $this->tzoffsetfrom : $this->tzoffsetfrom['value'];
  6164. break;
  6165. case 'TZOFFSETTO' :
  6166. if (! empty($this->tzoffsetto['value']))
  6167. return ($inclParam) ? $this->tzoffsetto : $this->tzoffsetto['value'];
  6168. break;
  6169. case 'TZURL' :
  6170. if (! empty($this->tzurl['value']))
  6171. return ($inclParam) ? $this->tzurl : $this->tzurl['value'];
  6172. break;
  6173. case 'UID' :
  6174. if (in_array($this->objName, array('valarm', 'vtimezone', 'standard', 'daylight')))
  6175. return FALSE;
  6176. if (empty($this->uid['value']))
  6177. $this->_makeuid();
  6178. return ($inclParam) ? $this->uid : $this->uid['value'];
  6179. break;
  6180. case 'URL' :
  6181. if (! empty($this->url['value']))
  6182. return ($inclParam) ? $this->url : $this->url['value'];
  6183. break;
  6184. default :
  6185. if ($propName != 'X-PROP')
  6186. {
  6187. if (! isset($this->xprop[$propName]))
  6188. return FALSE;
  6189. return ($inclParam) ? array($propName, $this->xprop[$propName]) : array($propName,
  6190. $this->xprop[$propName]['value']);
  6191. }
  6192. else
  6193. {
  6194. if (empty($this->xprop))
  6195. return FALSE;
  6196. $xpropno = 0;
  6197. foreach ($this->xprop as $xpropkey => $xpropvalue)
  6198. {
  6199. if ($propix == $xpropno)
  6200. return ($inclParam) ? array($xpropkey, $this->xprop[$xpropkey]) : array($xpropkey,
  6201. $this->xprop[$xpropkey]['value']);
  6202. else
  6203. $xpropno ++;
  6204. }
  6205. return FALSE; // not found ??
  6206. }
  6207. }
  6208. return FALSE;
  6209. }
  6210. /**
  6211. * returns calendar property unique values for 'CATEGORIES', 'RESOURCES' or 'ATTENDEE' and each number of ocurrence
  6212. *
  6213. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6214. * @since 2.8.8 - 2011-04-13
  6215. * @param string $propName
  6216. * @param array $output, incremented result array
  6217. */
  6218. function _getProperties($propName, & $output)
  6219. {
  6220. if (! in_array(strtoupper($propName), array('ATTENDEE', 'CATEGORIES', 'RESOURCES')))
  6221. return output;
  6222. while (FALSE !== ($content = $this->getProperty($propName)))
  6223. {
  6224. if (is_array($content))
  6225. {
  6226. foreach ($content as $part)
  6227. {
  6228. if (FALSE !== strpos($part, ','))
  6229. {
  6230. $part = explode(',', $part);
  6231. foreach ($part as $thePart)
  6232. {
  6233. $thePart = trim($thePart);
  6234. if (! empty($thePart))
  6235. {
  6236. if (! isset($output[$thePart]))
  6237. $output[$thePart] = 1;
  6238. else
  6239. $output[$thePart] += 1;
  6240. }
  6241. }
  6242. }
  6243. else
  6244. {
  6245. $part = trim($part);
  6246. if (! isset($output[$part]))
  6247. $output[$part] = 1;
  6248. else
  6249. $output[$part] += 1;
  6250. }
  6251. }
  6252. }
  6253. elseif (FALSE !== strpos($content, ','))
  6254. {
  6255. $content = explode(',', $content);
  6256. foreach ($content as $thePart)
  6257. {
  6258. $thePart = trim($thePart);
  6259. if (! empty($thePart))
  6260. {
  6261. if (! isset($output[$thePart]))
  6262. $output[$thePart] = 1;
  6263. else
  6264. $output[$thePart] += 1;
  6265. }
  6266. }
  6267. }
  6268. else
  6269. {
  6270. $content = trim($content);
  6271. if (! empty($content))
  6272. {
  6273. if (! isset($output[$content]))
  6274. $output[$content] = 1;
  6275. else
  6276. $output[$content] += 1;
  6277. }
  6278. }
  6279. }
  6280. ksort($output);
  6281. return $output;
  6282. }
  6283. /**
  6284. * general component property setting
  6285. *
  6286. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6287. * @since 2.5.1 - 2008-11-05
  6288. * @param mixed $args variable number of function arguments,
  6289. * first argument is ALWAYS component name,
  6290. * second ALWAYS component value!
  6291. * @return void
  6292. */
  6293. function setProperty()
  6294. {
  6295. $numargs = func_num_args();
  6296. if (1 > $numargs)
  6297. return FALSE;
  6298. $arglist = func_get_args();
  6299. if ($this->_notExistProp($arglist[0]))
  6300. return FALSE;
  6301. if (! $this->getConfig('allowEmpty') && (! isset($arglist[1]) || empty($arglist[1])))
  6302. return FALSE;
  6303. $arglist[0] = strtoupper($arglist[0]);
  6304. for($argix = $numargs; $argix < 12; $argix ++)
  6305. {
  6306. if (! isset($arglist[$argix]))
  6307. $arglist[$argix] = null;
  6308. }
  6309. switch ($arglist[0])
  6310. {
  6311. case 'ACTION' :
  6312. return $this->setAction($arglist[1], $arglist[2]);
  6313. case 'ATTACH' :
  6314. return $this->setAttach($arglist[1], $arglist[2], $arglist[3]);
  6315. case 'ATTENDEE' :
  6316. return $this->setAttendee($arglist[1], $arglist[2], $arglist[3]);
  6317. case 'CATEGORIES' :
  6318. return $this->setCategories($arglist[1], $arglist[2], $arglist[3]);
  6319. case 'CLASS' :
  6320. return $this->setClass($arglist[1], $arglist[2]);
  6321. case 'COMMENT' :
  6322. return $this->setComment($arglist[1], $arglist[2], $arglist[3]);
  6323. case 'COMPLETED' :
  6324. return $this->setCompleted($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7]);
  6325. case 'CONTACT' :
  6326. return $this->setContact($arglist[1], $arglist[2], $arglist[3]);
  6327. case 'CREATED' :
  6328. return $this->setCreated($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7]);
  6329. case 'DESCRIPTION' :
  6330. return $this->setDescription($arglist[1], $arglist[2], $arglist[3]);
  6331. case 'DTEND' :
  6332. return $this->setDtend($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8]);
  6333. case 'DTSTAMP' :
  6334. return $this->setDtstamp($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7]);
  6335. case 'DTSTART' :
  6336. return $this->setDtstart($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8]);
  6337. case 'DUE' :
  6338. return $this->setDue($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8]);
  6339. case 'DURATION' :
  6340. return $this->setDuration($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6]);
  6341. case 'EXDATE' :
  6342. return $this->setExdate($arglist[1], $arglist[2], $arglist[3]);
  6343. case 'EXRULE' :
  6344. return $this->setExrule($arglist[1], $arglist[2], $arglist[3]);
  6345. case 'FREEBUSY' :
  6346. return $this->setFreebusy($arglist[1], $arglist[2], $arglist[3], $arglist[4]);
  6347. case 'GEO' :
  6348. return $this->setGeo($arglist[1], $arglist[2], $arglist[3]);
  6349. case 'LAST-MODIFIED' :
  6350. return $this->setLastModified($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7]);
  6351. case 'LOCATION' :
  6352. return $this->setLocation($arglist[1], $arglist[2]);
  6353. case 'ORGANIZER' :
  6354. return $this->setOrganizer($arglist[1], $arglist[2]);
  6355. case 'PERCENT-COMPLETE' :
  6356. return $this->setPercentComplete($arglist[1], $arglist[2]);
  6357. case 'PRIORITY' :
  6358. return $this->setPriority($arglist[1], $arglist[2]);
  6359. case 'RDATE' :
  6360. return $this->setRdate($arglist[1], $arglist[2], $arglist[3]);
  6361. case 'RECURRENCE-ID' :
  6362. return $this->setRecurrenceid($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5], $arglist[6], $arglist[7], $arglist[8]);
  6363. case 'RELATED-TO' :
  6364. return $this->setRelatedTo($arglist[1], $arglist[2], $arglist[3]);
  6365. case 'REPEAT' :
  6366. return $this->setRepeat($arglist[1], $arglist[2]);
  6367. case 'REQUEST-STATUS' :
  6368. return $this->setRequestStatus($arglist[1], $arglist[2], $arglist[3], $arglist[4], $arglist[5]);
  6369. case 'RESOURCES' :
  6370. return $this->setResources($arglist[1], $arglist[2], $arglist[3]);
  6371. case 'RRULE' :
  6372. return $this->setRrule($arglist[1], $arglist[2], $arglist[3]);
  6373. case 'SEQUENCE' :
  6374. return $this->setSequence($arglist[1], $arglist[2]);
  6375. case 'STATUS' :
  6376. return $this->setStatus($arglist[1], $arglist[2]);
  6377. case 'SUMMARY' :
  6378. return $this->setSummary($arglist[1], $arglist[2]);
  6379. case 'TRANSP' :
  6380. return $this->setTransp($arglist[1], $arglist[2]);
  6381. case 'TRIGGER' :
  6382. 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]);
  6383. case 'TZID' :
  6384. return $this->setTzid($arglist[1], $arglist[2]);
  6385. case 'TZNAME' :
  6386. return $this->setTzname($arglist[1], $arglist[2], $arglist[3]);
  6387. case 'TZOFFSETFROM' :
  6388. return $this->setTzoffsetfrom($arglist[1], $arglist[2]);
  6389. case 'TZOFFSETTO' :
  6390. return $this->setTzoffsetto($arglist[1], $arglist[2]);
  6391. case 'TZURL' :
  6392. return $this->setTzurl($arglist[1], $arglist[2]);
  6393. case 'UID' :
  6394. return $this->setUid($arglist[1], $arglist[2]);
  6395. case 'URL' :
  6396. return $this->setUrl($arglist[1], $arglist[2]);
  6397. default :
  6398. return $this->setXprop($arglist[0], $arglist[1], $arglist[2]);
  6399. }
  6400. return FALSE;
  6401. }
  6402. /*********************************************************************************/
  6403. /**
  6404. * parse component unparsed data into properties
  6405. *
  6406. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6407. * @since 2.10.2 - 2011-07-17
  6408. * @param mixed $unparsedtext, optional, strict rfc2445 formatted, single property string or array of strings
  6409. * @return bool FALSE if error occurs during parsing
  6410. *
  6411. */
  6412. function parse($unparsedtext = null)
  6413. {
  6414. if (! empty($unparsedtext))
  6415. {
  6416. $nl = $this->getConfig('nl');
  6417. if (is_array($unparsedtext))
  6418. $unparsedtext = implode('\n' . $nl, $unparsedtext);
  6419. /* fix line folding */
  6420. $eolchars = array("\r\n", "\n\r", "\n", "\r"); // check all line endings
  6421. $EOLmark = FALSE;
  6422. foreach ($eolchars as $eolchar)
  6423. {
  6424. if (! $EOLmark && (FALSE !== strpos($unparsedtext, $eolchar)))
  6425. {
  6426. $unparsedtext = str_replace($eolchar . " ", '', $unparsedtext);
  6427. $unparsedtext = str_replace($eolchar . "\t", '', $unparsedtext);
  6428. if ($eolchar != $nl)
  6429. $unparsedtext = str_replace($eolchar, $nl, $unparsedtext);
  6430. $EOLmark = TRUE;
  6431. }
  6432. }
  6433. $tmp = explode($nl, $unparsedtext);
  6434. $unparsedtext = array();
  6435. foreach ($tmp as $tmpr)
  6436. if (! empty($tmpr))
  6437. $unparsedtext[] = $tmpr;
  6438. }
  6439. elseif (! isset($this->unparsed))
  6440. $unparsedtext = array();
  6441. else
  6442. $unparsedtext = $this->unparsed;
  6443. $this->unparsed = array();
  6444. $comp = & $this;
  6445. $config = $this->getConfig();
  6446. foreach ($unparsedtext as $line)
  6447. {
  6448. // echo $comp->objName.": $line<br />"; // test ###
  6449. if (in_array(strtoupper(substr($line, 0, 6)), array('END:VA', 'END:DA')))
  6450. $this->components[] = $comp->copy();
  6451. elseif ('END:ST' == strtoupper(substr($line, 0, 6)))
  6452. array_unshift($this->components, $comp->copy());
  6453. elseif ('END:' == strtoupper(substr($line, 0, 4)))
  6454. break;
  6455. elseif ('BEGIN:VALARM' == strtoupper(substr($line, 0, 12)))
  6456. $comp = new valarm($config);
  6457. elseif ('BEGIN:STANDARD' == strtoupper(substr($line, 0, 14)))
  6458. $comp = new vtimezone('standard', $config);
  6459. elseif ('BEGIN:DAYLIGHT' == strtoupper(substr($line, 0, 14)))
  6460. $comp = new vtimezone('daylight', $config);
  6461. elseif ('BEGIN:' == strtoupper(substr($line, 0, 6)))
  6462. continue;
  6463. else
  6464. {
  6465. $comp->unparsed[] = $line;
  6466. // echo $comp->objName.": $line<br />\n"; // test ###
  6467. }
  6468. }
  6469. unset($config);
  6470. // echo $this->objName.'<br />'.var_export( $this->unparsed, TRUE )."<br />\n"; // test ###
  6471. /* concatenate property values spread over several lines */
  6472. $lastix = - 1;
  6473. $propnames = array('action', 'attach', 'attendee', 'categories', 'comment', 'completed', 'contact', 'class',
  6474. 'created', 'description', 'dtend', 'dtstart', 'dtstamp', 'due', 'duration', 'exdate', 'exrule',
  6475. 'freebusy', 'geo', 'last-modified', 'location', 'organizer', 'percent-complete', 'priority', 'rdate',
  6476. 'recurrence-id', 'related-to', 'repeat', 'request-status', 'resources', 'rrule', 'sequence', 'status',
  6477. 'summary', 'transp', 'trigger', 'tzid', 'tzname', 'tzoffsetfrom', 'tzoffsetto', 'tzurl', 'uid', 'url',
  6478. 'x-');
  6479. $proprows = array();
  6480. foreach ($this->unparsed as $line)
  6481. {
  6482. $newProp = FALSE;
  6483. foreach ($propnames as $propname)
  6484. {
  6485. if ($propname == strtolower(substr($line, 0, strlen($propname))))
  6486. {
  6487. $newProp = TRUE;
  6488. break;
  6489. }
  6490. }
  6491. if ($newProp)
  6492. {
  6493. if (- 1 < $lastix)
  6494. $proprows[$lastix] = $proprows[$lastix];
  6495. $newProp = FALSE;
  6496. $lastix ++;
  6497. $proprows[$lastix] = $line;
  6498. }
  6499. else
  6500. $proprows[$lastix] .= '!"#¤%&/()=?' . $line;
  6501. }
  6502. /* parse each property 'line' */
  6503. foreach ($proprows as $line)
  6504. {
  6505. $line = str_replace('!"#¤%&/()=? ', '', $line);
  6506. $line = str_replace('!"#¤%&/()=?', '', $line);
  6507. if ('\n' == substr($line, - 2))
  6508. $line = substr($line, 0, strlen($line) - 2);
  6509. /* get propname, (problem with x-properties, otherwise in previous loop) */
  6510. $cix = $propname = null;
  6511. for($cix = 0, $clen = strlen($line); $cix < $clen; $cix ++)
  6512. {
  6513. if (in_array($line[$cix], array(':', ';')))
  6514. break;
  6515. else
  6516. {
  6517. $propname .= $line[$cix];
  6518. }
  6519. }
  6520. if (('x-' == substr($propname, 0, 2)) || ('X-' == substr($propname, 0, 2)))
  6521. {
  6522. $propname2 = $propname;
  6523. $propname = 'X-';
  6524. }
  6525. /* rest of the line is opt.params and value */
  6526. $line = substr($line, $cix);
  6527. /* separate attributes from value */
  6528. $attr = array();
  6529. $attrix = - 1;
  6530. $clen = strlen($line);
  6531. for($cix = 0; $cix < $clen; $cix ++)
  6532. {
  6533. if ((':' == $line[$cix]) && ('://' != substr($line, $cix, 3)) && (! in_array(strtolower(substr($line, $cix - 3, 4)), array(
  6534. 'fax:', 'cid:', 'sms:', 'tel:', 'urn:'))) && (! in_array(strtolower(substr($line, $cix - 4, 5)), array(
  6535. 'crid:', 'news:', 'pres:'))) && ('mailto:' != strtolower(substr($line, $cix - 6, 7))))
  6536. {
  6537. $attrEnd = TRUE;
  6538. if (($cix < ($clen - 4)) && ctype_digit(substr($line, $cix + 1, 4)))
  6539. { // an URI with a (4pos) portnr??
  6540. for($c2ix = $cix; 3 < $c2ix; $c2ix --)
  6541. {
  6542. if ('://' == substr($line, $c2ix - 2, 3))
  6543. {
  6544. $attrEnd = FALSE;
  6545. break; // an URI with a portnr!!
  6546. }
  6547. }
  6548. }
  6549. if ($attrEnd)
  6550. {
  6551. $line = substr($line, $cix + 1);
  6552. break;
  6553. }
  6554. }
  6555. if (';' == $line[$cix])
  6556. $attr[++ $attrix] = null;
  6557. else
  6558. $attr[$attrix] .= $line[$cix];
  6559. }
  6560. /* make attributes in array format */
  6561. $propattr = array();
  6562. foreach ($attr as $attribute)
  6563. {
  6564. $attrsplit = explode('=', $attribute, 2);
  6565. if (1 < count($attrsplit))
  6566. $propattr[$attrsplit[0]] = $attrsplit[1];
  6567. else
  6568. $propattr[] = $attribute;
  6569. }
  6570. /* call setProperty( $propname.. . */
  6571. switch (strtoupper($propname))
  6572. {
  6573. case 'ATTENDEE' :
  6574. foreach ($propattr as $pix => $attr)
  6575. {
  6576. $attr2 = explode(',', $attr);
  6577. if (1 < count($attr2))
  6578. $propattr[$pix] = $attr2;
  6579. }
  6580. $this->setProperty($propname, $line, $propattr);
  6581. break;
  6582. case 'CATEGORIES' :
  6583. case 'RESOURCES' :
  6584. if (FALSE !== strpos($line, ','))
  6585. {
  6586. $content = explode(',', $line);
  6587. $clen = count($content);
  6588. for($cix = 0; $cix < $clen; $cix ++)
  6589. {
  6590. if ("\\" == substr($content[$cix], - 1))
  6591. {
  6592. $content[$cix] .= ',' . $content[$cix + 1];
  6593. unset($content[$cix + 1]);
  6594. $cix ++;
  6595. }
  6596. }
  6597. if (1 < count($content))
  6598. {
  6599. $content = array_values($content);
  6600. foreach ($content as $cix => $contentPart)
  6601. $content[$cix] = calendarComponent :: _strunrep($contentPart);
  6602. $this->setProperty($propname, $content, $propattr);
  6603. break;
  6604. }
  6605. else
  6606. $line = reset($content);
  6607. }
  6608. case 'X-' :
  6609. $propname = (isset($propname2)) ? $propname2 : $propname;
  6610. case 'COMMENT' :
  6611. case 'CONTACT' :
  6612. case 'DESCRIPTION' :
  6613. case 'LOCATION' :
  6614. case 'SUMMARY' :
  6615. if (empty($line))
  6616. $propattr = null;
  6617. $this->setProperty($propname, calendarComponent :: _strunrep($line), $propattr);
  6618. unset($propname2);
  6619. break;
  6620. case 'REQUEST-STATUS' :
  6621. $values = explode(';', $line, 3);
  6622. $values[1] = (! isset($values[1])) ? null : calendarComponent :: _strunrep($values[1]);
  6623. $values[2] = (! isset($values[2])) ? null : calendarComponent :: _strunrep($values[2]);
  6624. $this->setProperty($propname, $values[0], // statcode
  6625. $values[1], // statdesc
  6626. $values[2], // extdata
  6627. $propattr);
  6628. break;
  6629. case 'FREEBUSY' :
  6630. $fbtype = (isset($propattr['FBTYPE'])) ? $propattr['FBTYPE'] : ''; // force setting default, if missing
  6631. unset($propattr['FBTYPE']);
  6632. $values = explode(',', $line);
  6633. foreach ($values as $vix => $value)
  6634. {
  6635. $value2 = explode('/', $value);
  6636. if (1 < count($value2))
  6637. $values[$vix] = $value2;
  6638. }
  6639. $this->setProperty($propname, $fbtype, $values, $propattr);
  6640. break;
  6641. case 'GEO' :
  6642. $value = explode(';', $line, 2);
  6643. if (2 > count($value))
  6644. $value[1] = null;
  6645. $this->setProperty($propname, $value[0], $value[1], $propattr);
  6646. break;
  6647. case 'EXDATE' :
  6648. $values = (! empty($line)) ? explode(',', $line) : null;
  6649. $this->setProperty($propname, $values, $propattr);
  6650. break;
  6651. case 'RDATE' :
  6652. if (empty($line))
  6653. {
  6654. $this->setProperty($propname, $line, $propattr);
  6655. break;
  6656. }
  6657. $values = explode(',', $line);
  6658. foreach ($values as $vix => $value)
  6659. {
  6660. $value2 = explode('/', $value);
  6661. if (1 < count($value2))
  6662. $values[$vix] = $value2;
  6663. }
  6664. $this->setProperty($propname, $values, $propattr);
  6665. break;
  6666. case 'EXRULE' :
  6667. case 'RRULE' :
  6668. $values = explode(';', $line);
  6669. $recur = array();
  6670. foreach ($values as $value2)
  6671. {
  6672. if (empty($value2))
  6673. continue; // ;-char in ending position ???
  6674. $value3 = explode('=', $value2, 2);
  6675. $rulelabel = strtoupper($value3[0]);
  6676. switch ($rulelabel)
  6677. {
  6678. case 'BYDAY' :
  6679. {
  6680. $value4 = explode(',', $value3[1]);
  6681. if (1 < count($value4))
  6682. {
  6683. foreach ($value4 as $v5ix => $value5)
  6684. {
  6685. $value6 = array();
  6686. $dayno = $dayname = null;
  6687. $value5 = trim((string) $value5);
  6688. if ((ctype_alpha(substr($value5, - 1))) && (ctype_alpha(substr($value5, - 2, 1))))
  6689. {
  6690. $dayname = substr($value5, - 2, 2);
  6691. if (2 < strlen($value5))
  6692. $dayno = substr($value5, 0, (strlen($value5) - 2));
  6693. }
  6694. if ($dayno)
  6695. $value6[] = $dayno;
  6696. if ($dayname)
  6697. $value6['DAY'] = $dayname;
  6698. $value4[$v5ix] = $value6;
  6699. }
  6700. }
  6701. else
  6702. {
  6703. $value4 = array();
  6704. $dayno = $dayname = null;
  6705. $value5 = trim((string) $value3[1]);
  6706. if ((ctype_alpha(substr($value5, - 1))) && (ctype_alpha(substr($value5, - 2, 1))))
  6707. {
  6708. $dayname = substr($value5, - 2, 2);
  6709. if (2 < strlen($value5))
  6710. $dayno = substr($value5, 0, (strlen($value5) - 2));
  6711. }
  6712. if ($dayno)
  6713. $value4[] = $dayno;
  6714. if ($dayname)
  6715. $value4['DAY'] = $dayname;
  6716. }
  6717. $recur[$rulelabel] = $value4;
  6718. break;
  6719. }
  6720. default :
  6721. {
  6722. $value4 = explode(',', $value3[1]);
  6723. if (1 < count($value4))
  6724. $value3[1] = $value4;
  6725. $recur[$rulelabel] = $value3[1];
  6726. break;
  6727. }
  6728. } // end - switch $rulelabel
  6729. } // end - foreach( $values.. .
  6730. $this->setProperty($propname, $recur, $propattr);
  6731. break;
  6732. case 'ACTION' :
  6733. case 'CLASSIFICATION' :
  6734. case 'STATUS' :
  6735. case 'TRANSP' :
  6736. case 'UID' :
  6737. case 'TZID' :
  6738. case 'RELATED-TO' :
  6739. case 'TZNAME' :
  6740. $line = calendarComponent :: _strunrep($line);
  6741. default :
  6742. $this->setProperty($propname, $line, $propattr);
  6743. break;
  6744. } // end switch( $propname.. .
  6745. } // end - foreach( $proprows.. .
  6746. unset($unparsedtext, $this->unparsed, $proprows);
  6747. if (isset($this->components) && is_array($this->components) && (0 < count($this->components)))
  6748. {
  6749. $ckeys = array_keys($this->components);
  6750. foreach ($ckeys as $ckey)
  6751. {
  6752. if (! empty($this->components[$ckey]) && ! empty($this->components[$ckey]->unparsed))
  6753. {
  6754. $this->components[$ckey]->parse();
  6755. }
  6756. }
  6757. }
  6758. return TRUE;
  6759. }
  6760. /*********************************************************************************/
  6761. /*********************************************************************************/
  6762. /**
  6763. * return a copy of this component
  6764. *
  6765. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6766. * @since 2.8.8 - 2011-03-15
  6767. * @return object
  6768. */
  6769. function copy()
  6770. {
  6771. $serialized_contents = serialize($this);
  6772. $copy = unserialize($serialized_contents);
  6773. return $copy;
  6774. }
  6775. /*********************************************************************************/
  6776. /*********************************************************************************/
  6777. /**
  6778. * delete calendar subcomponent from component container
  6779. *
  6780. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6781. * @since 2.8.8 - 2011-03-15
  6782. * @param mixed $arg1 ordno / component type / component uid
  6783. * @param mixed $arg2 optional, ordno if arg1 = component type
  6784. * @return void
  6785. */
  6786. function deleteComponent($arg1, $arg2 = FALSE)
  6787. {
  6788. if (! isset($this->components))
  6789. return FALSE;
  6790. $argType = $index = null;
  6791. if (ctype_digit((string) $arg1))
  6792. {
  6793. $argType = 'INDEX';
  6794. $index = (int) $arg1 - 1;
  6795. }
  6796. elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@')))
  6797. {
  6798. $argType = strtolower($arg1);
  6799. $index = (! empty($arg2) && ctype_digit((string) $arg2)) ? ((int) $arg2 - 1) : 0;
  6800. }
  6801. $cix2dC = 0;
  6802. foreach ($this->components as $cix => $component)
  6803. {
  6804. if (empty($component))
  6805. continue;
  6806. if (('INDEX' == $argType) && ($index == $cix))
  6807. {
  6808. unset($this->components[$cix]);
  6809. return TRUE;
  6810. }
  6811. elseif ($argType == $component->objName)
  6812. {
  6813. if ($index == $cix2dC)
  6814. {
  6815. unset($this->components[$cix]);
  6816. return TRUE;
  6817. }
  6818. $cix2dC ++;
  6819. }
  6820. elseif (! $argType && ($arg1 == $component->getProperty('uid')))
  6821. {
  6822. unset($this->components[$cix]);
  6823. return TRUE;
  6824. }
  6825. }
  6826. return FALSE;
  6827. }
  6828. /**
  6829. * get calendar component subcomponent from component container
  6830. *
  6831. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6832. * @since 2.8.8 - 2011-03-15
  6833. * @param mixed $arg1 optional, ordno/component type/ component uid
  6834. * @param mixed $arg2 optional, ordno if arg1 = component type
  6835. * @return object
  6836. */
  6837. function getComponent($arg1 = FALSE, $arg2 = FALSE)
  6838. {
  6839. if (! isset($this->components))
  6840. return FALSE;
  6841. $index = $argType = null;
  6842. if (! $arg1)
  6843. {
  6844. $argType = 'INDEX';
  6845. $index = $this->compix['INDEX'] = (isset($this->compix['INDEX'])) ? $this->compix['INDEX'] + 1 : 1;
  6846. }
  6847. elseif (ctype_digit((string) $arg1))
  6848. {
  6849. $argType = 'INDEX';
  6850. $index = (int) $arg1;
  6851. unset($this->compix);
  6852. }
  6853. elseif ((strlen($arg1) <= strlen('vfreebusy')) && (FALSE === strpos($arg1, '@')))
  6854. {
  6855. unset($this->compix['INDEX']);
  6856. $argType = strtolower($arg1);
  6857. if (! $arg2)
  6858. $index = $this->compix[$argType] = (isset($this->compix[$argType])) ? $this->compix[$argType] + 1 : 1;
  6859. else
  6860. $index = (int) $arg2;
  6861. }
  6862. $index -= 1;
  6863. $ckeys = array_keys($this->components);
  6864. if (! empty($index) && ($index > end($ckeys)))
  6865. return FALSE;
  6866. $cix2gC = 0;
  6867. foreach ($this->components as $cix => $component)
  6868. {
  6869. if (empty($component))
  6870. continue;
  6871. if (('INDEX' == $argType) && ($index == $cix))
  6872. return $component->copy();
  6873. elseif ($argType == $component->objName)
  6874. {
  6875. if ($index == $cix2gC)
  6876. return $component->copy();
  6877. $cix2gC ++;
  6878. }
  6879. elseif (! $argType && ($arg1 == $component->getProperty('uid')))
  6880. return $component->copy();
  6881. }
  6882. /* not found.. . */
  6883. unset($this->compix);
  6884. return false;
  6885. }
  6886. /**
  6887. * add calendar component as subcomponent to container for subcomponents
  6888. *
  6889. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6890. * @since 1.x.x - 2007-04-24
  6891. * @param object $component calendar component
  6892. * @return void
  6893. */
  6894. function addSubComponent($component)
  6895. {
  6896. $this->setComponent($component);
  6897. }
  6898. /**
  6899. * create new calendar component subcomponent, already included within component
  6900. *
  6901. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6902. * @since 2.6.33 - 2011-01-03
  6903. * @param string $compType subcomponent type
  6904. * @return object (reference)
  6905. */
  6906. function &newComponent($compType)
  6907. {
  6908. $config = $this->getConfig();
  6909. $keys = array_keys($this->components);
  6910. $ix = end($keys) + 1;
  6911. switch (strtoupper($compType))
  6912. {
  6913. case 'ALARM' :
  6914. case 'VALARM' :
  6915. $this->components[$ix] = new valarm($config);
  6916. break;
  6917. case 'STANDARD' :
  6918. array_unshift($this->components, new vtimezone('STANDARD', $config));
  6919. $ix = 0;
  6920. break;
  6921. case 'DAYLIGHT' :
  6922. $this->components[$ix] = new vtimezone('DAYLIGHT', $config);
  6923. break;
  6924. default :
  6925. return FALSE;
  6926. }
  6927. return $this->components[$ix];
  6928. }
  6929. /**
  6930. * add calendar component as subcomponent to container for subcomponents
  6931. *
  6932. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  6933. * @since 2.8.8 - 2011-03-15
  6934. * @param object $component calendar component
  6935. * @param mixed $arg1 optional, ordno/component type/ component uid
  6936. * @param mixed $arg2 optional, ordno if arg1 = component type
  6937. * @return bool
  6938. */
  6939. function setComponent($component, $arg1 = FALSE, $arg2 = FALSE)
  6940. {
  6941. if (! isset($this->components))
  6942. return FALSE;
  6943. $component->setConfig($this->getConfig(), FALSE, TRUE);
  6944. if (! in_array($component->objName, array('valarm', 'vtimezone', 'standard', 'daylight')))
  6945. {
  6946. /* make sure dtstamp and uid is set */
  6947. $dummy = $component->getProperty('dtstamp');
  6948. $dummy = $component->getProperty('uid');
  6949. }
  6950. if (! $arg1)
  6951. { // plain insert, last in chain
  6952. $this->components[] = $component->copy();
  6953. return TRUE;
  6954. }
  6955. $argType = $index = null;
  6956. if (ctype_digit((string) $arg1))
  6957. { // index insert/replace
  6958. $argType = 'INDEX';
  6959. $index = (int) $arg1 - 1;
  6960. }
  6961. elseif (in_array(strtolower($arg1), array('vevent', 'vtodo', 'vjournal', 'vfreebusy', 'valarm', 'vtimezone')))
  6962. {
  6963. $argType = strtolower($arg1);
  6964. $index = (ctype_digit((string) $arg2)) ? ((int) $arg2) - 1 : 0;
  6965. }
  6966. // else if arg1 is set, arg1 must be an UID
  6967. $cix2sC = 0;
  6968. foreach ($this->components as $cix => $component2)
  6969. {
  6970. if (empty($component2))
  6971. continue;
  6972. if (('INDEX' == $argType) && ($index == $cix))
  6973. { // index insert/replace
  6974. $this->components[$cix] = $component->copy();
  6975. return TRUE;
  6976. }
  6977. elseif ($argType == $component2->objName)
  6978. { // component Type index insert/replace
  6979. if ($index == $cix2sC)
  6980. {
  6981. $this->components[$cix] = $component->copy();
  6982. return TRUE;
  6983. }
  6984. $cix2sC ++;
  6985. }
  6986. elseif (! $argType && ($arg1 == $component2->getProperty('uid')))
  6987. { // UID insert/replace
  6988. $this->components[$cix] = $component->copy();
  6989. return TRUE;
  6990. }
  6991. }
  6992. /* arg1=index and not found.. . insert at index .. .*/
  6993. if ('INDEX' == $argType)
  6994. {
  6995. $this->components[$index] = $component->copy();
  6996. ksort($this->components, SORT_NUMERIC);
  6997. }
  6998. else /* not found.. . insert last in chain anyway .. .*/
  6999. $this->components[] = $component->copy();
  7000. return TRUE;
  7001. }
  7002. /**
  7003. * creates formatted output for subcomponents
  7004. *
  7005. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7006. * @since 2.6.27 - 2010-12-12
  7007. * @return string
  7008. */
  7009. function createSubComponent()
  7010. {
  7011. $output = null;
  7012. foreach ($this->components as $component)
  7013. {
  7014. if (empty($component))
  7015. continue;
  7016. $component->setConfig($this->getConfig(), FALSE, TRUE);
  7017. $output .= $component->createComponent($this->xcaldecl);
  7018. }
  7019. return $output;
  7020. }
  7021. /********************************************************************************/
  7022. /**
  7023. * break lines at pos 75
  7024. *
  7025. * Lines of text SHOULD NOT be longer than 75 octets, excluding the line
  7026. * break. Long content lines SHOULD be split into a multiple line
  7027. * representations using a line "folding" technique. That is, a long
  7028. * line can be split between any two characters by inserting a CRLF
  7029. * immediately followed by a single linear white space character (i.e.,
  7030. * SPACE, US-ASCII decimal 32 or HTAB, US-ASCII decimal 9). Any sequence
  7031. * of CRLF followed immediately by a single linear white space character
  7032. * is ignored (i.e., removed) when processing the content type.
  7033. *
  7034. * Edited 2007-08-26 by Anders Litzell, anders@litzell.se to fix bug where
  7035. * the reserved expression "\n" in the arg $string could be broken up by the
  7036. * folding of lines, causing ambiguity in the return string.
  7037. * Fix uses var $breakAtChar=75 and breaks the line at $breakAtChar-1 if need be.
  7038. *
  7039. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7040. * @since 2.6.13 - 2010-12-06
  7041. * @param string $value
  7042. * @return string
  7043. */
  7044. function _size75($string)
  7045. {
  7046. $tmp = $string;
  7047. $string = null;
  7048. /* if PHP is config with mb_string.. . */
  7049. if (defined(MB_OVERLOAD_STRING))
  7050. {
  7051. $strlen = mb_strlen($tmp);
  7052. while ($strlen > 75)
  7053. {
  7054. $breakAtChar = 75;
  7055. if (substr($tmp, ($breakAtChar - 1), strlen('\n')) == '\n')
  7056. $breakAtChar = $breakAtChar - 1;
  7057. $string .= mb_substr($tmp, 0, $breakAtChar);
  7058. if ('\n' == substr($string, (0 - strlen('\n'))))
  7059. $string = substr($string, 0, (strlen($string) - strlen('\n')));
  7060. if ($this->nl != mb_substr($string, (0 - strlen($this->nl))))
  7061. $string .= $this->nl;
  7062. $tmp = ' ' . mb_substr($tmp, $breakAtChar);
  7063. $strlen = mb_strlen($tmp);
  7064. } // end while
  7065. if (0 < $strlen)
  7066. {
  7067. $string .= $tmp; // the rest
  7068. if ('\n' == substr($string, (0 - strlen('\n'))))
  7069. $string = substr($string, 0, (strlen($string) - strlen('\n')));
  7070. if ($this->nl != mb_substr($string, (0 - strlen($this->nl))))
  7071. $string .= $this->nl;
  7072. }
  7073. return $string;
  7074. }
  7075. /* if PHP is not config with mb_string.. . */
  7076. $eolcharlen = strlen('\n');
  7077. while (TRUE)
  7078. {
  7079. $bytecnt = strlen($tmp);
  7080. $charCnt = $ix = 0;
  7081. for($ix = 0; $ix < $bytecnt; $ix ++)
  7082. {
  7083. if ((73 < $charCnt) && ('\n' == substr($tmp, $ix, $eolcharlen)))
  7084. {
  7085. $ix += $eolcharlen;
  7086. break; // break when '\n' and eol
  7087. }
  7088. elseif (74 < $charCnt)
  7089. break; // always break for-loop here
  7090. else
  7091. {
  7092. $byte = ord($tmp[$ix]);
  7093. if ($byte <= 127)
  7094. { // add a one byte character
  7095. $string .= substr($tmp, $ix, 1);
  7096. $charCnt += 1;
  7097. }
  7098. else
  7099. if ($byte >= 194 && $byte <= 223)
  7100. { // start byte in two byte character
  7101. $string .= substr($tmp, $ix, 2); // add a two bytes character
  7102. $charCnt += 1;
  7103. }
  7104. else
  7105. if ($byte >= 224 && $byte <= 239)
  7106. { // start byte in three bytes character
  7107. $string .= substr($tmp, $ix, 3); // add a three bytes character
  7108. $charCnt += 1;
  7109. }
  7110. else
  7111. if ($byte >= 240 && $byte <= 244)
  7112. { // start byte in four bytes character
  7113. $string .= substr($tmp, $ix, 4); // add a four bytes character
  7114. $charCnt += 1;
  7115. }
  7116. }
  7117. } // end for
  7118. if ('\n' == substr($string, (0 - strlen('\n'))))
  7119. $string = substr($string, 0, (strlen($string) - strlen('\n')));
  7120. if ($this->nl != substr($string, (0 - strlen($this->nl))))
  7121. $string .= $this->nl;
  7122. $tmp = substr($tmp, $ix);
  7123. if (empty($tmp))
  7124. break; // while-loop breakes here
  7125. else
  7126. $tmp = ' ' . $tmp;
  7127. } // end while
  7128. if (! empty($tmp))
  7129. {
  7130. if ('\n' == substr($string, (0 - strlen('\n'))))
  7131. $string = substr($string, 0, (strlen($string) - strlen('\n'))) . $this->nl;
  7132. if ($this->nl != substr($string, (0 - strlen($this->nl))))
  7133. $string .= $this->nl;
  7134. }
  7135. return $string;
  7136. }
  7137. /**
  7138. * special characters management output
  7139. *
  7140. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7141. * @since 2.6.15 - 2010-09-24
  7142. * @param string $string
  7143. * @return string
  7144. */
  7145. function _strrep($string)
  7146. {
  7147. switch ($this->format)
  7148. {
  7149. case 'xcal' :
  7150. $string = str_replace('\n', $this->nl, $string);
  7151. $string = htmlspecialchars(strip_tags(stripslashes(urldecode($string))));
  7152. break;
  7153. default :
  7154. $pos = 0;
  7155. $specChars = array('n', 'N', 'r', ',', ';');
  7156. while ($pos <= strlen($string))
  7157. {
  7158. $pos = strpos($string, "\\", $pos);
  7159. if (FALSE === $pos)
  7160. break;
  7161. if (! in_array(substr($string, $pos, 1), $specChars))
  7162. {
  7163. $string = substr($string, 0, $pos) . "\\" . substr($string, ($pos + 1));
  7164. $pos += 1;
  7165. }
  7166. $pos += 1;
  7167. }
  7168. if (FALSE !== strpos($string, '"'))
  7169. $string = str_replace('"', "'", $string);
  7170. if (FALSE !== strpos($string, ','))
  7171. $string = str_replace(',', '\,', $string);
  7172. if (FALSE !== strpos($string, ';'))
  7173. $string = str_replace(';', '\;', $string);
  7174. if (FALSE !== strpos($string, "\r\n"))
  7175. $string = str_replace("\r\n", '\n', $string);
  7176. elseif (FALSE !== strpos($string, "\r"))
  7177. $string = str_replace("\r", '\n', $string);
  7178. elseif (FALSE !== strpos($string, "\n"))
  7179. $string = str_replace("\n", '\n', $string);
  7180. if (FALSE !== strpos($string, '\N'))
  7181. $string = str_replace('\N', '\n', $string);
  7182. // if( FALSE !== strpos( $string, $this->nl ))
  7183. $string = str_replace($this->nl, '\n', $string);
  7184. break;
  7185. }
  7186. return $string;
  7187. }
  7188. /**
  7189. * special characters management input (from iCal file)
  7190. *
  7191. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7192. * @since 2.6.22 - 2010-10-17
  7193. * @param string $string
  7194. * @return string
  7195. */
  7196. static function _strunrep($string)
  7197. {
  7198. $string = str_replace('\\\\', '\\', $string);
  7199. $string = str_replace('\,', ',', $string);
  7200. $string = str_replace('\;', ';', $string);
  7201. // $string = str_replace( '\n', $this->nl, $string); // ??
  7202. return $string;
  7203. }
  7204. }
  7205. /*********************************************************************************/
  7206. /*********************************************************************************/
  7207. /**
  7208. * class for calendar component VEVENT
  7209. *
  7210. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7211. * @since 2.5.1 - 2008-10-12
  7212. */
  7213. class vevent extends calendarComponent
  7214. {
  7215. var $attach;
  7216. var $attendee;
  7217. var $categories;
  7218. var $comment;
  7219. var $contact;
  7220. var $class;
  7221. var $created;
  7222. var $description;
  7223. var $dtend;
  7224. var $dtstart;
  7225. var $duration;
  7226. var $exdate;
  7227. var $exrule;
  7228. var $geo;
  7229. var $lastmodified;
  7230. var $location;
  7231. var $organizer;
  7232. var $priority;
  7233. var $rdate;
  7234. var $recurrenceid;
  7235. var $relatedto;
  7236. var $requeststatus;
  7237. var $resources;
  7238. var $rrule;
  7239. var $sequence;
  7240. var $status;
  7241. var $summary;
  7242. var $transp;
  7243. var $url;
  7244. var $xprop;
  7245. // component subcomponents container
  7246. var $components;
  7247. /**
  7248. * constructor for calendar component VEVENT object
  7249. *
  7250. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7251. * @since 2.8.2 - 2011-05-01
  7252. * @param array $config
  7253. * @return void
  7254. */
  7255. function vevent($config = array())
  7256. {
  7257. $this->calendarComponent();
  7258. $this->attach = '';
  7259. $this->attendee = '';
  7260. $this->categories = '';
  7261. $this->class = '';
  7262. $this->comment = '';
  7263. $this->contact = '';
  7264. $this->created = '';
  7265. $this->description = '';
  7266. $this->dtstart = '';
  7267. $this->dtend = '';
  7268. $this->duration = '';
  7269. $this->exdate = '';
  7270. $this->exrule = '';
  7271. $this->geo = '';
  7272. $this->lastmodified = '';
  7273. $this->location = '';
  7274. $this->organizer = '';
  7275. $this->priority = '';
  7276. $this->rdate = '';
  7277. $this->recurrenceid = '';
  7278. $this->relatedto = '';
  7279. $this->requeststatus = '';
  7280. $this->resources = '';
  7281. $this->rrule = '';
  7282. $this->sequence = '';
  7283. $this->status = '';
  7284. $this->summary = '';
  7285. $this->transp = '';
  7286. $this->url = '';
  7287. $this->xprop = '';
  7288. $this->components = array();
  7289. if (defined('ICAL_LANG') && ! isset($config['language']))
  7290. $config['language'] = ICAL_LANG;
  7291. if (! isset($config['allowEmpty']))
  7292. $config['allowEmpty'] = TRUE;
  7293. if (! isset($config['nl']))
  7294. $config['nl'] = "\r\n";
  7295. if (! isset($config['format']))
  7296. $config['format'] = 'iCal';
  7297. if (! isset($config['delimiter']))
  7298. $config['delimiter'] = DIRECTORY_SEPARATOR;
  7299. $this->setConfig($config);
  7300. }
  7301. /**
  7302. * create formatted output for calendar component VEVENT object instance
  7303. *
  7304. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7305. * @since 2.5.1 - 2008-11-07
  7306. * @param array $xcaldecl
  7307. * @return string
  7308. */
  7309. function createComponent(&$xcaldecl)
  7310. {
  7311. $objectname = $this->_createFormat();
  7312. $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl;
  7313. $component .= $this->createUid();
  7314. $component .= $this->createDtstamp();
  7315. $component .= $this->createAttach();
  7316. $component .= $this->createAttendee();
  7317. $component .= $this->createCategories();
  7318. $component .= $this->createComment();
  7319. $component .= $this->createContact();
  7320. $component .= $this->createClass();
  7321. $component .= $this->createCreated();
  7322. $component .= $this->createDescription();
  7323. $component .= $this->createDtstart();
  7324. $component .= $this->createDtend();
  7325. $component .= $this->createDuration();
  7326. $component .= $this->createExdate();
  7327. $component .= $this->createExrule();
  7328. $component .= $this->createGeo();
  7329. $component .= $this->createLastModified();
  7330. $component .= $this->createLocation();
  7331. $component .= $this->createOrganizer();
  7332. $component .= $this->createPriority();
  7333. $component .= $this->createRdate();
  7334. $component .= $this->createRrule();
  7335. $component .= $this->createRelatedTo();
  7336. $component .= $this->createRequestStatus();
  7337. $component .= $this->createRecurrenceid();
  7338. $component .= $this->createResources();
  7339. $component .= $this->createSequence();
  7340. $component .= $this->createStatus();
  7341. $component .= $this->createSummary();
  7342. $component .= $this->createTransp();
  7343. $component .= $this->createUrl();
  7344. $component .= $this->createXprop();
  7345. $component .= $this->createSubComponent();
  7346. $component .= $this->componentEnd1 . $objectname . $this->componentEnd2;
  7347. if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl)))
  7348. {
  7349. foreach ($this->xcaldecl as $localxcaldecl)
  7350. $xcaldecl[] = $localxcaldecl;
  7351. }
  7352. return $component;
  7353. }
  7354. }
  7355. /*********************************************************************************/
  7356. /*********************************************************************************/
  7357. /**
  7358. * class for calendar component VTODO
  7359. *
  7360. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7361. * @since 2.5.1 - 2008-10-12
  7362. */
  7363. class vtodo extends calendarComponent
  7364. {
  7365. var $attach;
  7366. var $attendee;
  7367. var $categories;
  7368. var $comment;
  7369. var $completed;
  7370. var $contact;
  7371. var $class;
  7372. var $created;
  7373. var $description;
  7374. var $dtstart;
  7375. var $due;
  7376. var $duration;
  7377. var $exdate;
  7378. var $exrule;
  7379. var $geo;
  7380. var $lastmodified;
  7381. var $location;
  7382. var $organizer;
  7383. var $percentcomplete;
  7384. var $priority;
  7385. var $rdate;
  7386. var $recurrenceid;
  7387. var $relatedto;
  7388. var $requeststatus;
  7389. var $resources;
  7390. var $rrule;
  7391. var $sequence;
  7392. var $status;
  7393. var $summary;
  7394. var $url;
  7395. var $xprop;
  7396. // component subcomponents container
  7397. var $components;
  7398. /**
  7399. * constructor for calendar component VTODO object
  7400. *
  7401. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7402. * @since 2.8.2 - 2011-05-01
  7403. * @param array $config
  7404. * @return void
  7405. */
  7406. function vtodo($config = array())
  7407. {
  7408. $this->calendarComponent();
  7409. $this->attach = '';
  7410. $this->attendee = '';
  7411. $this->categories = '';
  7412. $this->class = '';
  7413. $this->comment = '';
  7414. $this->completed = '';
  7415. $this->contact = '';
  7416. $this->created = '';
  7417. $this->description = '';
  7418. $this->dtstart = '';
  7419. $this->due = '';
  7420. $this->duration = '';
  7421. $this->exdate = '';
  7422. $this->exrule = '';
  7423. $this->geo = '';
  7424. $this->lastmodified = '';
  7425. $this->location = '';
  7426. $this->organizer = '';
  7427. $this->percentcomplete = '';
  7428. $this->priority = '';
  7429. $this->rdate = '';
  7430. $this->recurrenceid = '';
  7431. $this->relatedto = '';
  7432. $this->requeststatus = '';
  7433. $this->resources = '';
  7434. $this->rrule = '';
  7435. $this->sequence = '';
  7436. $this->status = '';
  7437. $this->summary = '';
  7438. $this->url = '';
  7439. $this->xprop = '';
  7440. $this->components = array();
  7441. if (defined('ICAL_LANG') && ! isset($config['language']))
  7442. $config['language'] = ICAL_LANG;
  7443. if (! isset($config['allowEmpty']))
  7444. $config['allowEmpty'] = TRUE;
  7445. if (! isset($config['nl']))
  7446. $config['nl'] = "\r\n";
  7447. if (! isset($config['format']))
  7448. $config['format'] = 'iCal';
  7449. if (! isset($config['delimiter']))
  7450. $config['delimiter'] = DIRECTORY_SEPARATOR;
  7451. $this->setConfig($config);
  7452. }
  7453. /**
  7454. * create formatted output for calendar component VTODO object instance
  7455. *
  7456. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7457. * @since 2.5.1 - 2008-11-07
  7458. * @param array $xcaldecl
  7459. * @return string
  7460. */
  7461. function createComponent(&$xcaldecl)
  7462. {
  7463. $objectname = $this->_createFormat();
  7464. $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl;
  7465. $component .= $this->createUid();
  7466. $component .= $this->createDtstamp();
  7467. $component .= $this->createAttach();
  7468. $component .= $this->createAttendee();
  7469. $component .= $this->createCategories();
  7470. $component .= $this->createClass();
  7471. $component .= $this->createComment();
  7472. $component .= $this->createCompleted();
  7473. $component .= $this->createContact();
  7474. $component .= $this->createCreated();
  7475. $component .= $this->createDescription();
  7476. $component .= $this->createDtstart();
  7477. $component .= $this->createDue();
  7478. $component .= $this->createDuration();
  7479. $component .= $this->createExdate();
  7480. $component .= $this->createExrule();
  7481. $component .= $this->createGeo();
  7482. $component .= $this->createLastModified();
  7483. $component .= $this->createLocation();
  7484. $component .= $this->createOrganizer();
  7485. $component .= $this->createPercentComplete();
  7486. $component .= $this->createPriority();
  7487. $component .= $this->createRdate();
  7488. $component .= $this->createRelatedTo();
  7489. $component .= $this->createRequestStatus();
  7490. $component .= $this->createRecurrenceid();
  7491. $component .= $this->createResources();
  7492. $component .= $this->createRrule();
  7493. $component .= $this->createSequence();
  7494. $component .= $this->createStatus();
  7495. $component .= $this->createSummary();
  7496. $component .= $this->createUrl();
  7497. $component .= $this->createXprop();
  7498. $component .= $this->createSubComponent();
  7499. $component .= $this->componentEnd1 . $objectname . $this->componentEnd2;
  7500. if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl)))
  7501. {
  7502. foreach ($this->xcaldecl as $localxcaldecl)
  7503. $xcaldecl[] = $localxcaldecl;
  7504. }
  7505. return $component;
  7506. }
  7507. }
  7508. /*********************************************************************************/
  7509. /*********************************************************************************/
  7510. /**
  7511. * class for calendar component VJOURNAL
  7512. *
  7513. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7514. * @since 2.5.1 - 2008-10-12
  7515. */
  7516. class vjournal extends calendarComponent
  7517. {
  7518. var $attach;
  7519. var $attendee;
  7520. var $categories;
  7521. var $comment;
  7522. var $contact;
  7523. var $class;
  7524. var $created;
  7525. var $description;
  7526. var $dtstart;
  7527. var $exdate;
  7528. var $exrule;
  7529. var $lastmodified;
  7530. var $organizer;
  7531. var $rdate;
  7532. var $recurrenceid;
  7533. var $relatedto;
  7534. var $requeststatus;
  7535. var $rrule;
  7536. var $sequence;
  7537. var $status;
  7538. var $summary;
  7539. var $url;
  7540. var $xprop;
  7541. /**
  7542. * constructor for calendar component VJOURNAL object
  7543. *
  7544. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7545. * @since 2.8.2 - 2011-05-01
  7546. * @param array $config
  7547. * @return void
  7548. */
  7549. function vjournal($config = array())
  7550. {
  7551. $this->calendarComponent();
  7552. $this->attach = '';
  7553. $this->attendee = '';
  7554. $this->categories = '';
  7555. $this->class = '';
  7556. $this->comment = '';
  7557. $this->contact = '';
  7558. $this->created = '';
  7559. $this->description = '';
  7560. $this->dtstart = '';
  7561. $this->exdate = '';
  7562. $this->exrule = '';
  7563. $this->lastmodified = '';
  7564. $this->organizer = '';
  7565. $this->rdate = '';
  7566. $this->recurrenceid = '';
  7567. $this->relatedto = '';
  7568. $this->requeststatus = '';
  7569. $this->rrule = '';
  7570. $this->sequence = '';
  7571. $this->status = '';
  7572. $this->summary = '';
  7573. $this->url = '';
  7574. $this->xprop = '';
  7575. if (defined('ICAL_LANG') && ! isset($config['language']))
  7576. $config['language'] = ICAL_LANG;
  7577. if (! isset($config['allowEmpty']))
  7578. $config['allowEmpty'] = TRUE;
  7579. if (! isset($config['nl']))
  7580. $config['nl'] = "\r\n";
  7581. if (! isset($config['format']))
  7582. $config['format'] = 'iCal';
  7583. if (! isset($config['delimiter']))
  7584. $config['delimiter'] = DIRECTORY_SEPARATOR;
  7585. $this->setConfig($config);
  7586. }
  7587. /**
  7588. * create formatted output for calendar component VJOURNAL object instance
  7589. *
  7590. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7591. * @since 2.5.1 - 2008-10-12
  7592. * @param array $xcaldecl
  7593. * @return string
  7594. */
  7595. function createComponent(&$xcaldecl)
  7596. {
  7597. $objectname = $this->_createFormat();
  7598. $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl;
  7599. $component .= $this->createUid();
  7600. $component .= $this->createDtstamp();
  7601. $component .= $this->createAttach();
  7602. $component .= $this->createAttendee();
  7603. $component .= $this->createCategories();
  7604. $component .= $this->createClass();
  7605. $component .= $this->createComment();
  7606. $component .= $this->createContact();
  7607. $component .= $this->createCreated();
  7608. $component .= $this->createDescription();
  7609. $component .= $this->createDtstart();
  7610. $component .= $this->createExdate();
  7611. $component .= $this->createExrule();
  7612. $component .= $this->createLastModified();
  7613. $component .= $this->createOrganizer();
  7614. $component .= $this->createRdate();
  7615. $component .= $this->createRequestStatus();
  7616. $component .= $this->createRecurrenceid();
  7617. $component .= $this->createRelatedTo();
  7618. $component .= $this->createRrule();
  7619. $component .= $this->createSequence();
  7620. $component .= $this->createStatus();
  7621. $component .= $this->createSummary();
  7622. $component .= $this->createUrl();
  7623. $component .= $this->createXprop();
  7624. $component .= $this->componentEnd1 . $objectname . $this->componentEnd2;
  7625. if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl)))
  7626. {
  7627. foreach ($this->xcaldecl as $localxcaldecl)
  7628. $xcaldecl[] = $localxcaldecl;
  7629. }
  7630. return $component;
  7631. }
  7632. }
  7633. /*********************************************************************************/
  7634. /*********************************************************************************/
  7635. /**
  7636. * class for calendar component VFREEBUSY
  7637. *
  7638. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7639. * @since 2.5.1 - 2008-10-12
  7640. */
  7641. class vfreebusy extends calendarComponent
  7642. {
  7643. var $attendee;
  7644. var $comment;
  7645. var $contact;
  7646. var $dtend;
  7647. var $dtstart;
  7648. var $duration;
  7649. var $freebusy;
  7650. var $organizer;
  7651. var $requeststatus;
  7652. var $url;
  7653. var $xprop;
  7654. // component subcomponents container
  7655. var $components;
  7656. /**
  7657. * constructor for calendar component VFREEBUSY object
  7658. *
  7659. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7660. * @since 2.8.2 - 2011-05-01
  7661. * @param array $config
  7662. * @return void
  7663. */
  7664. function vfreebusy($config = array())
  7665. {
  7666. $this->calendarComponent();
  7667. $this->attendee = '';
  7668. $this->comment = '';
  7669. $this->contact = '';
  7670. $this->dtend = '';
  7671. $this->dtstart = '';
  7672. $this->duration = '';
  7673. $this->freebusy = '';
  7674. $this->organizer = '';
  7675. $this->requeststatus = '';
  7676. $this->url = '';
  7677. $this->xprop = '';
  7678. if (defined('ICAL_LANG') && ! isset($config['language']))
  7679. $config['language'] = ICAL_LANG;
  7680. if (! isset($config['allowEmpty']))
  7681. $config['allowEmpty'] = TRUE;
  7682. if (! isset($config['nl']))
  7683. $config['nl'] = "\r\n";
  7684. if (! isset($config['format']))
  7685. $config['format'] = 'iCal';
  7686. if (! isset($config['delimiter']))
  7687. $config['delimiter'] = DIRECTORY_SEPARATOR;
  7688. $this->setConfig($config);
  7689. }
  7690. /**
  7691. * create formatted output for calendar component VFREEBUSY object instance
  7692. *
  7693. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7694. * @since 2.3.1 - 2007-11-19
  7695. * @param array $xcaldecl
  7696. * @return string
  7697. */
  7698. function createComponent(&$xcaldecl)
  7699. {
  7700. $objectname = $this->_createFormat();
  7701. $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl;
  7702. $component .= $this->createUid();
  7703. $component .= $this->createDtstamp();
  7704. $component .= $this->createAttendee();
  7705. $component .= $this->createComment();
  7706. $component .= $this->createContact();
  7707. $component .= $this->createDtstart();
  7708. $component .= $this->createDtend();
  7709. $component .= $this->createDuration();
  7710. $component .= $this->createFreebusy();
  7711. $component .= $this->createOrganizer();
  7712. $component .= $this->createRequestStatus();
  7713. $component .= $this->createUrl();
  7714. $component .= $this->createXprop();
  7715. $component .= $this->componentEnd1 . $objectname . $this->componentEnd2;
  7716. if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl)))
  7717. {
  7718. foreach ($this->xcaldecl as $localxcaldecl)
  7719. $xcaldecl[] = $localxcaldecl;
  7720. }
  7721. return $component;
  7722. }
  7723. }
  7724. /*********************************************************************************/
  7725. /*********************************************************************************/
  7726. /**
  7727. * class for calendar component VALARM
  7728. *
  7729. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7730. * @since 2.5.1 - 2008-10-12
  7731. */
  7732. class valarm extends calendarComponent
  7733. {
  7734. var $action;
  7735. var $attach;
  7736. var $attendee;
  7737. var $description;
  7738. var $duration;
  7739. var $repeat;
  7740. var $summary;
  7741. var $trigger;
  7742. var $xprop;
  7743. /**
  7744. * constructor for calendar component VALARM object
  7745. *
  7746. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7747. * @since 2.8.2 - 2011-05-01
  7748. * @param array $config
  7749. * @return void
  7750. */
  7751. function valarm($config = array())
  7752. {
  7753. $this->calendarComponent();
  7754. $this->action = '';
  7755. $this->attach = '';
  7756. $this->attendee = '';
  7757. $this->description = '';
  7758. $this->duration = '';
  7759. $this->repeat = '';
  7760. $this->summary = '';
  7761. $this->trigger = '';
  7762. $this->xprop = '';
  7763. if (defined('ICAL_LANG') && ! isset($config['language']))
  7764. $config['language'] = ICAL_LANG;
  7765. if (! isset($config['allowEmpty']))
  7766. $config['allowEmpty'] = TRUE;
  7767. if (! isset($config['nl']))
  7768. $config['nl'] = "\r\n";
  7769. if (! isset($config['format']))
  7770. $config['format'] = 'iCal';
  7771. if (! isset($config['delimiter']))
  7772. $config['delimiter'] = DIRECTORY_SEPARATOR;
  7773. $this->setConfig($config);
  7774. }
  7775. /**
  7776. * create formatted output for calendar component VALARM object instance
  7777. *
  7778. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7779. * @since 2.5.1 - 2008-10-22
  7780. * @param array $xcaldecl
  7781. * @return string
  7782. */
  7783. function createComponent(&$xcaldecl)
  7784. {
  7785. $objectname = $this->_createFormat();
  7786. $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl;
  7787. $component .= $this->createAction();
  7788. $component .= $this->createAttach();
  7789. $component .= $this->createAttendee();
  7790. $component .= $this->createDescription();
  7791. $component .= $this->createDuration();
  7792. $component .= $this->createRepeat();
  7793. $component .= $this->createSummary();
  7794. $component .= $this->createTrigger();
  7795. $component .= $this->createXprop();
  7796. $component .= $this->componentEnd1 . $objectname . $this->componentEnd2;
  7797. return $component;
  7798. }
  7799. }
  7800. /**********************************************************************************
  7801. *********************************************************************************/
  7802. /**
  7803. * class for calendar component VTIMEZONE
  7804. *
  7805. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7806. * @since 2.5.1 - 2008-10-12
  7807. */
  7808. class vtimezone extends calendarComponent
  7809. {
  7810. var $timezonetype;
  7811. var $comment;
  7812. var $dtstart;
  7813. var $lastmodified;
  7814. var $rdate;
  7815. var $rrule;
  7816. var $tzid;
  7817. var $tzname;
  7818. var $tzoffsetfrom;
  7819. var $tzoffsetto;
  7820. var $tzurl;
  7821. var $xprop;
  7822. // component subcomponents container
  7823. var $components;
  7824. /**
  7825. * constructor for calendar component VTIMEZONE object
  7826. *
  7827. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7828. * @since 2.8.2 - 2011-05-01
  7829. * @param mixed $timezonetype optional, default FALSE ( STANDARD / DAYLIGHT )
  7830. * @param array $config
  7831. * @return void
  7832. */
  7833. function vtimezone($timezonetype = FALSE, $config = array())
  7834. {
  7835. if (is_array($timezonetype))
  7836. {
  7837. $config = $timezonetype;
  7838. $timezonetype = FALSE;
  7839. }
  7840. if (! $timezonetype)
  7841. $this->timezonetype = 'VTIMEZONE';
  7842. else
  7843. $this->timezonetype = strtoupper($timezonetype);
  7844. $this->calendarComponent();
  7845. $this->comment = '';
  7846. $this->dtstart = '';
  7847. $this->lastmodified = '';
  7848. $this->rdate = '';
  7849. $this->rrule = '';
  7850. $this->tzid = '';
  7851. $this->tzname = '';
  7852. $this->tzoffsetfrom = '';
  7853. $this->tzoffsetto = '';
  7854. $this->tzurl = '';
  7855. $this->xprop = '';
  7856. $this->components = array();
  7857. if (defined('ICAL_LANG') && ! isset($config['language']))
  7858. $config['language'] = ICAL_LANG;
  7859. if (! isset($config['allowEmpty']))
  7860. $config['allowEmpty'] = TRUE;
  7861. if (! isset($config['nl']))
  7862. $config['nl'] = "\r\n";
  7863. if (! isset($config['format']))
  7864. $config['format'] = 'iCal';
  7865. if (! isset($config['delimiter']))
  7866. $config['delimiter'] = DIRECTORY_SEPARATOR;
  7867. $this->setConfig($config);
  7868. }
  7869. /**
  7870. * create formatted output for calendar component VTIMEZONE object instance
  7871. *
  7872. * @author Kjell-Inge Gustafsson, kigkonsult <ical@kigkonsult.se>
  7873. * @since 2.5.1 - 2008-10-25
  7874. * @param array $xcaldecl
  7875. * @return string
  7876. */
  7877. function createComponent(&$xcaldecl)
  7878. {
  7879. $objectname = $this->_createFormat();
  7880. $component = $this->componentStart1 . $objectname . $this->componentStart2 . $this->nl;
  7881. $component .= $this->createTzid();
  7882. $component .= $this->createLastModified();
  7883. $component .= $this->createTzurl();
  7884. $component .= $this->createDtstart();
  7885. $component .= $this->createTzoffsetfrom();
  7886. $component .= $this->createTzoffsetto();
  7887. $component .= $this->createComment();
  7888. $component .= $this->createRdate();
  7889. $component .= $this->createRrule();
  7890. $component .= $this->createTzname();
  7891. $component .= $this->createXprop();
  7892. $component .= $this->createSubComponent();
  7893. $component .= $this->componentEnd1 . $objectname . $this->componentEnd2;
  7894. if (is_array($this->xcaldecl) && (0 < count($this->xcaldecl)))
  7895. {
  7896. foreach ($this->xcaldecl as $localxcaldecl)
  7897. $xcaldecl[] = $localxcaldecl;
  7898. }
  7899. return $component;
  7900. }
  7901. }
  7902. ?>