PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/phpical2/functions/ical_parser.php

https://gitlab.com/endomorphosis/fusenews
PHP | 518 lines | 430 code | 47 blank | 41 comment | 104 complexity | da4f999ae0c60b7e855523b75324ccef MD5 | raw file
  1. <?php
  2. if (!defined('BASE')) define('BASE', './');
  3. include_once(BASE.'functions/init.inc.php');
  4. include_once(BASE.'functions/date_functions.php');
  5. include_once(BASE.'functions/draw_functions.php');
  6. include_once(BASE.'functions/parse/overlapping_events.php');
  7. include_once(BASE.'functions/timezones.php');
  8. include_once(BASE.'functions/parse/recur_functions.php');
  9. // reading the file if it's allowed
  10. $parse_file = true;
  11. if ($phpiCal_config->save_parsed_cals == 'yes') {
  12. if (sizeof ($cal_filelist) > 1) {
  13. $parsedcal = $phpiCal_config->tmp_dir.'/parsedcal-'.urlencode($cpath.'::'.$cal_filename).'-'.$this_year;
  14. if (file_exists($parsedcal)) {
  15. $fd = fopen($parsedcal, 'r');
  16. $contents = fread($fd, filesize($parsedcal));
  17. fclose($fd);
  18. $master_array = unserialize($contents);
  19. $z=1;
  20. $y=0;
  21. $webcal_mtime = time() - ($phpiCal_config->webcal_hours * 3600);
  22. if (sizeof($master_array['-4']) == (sizeof($cal_filelist))) {
  23. foreach ($master_array['-4'] as $temp_array) {
  24. $mtime = $master_array['-4'][$z]['mtime'];
  25. $fname = $master_array['-4'][$z]['filename'];
  26. $wcalc = $master_array['-4'][$z]['webcal'];
  27. if ($wcalc == 'no') $realcal_mtime = filemtime($fname);
  28. if (isset($realcal_mtime) && ($mtime == $realcal_mtime) && ($wcalc == 'no')) {
  29. $y++;
  30. } elseif (($wcalc == 'yes') && ($mtime > $webcal_mtime)) {
  31. //echo date('H:i',$mtime). ' > '. date('H:i',$webcal_mtime);
  32. $y++;
  33. }
  34. $z++;
  35. }
  36. foreach ($master_array['-3'] as $temp_array) {
  37. if (isset($temp_array) && $temp_array !='') $caldisplaynames[] = $temp_array;
  38. }
  39. if ($y == sizeof($cal_filelist)) {
  40. if ($master_array['-1'] == 'valid cal file') {
  41. $parse_file = false;
  42. $calendar_name = $master_array['calendar_name'];
  43. $calendar_tz = $master_array['calendar_tz'];
  44. }
  45. }
  46. }
  47. }
  48. if ($parse_file == true) unset($master_array);
  49. } else {
  50. foreach ($cal_filelist as $filename) {
  51. $realcal_mtime = filemtime($filename);
  52. $parsedcal = $phpiCal_config->tmp_dir.'/parsedcal-'.urlencode($cpath.'::'.$cal_filename).'-'.$this_year;
  53. if (file_exists($parsedcal)) {
  54. $parsedcal_mtime = filemtime($parsedcal);
  55. if ($realcal_mtime == $parsedcal_mtime) {
  56. $fd = fopen($parsedcal, 'r');
  57. $contents = fread($fd, filesize($parsedcal));
  58. fclose($fd);
  59. $master_array = unserialize($contents);
  60. if ($master_array['-1'] == 'valid cal file') {
  61. $parse_file = false;
  62. $calendar_name = $master_array['calendar_name'];
  63. $calendar_tz = $master_array['calendar_tz'];
  64. }
  65. }
  66. }
  67. }
  68. }
  69. }
  70. if ($parse_file) {
  71. $overlap_array = array ();
  72. $uid_counter = 0;
  73. }
  74. $calnumber = 1;
  75. foreach ($cal_filelist as $cal_key=>$filename) {
  76. // Find the real name of the calendar.
  77. $actual_calname = getCalendarName($filename);
  78. if ($parse_file) {
  79. // Let's see if we're doing a webcal
  80. $is_webcal = FALSE;
  81. if (substr($filename, 0, 7) == 'http://' || substr($filename, 0, 8) == 'https://' || substr($filename, 0, 9) == 'webcal://') {
  82. $is_webcal = TRUE;
  83. $cal_webcalPrefix = str_replace('http://','webcal://',$filename);
  84. $cal_httpPrefix = str_replace('webcal://','http://',$filename);
  85. $cal_httpsPrefix = str_replace('webcal://','https://',$filename);
  86. $cal_httpsPrefix = str_replace('http://','https://',$cal_httpsPrefix);
  87. $filename = $cal_httpPrefix;
  88. $master_array['-4'][$calnumber]['webcal'] = 'yes';
  89. $actual_mtime = time();
  90. } else {
  91. $actual_mtime = @filemtime($filename);
  92. }
  93. include(BASE.'functions/parse/parse_tzs.php');
  94. $ifile = @fopen($filename, "r");
  95. if ($ifile == FALSE) exit(error($lang['l_error_cantopen'], $filename));
  96. $nextline = fgets($ifile, 1024);
  97. if (trim($nextline) != 'BEGIN:VCALENDAR') exit(error($lang['l_error_invalidcal'], $filename));
  98. // Set a value so we can check to make sure $master_array contains valid data
  99. $master_array['-1'] = 'valid cal file';
  100. // Set default calendar name - can be overridden by X-WR-CALNAME
  101. $calendar_name = $cal_filename;
  102. $master_array['calendar_name'] = $calendar_name;
  103. // read file in line by line
  104. // XXX end line is skipped because of the 1-line readahead
  105. while (!feof($ifile)) {
  106. $line = $nextline;
  107. $nextline = fgets($ifile, 1024);
  108. $nextline = ereg_replace("[\r\n]", "", $nextline);
  109. #handle continuation lines that start with either a space or a tab (MS Outlook)
  110. while (isset($nextline{0}) && ($nextline{0} == " " || $nextline{0} == "\t")) {
  111. $line = $line . substr($nextline, 1);
  112. $nextline = fgets($ifile, 1024);
  113. $nextline = ereg_replace("[\r\n]", "", $nextline);
  114. }
  115. $line = str_replace('\n',"\n",$line);
  116. $line = trim(stripslashes($line));
  117. switch ($line) {
  118. case 'BEGIN:VFREEBUSY':
  119. case 'BEGIN:VEVENT':
  120. // each of these vars were being set to an empty string
  121. unset (
  122. $start_time, $end_time, $start_date, $end_date,
  123. $allday_start, $allday_end, $start, $end, $the_duration,
  124. $beginning, $start_of_vevent,
  125. $valarm_description, $start_unixtime, $end_unixtime, $display_end_tmp, $end_time_tmp1,
  126. $recurrence_id, $uid, $rrule, $until_check,
  127. $until, $byweek, $byweekno,
  128. $byminute, $byhour, $bysecond
  129. );
  130. $interval = 1;
  131. $sequence = 0;
  132. $summary = '';
  133. $description = '';
  134. $status = '';
  135. $class = '';
  136. $location = '';
  137. $url = '';
  138. $geo = '';
  139. $type = '';
  140. $other = '';
  141. $wkst = 'MO';
  142. $vtodo_categories = '';
  143. $except_dates = array();
  144. $except_times = array();
  145. $rrule_array = array();
  146. $byday = array();
  147. $bymonth = array();
  148. $bymonthday = array();
  149. $byyearday = array();
  150. $bysetpos = array();
  151. $first_duration = TRUE;
  152. $count = 1000000;
  153. $valarm_set = FALSE;
  154. $attendee = array();
  155. $organizer = array();
  156. break;
  157. case 'END:VFREEBUSY':
  158. case 'END:VEVENT':
  159. include BASE."functions/parse/end_vevent.php";
  160. break;
  161. case 'END:VTODO':
  162. if (($vtodo_priority == '') && ($status == 'COMPLETED')) {
  163. $vtodo_sort = 11;
  164. } elseif ($vtodo_priority == '') {
  165. $vtodo_sort = 10;
  166. } else {
  167. $vtodo_sort = $vtodo_priority;
  168. }
  169. // CLASS support
  170. if (isset($class)) {
  171. if ($class == 'PRIVATE') {
  172. $summary = '**PRIVATE**';
  173. $description = '**PRIVATE**';
  174. } elseif ($class == 'CONFIDENTIAL') {
  175. $summary = '**CONFIDENTIAL**';
  176. $description = '**CONFIDENTIAL**';
  177. }
  178. }
  179. $master_array['-2']["$vtodo_sort"]["$uid"] = array (
  180. 'start_date' => $start_date,
  181. 'start_time' => $start_time,
  182. 'vtodo_text' => $summary,
  183. 'due_date'=> $due_date,
  184. 'due_time'=> $due_time,
  185. 'completed_date' => $completed_date,
  186. 'completed_time' => $completed_time,
  187. 'priority' => $vtodo_priority,
  188. 'status' => $status,
  189. 'class' => $class,
  190. 'categories' => $vtodo_categories,
  191. 'description' => $description,
  192. 'calname' => $actual_calname,
  193. 'geo' => $geo,
  194. 'url' => $url
  195. );
  196. unset ($start_date, $start_time, $due_date, $due_time, $completed_date, $completed_time, $vtodo_priority, $status, $class, $vtodo_categories, $summary, $description);
  197. $vtodo_set = FALSE;
  198. break;
  199. case 'BEGIN:VTODO':
  200. $vtodo_set = TRUE;
  201. $summary = '';
  202. $due_date = '';
  203. $due_time = '';
  204. $completed_date = '';
  205. $completed_time = '';
  206. $vtodo_priority = '';
  207. $vtodo_categories = '';
  208. $status = '';
  209. $class = '';
  210. $description = '';
  211. break;
  212. case 'BEGIN:VALARM':
  213. $valarm_set = TRUE;
  214. break;
  215. case 'END:VALARM':
  216. $valarm_set = FALSE;
  217. break;
  218. default:
  219. unset ($field, $data, $prop_pos, $property);
  220. if (ereg ("([^:]+):(.*)", $line, $line)){
  221. $field = $line[1];
  222. $data = $line[2];
  223. $property = strtoupper($field);
  224. $prop_pos = strpos($property,';');
  225. if ($prop_pos !== false) $property = substr($property,0,$prop_pos);
  226. switch ($property) {
  227. // Start VTODO Parsing
  228. //
  229. case 'DUE':
  230. $datetime = extractDateTime($data, $property, $field);
  231. $due_date = $datetime[1];
  232. $due_time = $datetime[2];
  233. break;
  234. case 'COMPLETED':
  235. $datetime = extractDateTime($data, $property, $field);
  236. $completed_date = $datetime[1];
  237. $completed_time = $datetime[2];
  238. break;
  239. case 'PRIORITY':
  240. $vtodo_priority = "$data";
  241. break;
  242. case 'STATUS':
  243. $status = "$data";
  244. break;
  245. case 'GEO':
  246. $geo = "$data";
  247. break;
  248. case 'CLASS':
  249. $class = "$data";
  250. break;
  251. case 'CATEGORIES':
  252. $vtodo_categories = "$data";
  253. break;
  254. //
  255. // End VTODO Parsing
  256. case 'DTSTART':
  257. $datetime = extractDateTime($data, $property, $field);
  258. $start_unixtime = $datetime[0];
  259. $start_date = $datetime[1];
  260. $start_time = $datetime[2];
  261. $allday_start = $datetime[3];
  262. $start_tz = $datetime[4];
  263. preg_match ('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})/', $data, $regs);
  264. $vevent_start_date = $regs[1] . $regs[2] . $regs[3];
  265. $day_offset = dayCompare($start_date, $vevent_start_date);
  266. #echo date("Ymd Hi", $start_unixtime)." $start_date $start_time $vevent_start_date $day_offset<br>";
  267. break;
  268. case 'DTEND':
  269. $datetime = extractDateTime($data, $property, $field);
  270. $end_unixtime = $datetime[0];
  271. $end_date = $datetime[1];
  272. $end_time = $datetime[2];
  273. $allday_end = $datetime[3];
  274. break;
  275. case 'EXDATE':
  276. $data = split(",", $data);
  277. foreach ($data as $exdata) {
  278. $exdata = str_replace('T', '', $exdata);
  279. $exdata = str_replace('Z', '', $exdata);
  280. preg_match ('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})/', $exdata, $regs);
  281. $except_dates[] = $regs[1] . $regs[2] . $regs[3];
  282. // Added for Evolution, since they dont think they need to tell me which time to exclude.
  283. if ($regs[4] == '' && isset($start_time) && $start_time != '') {
  284. $except_times[] = $start_time;
  285. } else {
  286. $except_times[] = $regs[4] . $regs[5];
  287. }
  288. }
  289. break;
  290. case 'SUMMARY':
  291. $data = str_replace("\\n", "<br />", $data);
  292. $data = str_replace("\\t", "&nbsp;", $data);
  293. $data = str_replace("\\r", "<br />", $data);
  294. $data = str_replace('$', '&#36;', $data);
  295. $data = stripslashes($data);
  296. $data = htmlentities(urlencode($data));
  297. if ($valarm_set == FALSE) {
  298. $summary = $data;
  299. } else {
  300. $valarm_summary = $data;
  301. }
  302. break;
  303. case 'DESCRIPTION':
  304. $data = str_replace("\n", "<br />", $data);
  305. $data = str_replace("\\t", "&nbsp;", $data);
  306. $data = str_replace("\r", "<br />", $data);
  307. $data = str_replace('$', '&#36;', $data);
  308. $data = stripslashes($data);
  309. $data = htmlentities(urlencode($data));
  310. if ($valarm_set == FALSE) {
  311. $description = $data;
  312. } else {
  313. $valarm_description = $data;
  314. }
  315. break;
  316. case 'RECURRENCE-ID':
  317. $parts = explode(';', $field);
  318. foreach($parts as $part) {
  319. $eachval = split('=',$part);
  320. if ($eachval[0] == 'RECURRENCE-ID') {
  321. // do nothing
  322. } elseif ($eachval[0] == 'TZID') {
  323. $recurrence_id['tzid'] = $eachval[1];
  324. } elseif ($eachval[0] == 'RANGE') {
  325. $recurrence_id['range'] = $eachval[1];
  326. } elseif ($eachval[0] == 'VALUE') {
  327. $recurrence_id['value'] = $eachval[1];
  328. } else {
  329. $recurrence_id[] = $eachval[1];
  330. }
  331. }
  332. unset($parts, $part, $eachval);
  333. $data = str_replace('T', '', $data);
  334. $data = str_replace('Z', '', $data);
  335. ereg ('([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})', $data, $regs);
  336. $recurrence_id['date'] = $regs[1] . $regs[2] . $regs[3];
  337. $recurrence_id['time'] = $regs[4] . $regs[5];
  338. $recur_unixtime = mktime($regs[4], $regs[5], 0, $regs[2], $regs[3], $regs[1]);
  339. if (isset($recurrence_id['tzid'])) {
  340. $offset_tmp = chooseOffset($recur_unixtime, $recurrence_id['tzid']);
  341. } elseif (isset($calendar_tz)) {
  342. $offset_tmp = chooseOffset($recur_unixtime, $calendar_tz);
  343. } else {
  344. $offset_tmp = $chooseOffset($recur_unixtime);
  345. }
  346. $recur_unixtime = calcTime($offset_tmp, @$server_offset_tmp, $recur_unixtime);
  347. $recurrence_id['date'] = date('Ymd', $recur_unixtime);
  348. $recurrence_id['time'] = date('Hi', $recur_unixtime);
  349. $recurrence_d = date('Ymd', $recur_unixtime);
  350. $recurrence_t = date('Hi', $recur_unixtime);
  351. unset($server_offset_tmp);
  352. break;
  353. case 'SEQUENCE':
  354. $sequence = $data;
  355. break;
  356. case 'UID':
  357. $uid = $data;
  358. break;
  359. case 'X-WR-CALNAME':
  360. $actual_calname = $data;
  361. $master_array['calendar_name'] = $actual_calname;
  362. $cal_displaynames[$cal_key] = $actual_calname; #correct the default calname based on filename
  363. break;
  364. case 'X-WR-TIMEZONE':
  365. $calendar_tz = $data;
  366. $master_array['calendar_tz'] = $calendar_tz;
  367. break;
  368. case 'DURATION':
  369. if (($first_duration == TRUE) && (!stristr($field, '=DURATION'))) {
  370. ereg ('^P([0-9]{1,2}[W])?([0-9]{1,3}[D])?([T]{0,1})?([0-9]{1,2}[H])?([0-9]{1,2}[M])?([0-9]{1,2}[S])?', $data, $duration);
  371. $weeks = str_replace('W', '', $duration[1]);
  372. $days = str_replace('D', '', $duration[2]);
  373. $hours = str_replace('H', '', $duration[4]);
  374. $minutes = str_replace('M', '', $duration[5]);
  375. $seconds = str_replace('S', '', $duration[6]);
  376. $the_duration = ($weeks * 60 * 60 * 24 * 7) + ($days * 60 * 60 * 24) + ($hours * 60 * 60) + ($minutes * 60) + ($seconds);
  377. $first_duration = FALSE;
  378. }
  379. break;
  380. case 'RRULE':
  381. $data = str_replace ('RRULE:', '', $data);
  382. $rrule = split (';', $data);
  383. foreach ($rrule as $recur) {
  384. ereg ('(.*)=(.*)', $recur, $regs);
  385. $rrule_array[$regs[1]] = $regs[2];
  386. }
  387. break;
  388. case 'ATTENDEE':
  389. $attendee[] = array ('name' => ereg_replace ("ATTENDEE;CN=([^;]*).*", "\\1", $field),
  390. 'email' => ereg_replace (".*mailto:(.*).*", "\\1", $field),
  391. 'RSVP' => ereg_replace (".*RSVP=([^;]*).*", "\\1", $field),
  392. 'PARSTAT' => ereg_replace (".*PARTSTAT=([^;]*).*", "\\1", $field),
  393. 'ROLE' => ereg_replace (".*ROLE=([^;]*).*", "\\1", $field));
  394. break;
  395. case 'ORGANIZER':
  396. $field = str_replace("ORGANIZER;CN=", "", $field);
  397. $data = str_replace ("mailto:", "", $data);
  398. $organizer[] = array ('name' => stripslashes($field), 'email' => stripslashes($data));
  399. break;
  400. case 'LOCATION':
  401. $data = str_replace("\\n", "<br />", $data);
  402. $data = str_replace("\\t", "&nbsp;", $data);
  403. $data = str_replace("\\r", "<br />", $data);
  404. $data = stripslashes($data);
  405. $location = $data;
  406. break;
  407. case 'URL':
  408. $url = $data;
  409. break;
  410. default:
  411. if(strpos(':',$data) > 1) $other .= $data;
  412. }
  413. }
  414. }
  415. }
  416. }
  417. if (!isset($master_array['-3'][$calnumber])) $master_array['-3'][$calnumber] = $actual_calname;
  418. if (!isset($master_array['-4'][$calnumber]['mtime'])) $master_array['-4'][$calnumber]['mtime'] = $actual_mtime;
  419. if (!isset($master_array['-4'][$calnumber]['filename'])) $master_array['-4'][$calnumber]['filename'] = $filename;
  420. if (!isset($master_array['-4'][$calnumber]['webcal'])) $master_array['-4'][$calnumber]['webcal'] = 'no';
  421. $calnumber = $calnumber + 1;
  422. }
  423. if ($parse_file) {
  424. // Sort the array by absolute date.
  425. if (isset($master_array) && is_array($master_array)) {
  426. ksort($master_array);
  427. reset($master_array);
  428. // sort the sub (day) arrays so the times are in order
  429. foreach (array_keys($master_array) as $k) {
  430. if (isset($master_array[$k]) && is_array($master_array[$k])) {
  431. ksort($master_array[$k]);
  432. reset($master_array[$k]);
  433. }
  434. }
  435. }
  436. // write the new master array to the file
  437. if (isset($master_array) && is_array($master_array) && $phpiCal_config->save_parsed_cals == 'yes') {
  438. $write_me = serialize($master_array);
  439. $fd = @fopen($parsedcal, 'w');
  440. if ($fd == FALSE) exit(error($lang['l_error_cache'], $filename));
  441. @fwrite($fd, $write_me);
  442. @fclose($fd);
  443. @touch($parsedcal, $realcal_mtime);
  444. }
  445. }
  446. // Set a calender name for all calenders combined
  447. if ($cal == $phpiCal_config->ALL_CALENDARS_COMBINED) {
  448. $calendar_name = $all_cal_comb_lang;
  449. }
  450. /* example of how to customize the display name sort order
  451. if(in_array('US Holidays',$cal_displaynames)){
  452. unset($cal_displaynames[array_search('US Holidays',$cal_displaynames)]);
  453. array_unshift($cal_displaynames, 'US Holidays');
  454. }
  455. */
  456. $cal_displayname = urldecode(implode(', ', $cal_displaynames)); #reset this with the correct names
  457. $template_started = getmicrotime();
  458. //If you want to see the values in the arrays, uncomment below.
  459. #print '<pre>';
  460. #var_dump($phpiCal_config);
  461. #print_r($master_array);
  462. #var_dump($overlap_array['20081211']);
  463. //print_r($day_array);
  464. //print_r($rrule_array);
  465. //print_r($byday_arr);
  466. //print_r($recurrence_delete);
  467. //print_r($cal_displaynames);
  468. //print_r($cal_filelist);
  469. //print_r($tz_array);
  470. #print '</pre>';
  471. ?>