[ Index ] |
|
Code source de WebCalendar 1.0.5 |
1 <?php 2 /* 3 * $Id: import_ical.php,v 1.19.2.1 2005/08/19 17:52:35 umcesrjones Exp $ 4 * 5 * File Description: 6 * This file incudes functions for parsing iCal data files during 7 * an import. 8 * 9 * It will be included by import_handler.php. 10 * 11 * The iCal specification is available online at: 12 * http://www.ietf.org/rfc/rfc2445.txt 13 * 14 */ 15 16 // Parse the ical file and return the data hash. 17 function parse_ical ( $cal_file ) { 18 global $tz, $errormsg; 19 20 $ical_data = array(); 21 22 if (!$fd=@fopen($cal_file,"r")) { 23 $errormsg .= "Can't read temporary file: $cal_file\n"; 24 exit(); 25 } else { 26 27 // Read in contents of entire file first 28 $data = ''; 29 $line = 0; 30 while (!feof($fd) && empty( $error ) ) { 31 $line++; 32 $data .= fgets($fd, 4096); 33 } 34 fclose($fd); 35 // Now fix folding. According to RFC, lines can fold by having 36 // a CRLF and then a single white space character. 37 // We will allow it to be CRLF, CR or LF or any repeated sequence 38 // so long as there is a single white space character next. 39 //echo "Orig:<br><pre>$data</pre><br/><br/>\n"; 40 $data = preg_replace ( "/[\r\n]+ /", "", $data ); 41 $data = preg_replace ( "/[\r\n]+/", "\n", $data ); 42 //echo "Data:<br><pre>$data</pre><P>"; 43 44 // reflect the section where we are in the file: 45 // VEVENT, VTODO, VJORNAL, VFREEBUSY, VTIMEZONE 46 $state = "NONE"; 47 $substate = "none"; // reflect the sub section 48 $subsubstate = ""; // reflect the sub-sub section 49 $error = false; 50 $line = 0; 51 $event = ''; 52 53 $lines = explode ( "\n", $data ); 54 for ( $n = 0; $n < count ( $lines ) && ! $error; $n++ ) { 55 $line++; 56 $buff = $lines[$n]; 57 58 // parser debugging code... 59 //echo "line = $line <br />"; 60 //echo "state = $state <br />"; 61 //echo "substate = $substate <br />"; 62 //echo "subsubstate = $subsubstate <br />"; 63 //echo "buff = " . htmlspecialchars ( $buff ) . "<br /><br />\n"; 64 65 if ($state == "VEVENT") { 66 if ( ! empty ( $subsubstate ) ) { 67 if (preg_match("/^END:(.+)$/i", $buff, $match)) { 68 if ( $match[1] == $subsubstate ) { 69 $subsubstate = ''; 70 } 71 } else if ( $subsubstate == "VALARM" && 72 preg_match ( "/TRIGGER:(.+)$/i", $buff, $match ) ) { 73 // Example: TRIGGER;VALUE=DATE-TIME:19970317T133000Z 74 //echo "Set reminder to $match[1]<br />"; 75 // reminder time is $match[1] 76 } 77 } 78 else if (preg_match("/^BEGIN:(.+)$/i", $buff, $match)) { 79 $subsubstate = $match[1]; 80 } 81 // we suppose ":" is on the same line as property name, this can perhaps cause problems 82 else if (preg_match("/^SUMMARY.*:(.+)$/i", $buff, $match)) { 83 $substate = "summary"; 84 $event[$substate] = $match[1]; 85 } elseif (preg_match("/^DESCRIPTION:(.+)$/i", $buff, $match)) { 86 $substate = "description"; 87 $event[$substate] = $match[1]; 88 } elseif (preg_match("/^DESCRIPTION.*:(.+)$/i", $buff, $match)) { 89 $substate = "description"; 90 $event[$substate] = $match[1]; 91 } elseif (preg_match("/^CLASS.*:(.*)$/i", $buff, $match)) { 92 $substate = "class"; 93 $event[$substate] = $match[1]; 94 } elseif (preg_match("/^PRIORITY.*:(.*)$/i", $buff, $match)) { 95 $substate = "priority"; 96 $event[$substate] = $match[1]; 97 } elseif (preg_match("/^DTSTART.*:\s*(\d+T\d+Z?)\s*$/i", $buff, $match)) { 98 $substate = "dtstart"; 99 $event[$substate] = $match[1]; 100 } elseif (preg_match("/^DTSTART.*:\s*(\d+)\s*$/i", $buff, $match)) { 101 $substate = "dtstart"; 102 $event[$substate] = $match[1]; 103 } elseif (preg_match("/^DTEND.*:\s*(.*)\s*$/i", $buff, $match)) { 104 $substate = "dtend"; 105 $event[$substate] = $match[1]; 106 } elseif (preg_match("/^DURATION.*:(.+)\s*$/i", $buff, $match)) { 107 $substate = "duration"; 108 $durH = $durM = 0; 109 if ( preg_match ( "/PT.*([0-9]+)H/", $match[1], $submatch ) ) 110 $durH = $submatch[1]; 111 if ( preg_match ( "/PT.*([0-9]+)M/", $match[1], $submatch ) ) 112 $durM = $submatch[1]; 113 $event[$substate] = $durH * 60 + $durM; 114 } elseif (preg_match("/^RRULE.*:(.+)$/i", $buff, $match)) { 115 $substate = "rrule"; 116 $event[$substate] = $match[1]; 117 } elseif (preg_match("/^EXDATE.*:(.+)$/i", $buff, $match)) { 118 $substate = "exdate"; 119 $event[$substate] = $match[1]; 120 } elseif (preg_match("/^CATEGORIES.*:(.+)$/i", $buff, $match)) { 121 $substate = "categories"; 122 $event[$substate] = $match[1]; 123 } elseif (preg_match("/^UID.*:(.+)$/i", $buff, $match)) { 124 $substate = "uid"; 125 $event[$substate] = $match[1]; 126 } elseif (preg_match("/^END:VEVENT$/i", $buff, $match)) { 127 $state = "VCALENDAR"; 128 $substate = "none"; 129 $subsubstate = ''; 130 if ($tmp_data = format_ical($event)) $ical_data[] = $tmp_data; 131 // clear out data for new event 132 $event = ''; 133 134 // TODO: QUOTED-PRINTABLE descriptions 135 136 // folded lines 137 // TODO: This is not the best way to handle folded lines. 138 // We should fix the folding before we parse... 139 } elseif (preg_match("/^\s(\S.*)$/", $buff, $match)) { 140 if ($substate != "none") { 141 $event[$substate] .= $match[1]; 142 } else { 143 $errormsg .= "iCal parse error on line $line:<br />$buff\n"; 144 $error = true; 145 } 146 // For unsupported properties 147 } else { 148 $substate = "none"; 149 } 150 } elseif ($state == "VCALENDAR") { 151 if (preg_match("/^BEGIN:VEVENT/i", $buff)) { 152 $state = "VEVENT"; 153 } elseif (preg_match("/^END:VCALENDAR/i", $buff)) { 154 $state = "NONE"; 155 } else if (preg_match("/^BEGIN:VTIMEZONE/i", $buff)) { 156 $state = "VTIMEZONE"; 157 } else if (preg_match("/^BEGIN:VALARM/i", $buff)) { 158 $state = "VALARM"; 159 } 160 } elseif ($state == "VTIMEZONE") { 161 // We don't do much with timezone info yet... 162 if (preg_match("/^END:VTIMEZONE$/i", $buff)) { 163 $state = "VCALENDAR"; 164 } 165 } elseif ($state == "NONE") { 166 if (preg_match("/^BEGIN:VCALENDAR$/i", $buff)) 167 $state = "VCALENDAR"; 168 } 169 } // End while 170 } 171 172 return $ical_data; 173 } 174 175 // Convert ical format (yyyymmddThhmmssZ) to epoch time 176 function icaldate_to_timestamp ($vdate, $plus_d = '0', $plus_m = '0', 177 $plus_y = '0') { 178 global $TZoffset; 179 180 $y = substr($vdate, 0, 4) + $plus_y; 181 $m = substr($vdate, 4, 2) + $plus_m; 182 $d = substr($vdate, 6, 2) + $plus_d; 183 $H = substr($vdate, 9, 2); 184 $M = substr($vdate, 11, 2); 185 $S = substr($vdate, 13, 2); 186 $Z = substr($vdate, 15, 1); 187 188 if ($Z == 'Z') { 189 $TS = gmmktime($H,$M,$S,$m,$d,$y); 190 } else { 191 // Problem here if server in different timezone 192 $TS = mktime($H,$M,$S,$m,$d,$y); 193 } 194 195 return $TS; 196 } 197 198 199 // Put all ical data into import hash structure 200 function format_ical($event) { 201 202 // Start and end time 203 $fevent['StartTime'] = icaldate_to_timestamp($event['dtstart']); 204 if ($fevent['StartTime'] == '-1') return false; 205 if ( isset ( $event['dtend'] ) ) { 206 $fevent['EndTime'] = icaldate_to_timestamp($event['dtend']); 207 } else { 208 if ( isset ( $event['duration'] ) ) { 209 $fevent['EndTime'] = $fevent['StartTime'] + $event['duration'] * 60; 210 } else { 211 $fevent['EndTime'] = $fevent['StartTime']; 212 } 213 } 214 215 // Calculate duration in minutes 216 if ( isset ( $event['duration'] ) ) { 217 $fevent['Duration'] = $event['duration']; 218 } else if ( empty ( $fevent['Duration'] ) ) { 219 $fevent['Duration'] = ($fevent['EndTime'] - $fevent['StartTime']) / 60; 220 } 221 if ( $fevent['Duration'] == '1440' ) { 222 // All day event... nothing to do here :-) 223 } else if ( preg_match ( "/\d\d\d\d\d\d\d\d$/", 224 $event['dtstart'], $pmatch ) ) { 225 // Untimed event 226 $fevent['Duration'] = 0; 227 $fevent['Untimed'] = 1; 228 } 229 if ( preg_match ( "/\d\d\d\d\d\d\d\d$/", $event['dtstart'], 230 $pmatch ) && preg_match ( "/\d\d\d\d\d\d\d\d$/", $event['dtend'], 231 $pmatch2 ) && $event['dtstart'] != $event['dtend'] ) { 232 $startTime = icaldate_to_timestamp($event['dtstart']); 233 $endTime = icaldate_to_timestamp($event['dtend']); 234 // Not sure... should this be untimed or allday? 235 if ( $endTime - $startTime == ( 3600 * 24 ) ) { 236 // They used a DTEND set to the next day to say this is an all day 237 // event. We will call this an untimed event. 238 $fevent['Duration'] = '0'; 239 $fevent['Untimed'] = 1; 240 } else { 241 // Event spans multiple days. The EndTime actually represents 242 // the first day the event does _not_ take place. So, 243 // we need to back up one day since WebCalendar end date is the 244 // last day the event takes place. 245 $fevent['Repeat']['Interval'] = '1'; // 1 = daily 246 $fevent['Repeat']['Frequency'] = '1'; // 1 = every day 247 $fevent['Duration'] = '0'; 248 $fevent['Untimed'] = 1; 249 $fevent['Repeat']['EndTime'] = $endTime - ( 24 * 3600 ); 250 } 251 } 252 253 $fevent['Summary'] = $event['summary']; 254 if ( ! empty ( $event['description'] ) ) { 255 $fevent['Description'] = $event['description']; 256 } else { 257 $fevent['Description'] = $event['summary']; 258 } 259 if ( ! empty ( $event['class'] ) ) { 260 $fevent['Private'] = preg_match("/private|confidential/i", 261 $event['class']) ? '1' : '0'; 262 } 263 $fevent['UID'] = $event['uid']; 264 265 // Repeats 266 // 267 // Handle RRULE 268 if ( ! empty ( $event['rrule'] ) ) { 269 // first remove and EndTime that may have been calculated above 270 unset ( $fevent['Repeat']['EndTime'] ); 271 //split into pieces 272 //echo "RRULE line: $event[rrule] <br />\n"; 273 $RR = explode ( ";", $event['rrule'] ); 274 275 // create an associative array of key-value paris in $RR2[] 276 for ( $i = 0; $i < count ( $RR ); $i++ ) { 277 $ar = explode ( "=", $RR[$i] ); 278 $RR2[$ar[0]] = $ar[1]; 279 } 280 281 for ( $i = 0; $i < count ( $RR ); $i++ ) { 282 //echo "RR $i = $RR[$i] <br />"; 283 if ( preg_match ( "/^FREQ=(.+)$/i", $RR[$i], $match ) ) { 284 if ( preg_match ( "/YEARLY/i", $match[1], $submatch ) ) { 285 $fevent['Repeat']['Interval'] = 5; 286 } else if ( preg_match ( "/MONTHLY/i", $match[1], $submatch ) ) { 287 $fevent['Repeat']['Interval'] = 2; 288 } else if ( preg_match ( "/WEEKLY/i", $match[1], $submatch ) ) { 289 $fevent['Repeat']['Interval'] = 2; 290 } else if ( preg_match ( "/DAILY/i", $match[1], $submatch ) ) { 291 $fevent['Repeat']['Interval'] = 1; 292 } else { 293 // not supported :-( 294 echo "Unsupported iCal FREQ value \"$match[1]\"<br />\n"; 295 } 296 } else if ( preg_match ( "/^INTERVAL=(.+)$/i", $RR[$i], $match ) ) { 297 $fevent['Repeat']['Frequency'] = $match[1]; 298 } else if ( preg_match ( "/^UNTIL=(.+)$/i", $RR[$i], $match ) ) { 299 // specifies an end date 300 $fevent['Repeat']['EndTime'] = icaldate_to_timestamp ( $match[1] ); 301 } else if ( preg_match ( "/^COUNT=(.+)$/i", $RR[$i], $match ) ) { 302 // NOT YET SUPPORTED -- TODO 303 echo "Unsupported iCal COUNT value \"$RR[$i]\"<br />\n"; 304 } else if ( preg_match ( "/^BYSECOND=(.+)$/i", $RR[$i], $match ) ) { 305 // NOT YET SUPPORTED -- TODO 306 echo "Unsupported iCal BYSECOND value \"$RR[$i]\"<br />\n"; 307 } else if ( preg_match ( "/^BYMINUTE=(.+)$/i", $RR[$i], $match ) ) { 308 // NOT YET SUPPORTED -- TODO 309 echo "Unsupported iCal BYMINUTE value \"$RR[$i]\"<br />\n"; 310 } else if ( preg_match ( "/^BYHOUR=(.+)$/i", $RR[$i], $match ) ) { 311 // NOT YET SUPPORTED -- TODO 312 echo "Unsupported iCal BYHOUR value \"$RR[$i]\"<br />\n"; 313 } else if ( preg_match ( "/^BYMONTH=(.+)$/i", $RR[$i], $match ) ) { 314 // this event repeats during the specified months 315 $months = explode ( ",", $match[1] ); 316 if ( count ( $months ) == 1 ) { 317 // Change this to a monthly event so we can support repeat by 318 // day of month (if needed) 319 // Frequency = 3 (by day), 4 (by date), 6 (by day reverse) 320 if ( ! empty ( $RR2['BYDAY'] ) ) { 321 if ( preg_match ( "/^-/", $RR2['BYDAY'], $junk ) ) 322 $fevent['Repeat']['Interval'] = 6; // monthly by day reverse 323 else 324 $fevent['Repeat']['Interval'] = 3; // monthly by day 325 $fevent['Repeat']['Frequency'] = 12; // once every 12 months 326 } else { 327 // could convert this to monthly by date, but we will just 328 // leave it as yearly. 329 //$fevent['Repeat']['Interval'] = 4; // monthly by date 330 } 331 } else { 332 // WebCalendar does not support this 333 echo "Unsupported iCal BYMONTH value \"$match[1]\"<br />\n"; 334 } 335 } else if ( preg_match ( "/^BYDAY=(.+)$/i", $RR[$i], $match ) ) { 336 $fevent['Repeat']['RepeatDays'] = rrule_repeat_days( $match[1] ); 337 } else if ( preg_match ( "/^BYMONTHDAY=(.+)$/i", $RR[$i], $match ) ) { 338 $fevent['Repeat']['Frequency'] = 4; //monthlyByDate 339 //echo "Partially Supported iCal BYSETPOS value \"$RR[$i]\"<br />\n"; 340 } else if ( preg_match ( "/^BYSETPOS=(.+)$/i", $RR[$i], $match ) ) { 341 // NOT YET SUPPORTED -- TODO 342 echo "Unsupported iCal BYSETPOS value \"$RR[$i]\"<br />\n"; 343 } 344 } 345 346 // Repeating exceptions? 347 if ( ! empty ( $event['exdate'] ) && $event['exdate']) { 348 $fevent['Repeat']['Exceptions'] = array(); 349 $EX = explode(",", $event['exdate']); 350 foreach ( $EX as $exdate ){ 351 $fevent['Repeat']['Exceptions'][] = icaldate_to_timestamp($exdate); 352 } 353 } 354 } // end if rrule 355 356 return $fevent; 357 } 358 359 // Figure out days of week for weekly repeats 360 function rrule_repeat_days($RA) { 361 $RA = explode(",", $RA ); 362 $T = count( $RA ) ; 363 $sun = $mon = $tue = $wed = $thu = $fri = $sat = 'n'; 364 for ($i = 0; $i < $T; $i++) { 365 if ($RA[$i] == 'SU') { 366 $sun = 'y'; 367 } elseif ($RA[$i] == 'MO') { 368 $mon = 'y'; 369 } elseif ($RA[$i] == 'TU') { 370 $tue = 'y'; 371 } elseif ($RA[$i] == 'WE') { 372 $wed = 'y'; 373 } elseif ($RA[$i] == 'TH') { 374 $thu = 'y'; 375 } elseif ($RA[$i] == 'FR') { 376 $fri = 'y'; 377 } elseif ($RA[$i] == 'SA') { 378 $sat = 'y'; 379 } 380 } 381 return $sun.$mon.$tue.$wed.$thu.$fri.$sat; 382 } 383 384 385 // Calculate repeating ending time 386 function rrule_endtime($int,$freq,$start,$end) { 387 388 // if # then we have to add the difference to the start time 389 if (preg_match("/^#(.+)$/i", $end, $M)) { 390 $T = $M[1] * $freq; 391 $plus_d = $plus_m = $plus_y = '0'; 392 if ($int == '1') { 393 $plus_d = $T; 394 } elseif ($int == '2') { 395 $plus_d = $T * 7; 396 } elseif ($int == '3') { 397 $plus_m = $T; 398 } elseif ($int == '4') { 399 $plus_m = $T; 400 } elseif ($int == '5') { 401 $plus_y = $T; 402 } elseif ($int == '6') { 403 $plus_m = $T; 404 } 405 $endtime = icaldate_to_timestamp($start,$plus_d,$plus_m,$plus_y); 406 407 // if we have the enddate 408 } else { 409 $endtime = icaldate_to_timestamp($end); 410 } 411 return $endtime; 412 } 413 414 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Nov 30 19:09:19 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |