PageRenderTime 59ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full file

  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 = iCalUtilit

Large files files are truncated, but you can click here to view the full file