PageRenderTime 108ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 2ms

/monket-cal-source/icalcreator/iCalcreator.class.php

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