1<?php
2
3/** Returns the offset from the origin timezone to the remote timezone, in seconds.
4 * @param $remote_tz;
5 * @param $origin_tz; If null the servers current timezone is used as the origin.
6 * @return int;
7 */
8function get_timezone_offset($remote_tz, $timestamp, $origin_tz = null) {
9	if($origin_tz === null) {
10		if(!is_string($origin_tz = date_default_timezone_get())) {
11			return false; // A UTC timestamp was returned -- bail out!
12		}
13	}
14	$origin_dtz = new DateTimeZone($origin_tz);
15	$remote_dtz = new DateTimeZone($remote_tz);
16
17	$origin_dt = new DateTime("@$timestamp", $origin_dtz);
18	$remote_dt = new DateTime("@$timestamp", $remote_dtz);
19
20	$offset = $origin_dtz->getOffset($origin_dt) - $remote_dtz->getOffset($remote_dt);
21	return $offset;
22}
23
24/**
25 * Parses a VEVENT into an array with fields.
26 *
27 * @param vevent VEVENT.
28 * @param dateFormat dateformat for displaying the start and end date.
29 *
30 * @return array().
31 */
32function parse_vevent( $vevent, $dateFormat="%Y-%m-%d", $timeFormat="%H:%M" ) {
33
34    // Regex for the different fields
35    $regex_summary     = '/SUMMARY:(.*?)\n/';
36	$regex_location    = '/LOCATION:(.*?)\n/';
37
38	// descriptions may be continued with a space at the start of the next line
39	// BUGFIX: OR descriptions can be the last item in the VEVENT string
40	$regex_description = '/DESCRIPTION:(.*?)\n([^ ]|$)/s';
41
42	// normal events with time
43	$regex_dtstart     = '/DTSTART.*?:([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})/';
44	$regex_dtend       = '/DTEND.*?:([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})/';
45
46	// Timezones can be passed for individual dtstart and dtend by the ics
47	$regex_dtstart_timezone = '/DTSTART;TZID=(.*?):([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})/';
48	$regex_dtend_timezone = '/DTEND;TZID=(.*?):([0-9]{4})([0-9]{2})([0-9]{2})T([0-9]{2})([0-9]{2})([0-9]{2})/';
49
50	// all day event
51	$regex_alldaystart = '/DTSTART;VALUE=DATE:([0-9]{4})([0-9]{2})([0-9]{2})/';
52	$regex_alldayend   = '/DTEND;VALUE=DATE:([0-9]{4})([0-9]{2})([0-9]{2})/';
53
54    // Make the entry
55    $entry = array();
56	$entry['vevent'] = "BEGIN:VEVENT\r\n".$vevent."END:VEVENT\r\n";
57    // Get the summary
58	if (preg_match($regex_summary, $vevent, $summary)) {
59		$entry['summary'] = str_replace('\,', ',', $summary[1]);
60	}
61
62    // Get the starting time timezone
63	if ( preg_match( $regex_dtstart_timezone, $vevent, $timezone ) ) {
64	   $start_timezone = $timezone[1];
65    }
66    else {
67        $start_timezone = 'UTC';
68    }
69    // Get the end time timezone
70    if ( preg_match( $regex_dtend_timezone, $vevent, $timezone ) ) {
71	   $end_timezone = $timezone[1];
72    }
73    else {
74        $end_timezone = 'UTC';
75    }
76
77	// Get the start and end times
78	if (preg_match($regex_dtstart, $vevent, $dtstart)) {
79		#                                hour          minute       second       month        day          year
80		$entry['startunixdate'] = mktime($dtstart[4], $dtstart[5], $dtstart[6], $dtstart[2], $dtstart[3], $dtstart[1]);
81		#Calculate the timezone offset
82
83		$start_timeOffset = get_timezone_offset($start_timezone, $entry['startunixdate']);
84
85		$entry['startunixdate'] = $entry['startunixdate'] + $start_timeOffset;
86		$entry['startdate']     = strftime($dateFormat, $entry['startunixdate']);
87		$entry['starttime']       = strftime($timeFormat, $entry['startunixdate']);
88
89		preg_match($regex_dtend, $vevent, $dtend);
90        $entry['endunixdate']   = mktime($dtend[4], $dtend[5], $dtend[6], $dtend[2], $dtend[3], $dtend[1]) + $timeOffset;
91
92        $end_timeOffset = get_timezone_offset($end_timezone, $entry['endunixdate']);
93        $entry['endunixdate'] = $entry['endunixdate'] + $end_timeOffset;
94
95		$entry['enddate']       = strftime($dateFormat, $entry['endunixdate']);
96		$entry['endtime']       = strftime($timeFormat, $entry['endunixdate']);
97		$entry['allday']        = false;
98	}
99	if (preg_match($regex_alldaystart, $vevent, $alldaystart)) {
100		$entry['startunixdate'] = mktime(0, 0, 0, $alldaystart[2], $alldaystart[3], $alldaystart[1]);
101		# Calculate the timezone offset
102		$start_timeOffset = get_timezone_offset($start_timezone, $entry['startunixdate']);
103
104		$entry['startunixdate'] = $entry['startunixdate'] + $start_timeOffset;
105		$entry['startdate']     = strftime($dateFormat, $entry['startunixdate']);
106
107		preg_match($regex_alldayend, $vevent, $alldayend);
108
109		$entry['endunixdate']   = mktime(0, 0, 0, $alldayend[2], $alldayend[3], $alldayend[1]);
110		$end_timeOffset = get_timezone_offset($end_timezone, $entry['endunixdate']);
111		$entry['endunixdate']   = $entry['endunixdate'] + $end_timeOffset - 1;
112		$entry['enddate']       = strftime($dateFormat, $entry['endunixdate']);
113		$entry['allday']        = true;
114	}
115
116	# also filter PalmPilot internal stuff
117	if (preg_match('/@@@/', $entry['description'])) { continue; }
118
119	if (preg_match($regex_description, $vevent, $description)) {
120		$entry['description'] = $description[1];
121        $entry['description'] = preg_replace("/[\r\n] ?/", "", $entry['description']);
122        $entry['description'] = str_replace('\,', ',', $entry['description']);
123	}
124	if (preg_match($regex_location, $vevent, $location)) {
125		$entry['location'] = str_replace('\,', ',', $location[1]);
126	}
127	return $entry;
128}
129
130?>