function ics_import_parse($cal_file, $uid = NULL) { global $tz, $errormsg, $TZOffset, $TZOffsetDaylight; $ical_data = array(); if (!($fd = @fopen($cal_file, "r"))) { $errormsg .= "Can't read temporary file: {$cal_file}\n"; exit; } else { // Read in contents of entire file first $data = ''; while (!feof($fd) && !$error) { $line++; $data .= fgets($fd, 4096); } fclose($fd); // Now fix folding. According to RFC, lines can fold by having // a CRLF and then a single white space character. // We will allow it to be CRLF, CR or LF or any repeated sequence // so long as there is a single white space character next. //echo "Orig:<br><pre>$data</pre><br/><br/>\n"; $data = preg_replace("/[\r\n]+ /", "", $data); $data = preg_replace("/[\r\n]+/", "\n", $data); //echo "Data:<br><pre>$data</pre><P>"; // reflect the section where we are in the file: // VEVENT, VTODO, VJOURNAL, VFREEBUSY, VTIMEZONE $state = "NONE"; $substate = "none"; // reflect the sub section $subsubstate = ""; // reflect the sub-sub section $error = false; $line = 0; $event = ''; $lines = explode("\n", $data); for ($n = 0; $n < count($lines) && !$error; $n++) { $line++; $buff = $lines[$n]; $y = $n + 1; while (preg_match("/^\\s/", $lines[$y])) { $buff .= trim($lines[$y]); $lines[$y] = NULL; $y++; } if ($state == "VEVENT") { $event['RAW'][] = $buff; if (!empty($subsubstate)) { if (preg_match("/^END:(.+)\$/i", $buff, $match)) { if ($match[1] == $subsubstate) { $subsubstate = ''; } } else { if ($subsubstate == "VALARM" && preg_match("/TRIGGER:(.+)\$/i", $buff, $match)) { // Example: TRIGGER;VALUE=DATE-TIME:19970317T133000Z //echo "Set reminder to $match[1]<br />"; // reminder time is $match[1] } } } else { if (preg_match("/^BEGIN:(.+)\$/i", $buff, $match)) { $subsubstate = $match[1]; } else { if (preg_match("/^SUMMARY[^:]*:(.+)\$/i", $buff, $match)) { $substate = "summary"; $event[$substate] = $match[1]; } elseif (preg_match("/^DESCRIPTION[^:]*:(.+)\$/i", $buff, $match)) { $substate = "description"; $event[$substate] = $match[1]; } elseif (preg_match("/^LOCATION[^:]*:(.+)\$/i", $buff, $match)) { $substate = "location"; $event[$substate] = $match[1]; } elseif (preg_match("/^URL(?:;VALUE=[^:]+)?:(.+)\$/i", $buff, $match)) { $substate = "url"; $event[$substate] = $match[1]; } elseif (preg_match("/^CLASS[^:]*:(.*)\$/i", $buff, $match)) { $substate = "class"; $event[$substate] = $match[1]; } elseif (preg_match("/^PRIORITY[^:]*:(.*)\$/i", $buff, $match)) { $substate = "priority"; $event[$substate] = $match[1]; } elseif (preg_match("/^DTSTART[^:]*:\\s*(\\d+T\\d+Z?)\\s*\$/i", $buff, $match)) { $substate = "dtstart"; $event[$substate] = $match[1]; } elseif (preg_match("/^DTSTART[^:]*:\\s*(\\d+)\\s*\$/i", $buff, $match)) { $substate = "dtstart"; $event[$substate] = $match[1]; } elseif (preg_match("/^DTEND[^:]*:\\s*(.*)\\s*\$/i", $buff, $match)) { $substate = "dtend"; $event[$substate] = $match[1]; } elseif (preg_match("/^DURATION[^:]*:(.+)\\s*\$/i", $buff, $match)) { $substate = "duration"; $durH = $durM = $durS = 0; if (preg_match("/PT(?:([0-9]+)H)?(?:([0-9]+)M)?(?:([0-9]+)S)?/", $match[1], $submatch)) { $durH = $submatch[1]; $durM = $submatch[2]; $durS = $submatch[3]; } $event[$substate] = $durH * 60 + $durM + $durS / 60; } elseif (preg_match("/^RRULE[^:]*:(.+)\$/i", $buff, $match)) { $substate = "rrule"; $event[$substate] = $match[1]; } elseif (preg_match("/^EXDATE[^:]*:(.+)\$/i", $buff, $match)) { $substate = "exdate"; if (empty($event[$substate])) { $event[$substate] = $match[1] . ','; } else { $event[$substate] .= $match[1] . ','; } } elseif (preg_match("/^ATTACH[^:]*:(.+)\$/i", $buff, $match)) { $substate = "attach"; $event[$substate] = $match[1]; } elseif (preg_match("/^CATEGORIES[^:]*:(.+)\$/i", $buff, $match)) { $substate = "categories"; $event[$substate] = $match[1]; } elseif (preg_match("/^STATUS[^:]*:(.+)\$/i", $buff, $match)) { $substate = "status"; $event[$substate] = $match[1]; } elseif (preg_match("/^RECURRENCE-ID[^:]*:\\s*(.*)\\s*\$/i", $buff, $match)) { $substate = "recurrence-id"; $event[$substate] = $match[1]; } elseif (preg_match("/^UID[^:]*:(.+)\$/i", $buff, $match)) { $substate = "uid"; $event[$substate] = $match[1]; } elseif (preg_match("/^END:VEVENT\$/i", $buff, $match)) { $state = "VCALENDAR"; $substate = "none"; $subsubstate = ''; if (!isset($uid) || $event['uid'] == $uid) { $ical_data[] = format_ical($event); } // clear out data for new event $event = ''; // TODO: QUOTED-PRINTABLE descriptions // folded lines // TODO: This is not the best way to handle folded lines. // We should fix the folding before we parse... } elseif (preg_match("/^\\s(\\S.*)\$/", $buff, $match)) { if ($substate != "none") { $event[$substate] .= $match[1]; } else { $errormsg .= "iCal parse error on line {$line}:<br />{$buff}\n"; $error = true; } // For unsupported properties } else { $substate = "none"; } } } } elseif ($state == "VCALENDAR") { if (preg_match("/^BEGIN:VEVENT/i", $buff)) { $state = "VEVENT"; } elseif (preg_match("/^END:VCALENDAR/i", $buff)) { $state = "NONE"; } else { if (preg_match("/^BEGIN:VTIMEZONE/i", $buff)) { $state = "VTIMEZONE"; } else { if (preg_match("/^BEGIN:VALARM/i", $buff)) { $state = "VALARM"; } } } } elseif ($state == "VTIMEZONE") { // We don't do much with timezone info yet... if ($substate == "DAYLIGHT") { if (preg_match("/^END:DAYLIGHT\$/i", $buff)) { $substate = ""; } elseif (preg_match("/^TZOFFSETTO[^:]*:(.+)\$/i", $buff, $match)) { $TZOffsetDaylight = $match[1]; } } else { if (preg_match("/^BEGIN:DAYLIGHT\$/i", $buff)) { $substate = "DAYLIGHT"; } elseif (preg_match("/^END:VTIMEZONE\$/i", $buff)) { $state = "VCALENDAR"; } elseif (preg_match("/^TZOFFSETTO[^:]*:(.+)\$/i", $buff, $match)) { $TZOffset = $match[1]; } } } elseif ($state == "NONE") { if (preg_match("/^BEGIN:VCALENDAR\$/i", $buff)) { $state = "VCALENDAR"; } } } // End while } return $ical_data; }
function parse_ical($cal_file) { global $tz, $errormsg; $ical_data = array(); if (!($fd = @fopen($cal_file, "r"))) { $errormsg .= "Can't read temporary file: {$cal_file}\n"; exit; } else { // Read in contents of entire file first $data = ''; $line = 0; while (!feof($fd) && empty($error)) { $line++; $data .= fgets($fd, 4096); } fclose($fd); // Now fix folding. According to RFC, lines can fold by having // a CRLF and then a single white space character. // We will allow it to be CRLF, CR or LF or any repeated sequence // so long as there is a single white space character next. //echo "Orig:<br><pre>$data</pre><br/><br/>\n"; $data = preg_replace("/[\r\n]+ /", "", $data); $data = preg_replace("/[\r\n]+/", "\n", $data); //echo "Data:<br><pre>$data</pre><p>"; // reflect the section where we are in the file: // VEVENT, VTODO, VJORNAL, VFREEBUSY, VTIMEZONE $state = "NONE"; $substate = "none"; // reflect the sub section $subsubstate = ""; // reflect the sub-sub section $error = false; $line = 0; $event = ''; $lines = explode("\n", $data); for ($n = 0; $n < count($lines) && !$error; $n++) { $line++; $buff = $lines[$n]; // parser debugging code... //echo "line = $line <br />"; //echo "state = $state <br />"; //echo "substate = $substate <br />"; //echo "subsubstate = $subsubstate <br />"; //echo "buff = " . htmlspecialchars ( $buff ) . "<br /><br />\n"; if ($state == "VEVENT") { if (!empty($subsubstate)) { if (preg_match("/^END:(.+)\$/i", $buff, $match)) { if ($match[1] == $subsubstate) { $subsubstate = ''; } } else { if ($subsubstate == "VALARM" && preg_match("/TRIGGER:(.+)\$/i", $buff, $match)) { // Example: TRIGGER;VALUE=DATE-TIME:19970317T133000Z //echo "Set reminder to $match[1]<br />"; // reminder time is $match[1] } } } else { if (preg_match("/^BEGIN:(.+)\$/i", $buff, $match)) { $subsubstate = $match[1]; } else { if (preg_match("/^SUMMARY.*:(.+)\$/i", $buff, $match)) { $substate = "summary"; $event[$substate] = $match[1]; } elseif (preg_match("/^DESCRIPTION:(.+)\$/i", $buff, $match)) { $substate = "description"; $event[$substate] = $match[1]; } elseif (preg_match("/^DESCRIPTION.*:(.+)\$/i", $buff, $match)) { $substate = "description"; $event[$substate] = $match[1]; } elseif (preg_match("/^CLASS.*:(.*)\$/i", $buff, $match)) { $substate = "class"; $event[$substate] = $match[1]; } elseif (preg_match("/^PRIORITY.*:(.*)\$/i", $buff, $match)) { $substate = "priority"; $event[$substate] = $match[1]; } elseif (preg_match("/^DTSTART.*:\\s*(\\d+T\\d+Z?)\\s*\$/i", $buff, $match)) { $substate = "dtstart"; $event[$substate] = $match[1]; } elseif (preg_match("/^DTSTART.*:\\s*(\\d+)\\s*\$/i", $buff, $match)) { $substate = "dtstart"; $event[$substate] = $match[1]; } elseif (preg_match("/^DTEND.*:\\s*(.*)\\s*\$/i", $buff, $match)) { $substate = "dtend"; $event[$substate] = $match[1]; } elseif (preg_match("/^DURATION.*:(.+)\\s*\$/i", $buff, $match)) { $substate = "duration"; $durH = $durM = 0; if (preg_match("/PT.*([0-9]+)H/", $match[1], $submatch)) { $durH = $submatch[1]; } if (preg_match("/PT.*([0-9]+)M/", $match[1], $submatch)) { $durM = $submatch[1]; } $event[$substate] = $durH * 60 + $durM; } elseif (preg_match("/^RRULE.*:(.+)\$/i", $buff, $match)) { $substate = "rrule"; $event[$substate] = $match[1]; } elseif (preg_match("/^EXDATE.*:(.+)\$/i", $buff, $match)) { $substate = "exdate"; $event[$substate] = $match[1]; } elseif (preg_match("/^CATEGORIES.*:(.+)\$/i", $buff, $match)) { $substate = "categories"; $event[$substate] = $match[1]; } elseif (preg_match("/^UID.*:(.+)\$/i", $buff, $match)) { $substate = "uid"; $event[$substate] = $match[1]; } elseif (preg_match("/^END:VEVENT\$/i", $buff, $match)) { $state = "VCALENDAR"; $substate = "none"; $subsubstate = ''; if ($tmp_data = format_ical($event)) { $ical_data[] = $tmp_data; } // clear out data for new event $event = ''; // TODO: QUOTED-PRINTABLE descriptions // folded lines // TODO: This is not the best way to handle folded lines. // We should fix the folding before we parse... } elseif (preg_match("/^\\s(\\S.*)\$/", $buff, $match)) { if ($substate != "none") { $event[$substate] .= $match[1]; } else { $errormsg .= "iCal parse error on line {$line}:<br />{$buff}\n"; $error = true; } // For unsupported properties } else { $substate = "none"; } } } } elseif ($state == "VCALENDAR") { if (preg_match("/^BEGIN:VEVENT/i", $buff)) { $state = "VEVENT"; } elseif (preg_match("/^END:VCALENDAR/i", $buff)) { $state = "NONE"; } else { if (preg_match("/^BEGIN:VTIMEZONE/i", $buff)) { $state = "VTIMEZONE"; } else { if (preg_match("/^BEGIN:VALARM/i", $buff)) { $state = "VALARM"; } } } } elseif ($state == "VTIMEZONE") { // We don't do much with timezone info yet... if (preg_match("/^END:VTIMEZONE\$/i", $buff)) { $state = "VCALENDAR"; } } elseif ($state == "NONE") { if (preg_match("/^BEGIN:VCALENDAR\$/i", $buff)) { $state = "VCALENDAR"; } } } // End while } return $ical_data; }
function parse_hcal($hcal_array) { global $tz, $errormsg; $ical_data = array(); $error = false; $event = ''; if (!is_array($hcal_array)) { return false; } foreach ($hcal_array as $hcal) { foreach ($hcal as $key => $value) { $value = trim($value); // set default UID $event['uid'] = generate_uid(1); // parser debugging code... // echo "buff = " . htmlspecialchars ( $buff ) . "<br /><br />\n"; if ($key == 'SUMMARY') { $substate = 'summary'; $event[$substate] = $value; } elseif ($key == 'DESCRIPTION') { $substate = 'description'; $event[$substate] = $value; } elseif ($key == 'CLASS') { $substate = 'class'; $event[$substate] = $value; } elseif ($key == 'LOCATION') { $substate = 'location'; $event[$substate] = $value; } elseif ($key == 'URL') { $substate = 'url'; $event[$substate] = $value; } elseif ($key == 'TRANSP') { $substate = 'transparency'; $event[$substate] = $value; } elseif ($key == 'STATUS') { $substate = 'status'; $event[$substate] = $value; } elseif ($key == 'PRIORITY') { $substate = 'priority'; $event[$substate] = $value; } elseif ($key == 'DTSTART') { $substate = 'dtstart'; $event[$substate] = $value; if (strlen($value) > 8) { $substate = 'dtstartDATETIME'; $event[$substate] = true; } else { $substate = 'dtstartDATE'; $event[$substate] = true; } } elseif ($key == 'DTEND') { $substate = 'dtend'; $event[$substate] = $value; if (strlen($value) > 8) { $substate = 'dtendDATETIME'; $event[$substate] = true; } else { $substate = 'dtendDATE'; $event[$substate] = true; } } elseif ($key == 'TZ') { $substate = 'tzid'; $event[$substate] = $value; } elseif ($key == 'DUE') { $substate = 'due'; $event[$substate] = $value; } elseif ($key == 'COMPLETED') { $substate = 'completed'; $event[$substate] = $value; } elseif ($key == 'PERCENT-COMPLETE') { $substate = 'percent'; $event[$substate] = $value; } elseif ($key == 'DURATION') { $substate = 'duration'; $event[$substate] = parse_ISO8601_duration($value); } elseif ($key == 'RRULE') { $substate = 'rrule'; $event[$substate] = $value; } elseif ($key == 'EXDATE') { $substate = 'exdate'; // allows multiple ocurrances of EXDATE to be processed if (isset($event[$substate])) { $event[$substate] .= ',' . $value; } else { $event[$substate] = $value; } } elseif ($key == 'RDATE') { $substate = 'rdate'; // allows multiple ocurrances of RDATE to be processed if (isset($event[$substate])) { $event[$substate] .= ',' . $value; } else { $event[$substate] = $value; } } elseif ($key == 'CATEGORIES') { $substate = 'categories'; // allows multiple ocurrances of CATEGORIES to be processed if (isset($event[$substate])) { $event[$substate] .= ',' . $value; } else { $event[$substate] = $value; } } elseif ($key == 'UID') { $substate = 'uid'; $event[$substate] = $value; } } // End foreach $hcal $event['state'] = 'VEVENT'; if ($tmp_data = format_ical($event)) { $hcal_data[] = $tmp_data; } $event = ''; } // End foreach $hcal_array return $hcal_data; }