PageRenderTime 66ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 2ms

/sites/lifestream/classes/iCalcreator.class.php

https://github.com/NeilCrosby/lifestream
PHP | 7382 lines | 5553 code | 8 blank | 1821 comment | 1357 complexity | 33abf23ad639818738178066a5f5d4a7 MD5 | raw file

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

  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;

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