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  */
8 function 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  */
32 function 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 ?>