ical.inc in Event 5
Same filename and directory in other branches
API for event import/export in iCalendar format as outlined in Internet Calendaring and Scheduling Core Object Specification http://www.ietf.org/rfc/rfc2445.txt
This module is IN DEVELOPMENT and not a finished product
File
ical.incView source
<?php
/**
* @file
* API for event import/export in iCalendar format as outlined in Internet Calendaring and Scheduling Core Object Specification
* http://www.ietf.org/rfc/rfc2445.txt
*
* This module is IN DEVELOPMENT and not a finished product
*/
/**
* Turn an array of events into a valid iCalendar file
*
* @param $events
* An array of associative arrays where
* 'start' => Unix timestamp (GMT) of start time (Required, if no allday_start)
* 'end' => Unix timestamp (GMT) of end time (Optional)
* 'allday_start' => Start date of all-day event in YYYYMMDD format (Required, if no start)
* 'allday_end' => End date of all-day event in YYYYMMDD format (Optional)
* 'summary' => Title of event (Text)
* 'description' => Description of event (Text)
* 'location' => Location of event (Text)
* 'uid' => ID of the event for use by calendaring program. Recommend the url of the node
* 'url' => URL of event information
*
* @param $calname
* Name of the calendar. Will use site name if none is specified.
*
* @return
* Text of a iCalendar file
*/
function ical_export($events, $calname = NULL) {
$output .= "BEGIN:VCALENDAR\nVERSION:2.0\n";
$output .= "METHOD:PUBLISH\n";
$output .= 'X-WR-CALNAME:' . variable_get('site_name', '') . ' | ' . ical_escape_text($calname) . "\n";
$output .= "PRODID:-//strange bird labs//Drupal iCal API//EN\n";
foreach ($events as $uid => $event) {
$output .= "BEGIN:VEVENT\n";
$output .= "DTSTAMP;VALUE=DATE:" . gmdate("Ymd\\THis\\Z", time()) . "\n";
if ($event['allday_start'] && $event['allday_end']) {
$output .= "DTSTART;VALUE=DATE:" . $event['allday_start'] . "\n";
$output .= "DTEND;VALUE=DATE:" . $event['allday_end'] . "\n";
}
else {
if ($event['allday_start'] && empty($event['allday_end'])) {
$output .= "DTSTART;VALUE=DATE:" . $event['allday_start'] . "\n";
$output .= "DTEND;VALUE=DATE:" . date('Ymd', strtotime($event['allday_start']) + 86400) . "\n";
//If no allday end date, set to day after allday start
}
else {
if ($event['start'] && $event['end']) {
$output .= "DTSTART;VALUE=DATE-TIME:" . gmdate("Ymd\\THis\\Z", $event['start']) . "\n";
$output .= "DTEND;VALUE=DATE-TIME:" . gmdate("Ymd\\THis\\Z", $event['end']) . "\n";
}
else {
if ($event['start']) {
$output .= "DTSTART;VALUE=DATE-TIME:" . gmdate("Ymd\\THis\\Z", $event['start']) . "\n";
}
}
}
}
$output .= "UID:" . ($event['uid'] ? $event['uid'] : $uid) . "\n";
if ($event['url']) {
$output .= "URL;VALUE=URI:" . $event['url'] . "\n";
}
if ($event['location']) {
$output .= "LOCATION:" . ical_escape_text($event['location']) . "\n";
}
$output .= "SUMMARY:" . ical_escape_text($event['summary']) . "\n";
if ($event['description']) {
$output .= "DESCRIPTION:" . ical_escape_text($event['description']) . "\n";
}
$output .= "END:VEVENT\n";
}
$output .= "END:VCALENDAR\n";
return $output;
}
/**
* Escape #text elements for safe iCal use
*
* @param $text
* Text to escape
*
* @return
* Escaped text
*
*/
function ical_escape_text($text) {
//$text = strip_tags($text);
$text = str_replace('"', '\\"', $text);
$text = str_replace("\\", "\\\\", $text);
$text = str_replace(",", "\\,", $text);
$text = str_replace(":", "\\:", $text);
$text = str_replace(";", "\\;", $text);
$text = str_replace("\n", "\n ", $text);
return $text;
}
/**
* Given the location of a valide iCalendar file, will return an array of event information
*
* @param $filename
* Location (local or remote) of a valid iCalendar file
*
* @return
* An array of associative arrays where
* 'start' => Unix timestamp (GMT) of start time
* 'end' => Unix timestamp (GMT) of end time
* 'allday_start' => Start date of all-day event in YYYYMMDD format
* 'allday_end' => End date of all-day event in YYYYMMDD format
* 'summary' => Title of event
* 'description' => Description of event
* 'location' => Location of event
* 'uid' => ID of the event in calendaring program
* 'url' => URL of event information *
*/
function ical_import($filename) {
$items = array();
$ifile = @fopen($filename, "r");
if ($ifile == FALSE) {
exit('Invalid input file');
}
$nextline = fgets($ifile, 1024);
if (trim($nextline) != 'BEGIN:VCALENDAR') {
exit('Invalid calendar file:' . $filename);
}
while (!feof($ifile)) {
$line = $nextline;
$nextline = fgets($ifile, 1024);
$nextline = ereg_replace("[\r\n]", "", $nextline);
while (substr($nextline, 0, 1) == " ") {
$line = $line . substr($nextline, 1);
$nextline = fgets($ifile, 1024);
$nextline = ereg_replace("[\r\n]", "", $nextline);
}
$line = trim($line);
switch ($line) {
case 'BEGIN:VEVENT':
unset($start_unixtime, $start_date, $start_time, $end_unixtime, $end_date, $end_time, $allday_start, $allday_end, $the_duration, $uid, $summary, $description, $url, $location);
break;
case 'END:VEVENT':
if (empty($uid)) {
$uid = $uid_counter;
$uid_counter++;
}
if (empty($end_unixtime) && isset($the_duration)) {
$end_unixtime = $start_unixtime + $the_duration;
$end_time = date('Hi', $end_unixtime);
}
$items[$uid] = array(
'start' => $start_unixtime,
'end' => $end_unixtime,
'allday_start' => $allday_start,
'allday_end' => $allday_end,
'summary' => $summary,
'description' => $description,
'location' => $location,
'url' => $url,
'uid' => $uid,
);
break;
default:
unset($field, $data, $prop_pos, $property);
ereg("([^:]+):(.*)", $line, $line);
$field = $line[1];
$data = $line[2];
$property = $field;
$prop_pos = strpos($property, ';');
if ($prop_pos !== false) {
$property = substr($property, 0, $prop_pos);
}
$property = strtoupper($property);
switch ($property) {
case 'DTSTART':
$zulu_time = false;
if (substr($data, -1) == 'Z') {
$zulu_time = true;
}
$data = str_replace('T', '', $data);
$data = str_replace('Z', '', $data);
$field = str_replace(';VALUE=DATE-TIME', '', $field);
if (preg_match("/^DTSTART;VALUE=DATE/i", $field) || ereg('^([0-9]{4})([0-9]{2})([0-9]{2})$', $data)) {
ereg('([0-9]{4})([0-9]{2})([0-9]{2})', $data, $dtstart_check);
$allday_start = $data;
$start_date = $allday_start;
$start_unixtime = strtotime($data);
}
else {
if (preg_match("/^DTSTART;TZID=/i", $field)) {
$tz_tmp = explode('=', $field);
$tz_dtstart = $tz_tmp[1];
unset($tz_tmp);
}
elseif ($zulu_time) {
$tz_dtstart = 'GMT';
}
preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})/', $data, $regs);
$start_date = $regs[1] . $regs[2] . $regs[3];
$start_time = $regs[4] . $regs[5];
$start_unixtime = mktime($regs[4], $regs[5], 0, $regs[2], $regs[3], $regs[1]);
$dlst = date('I', $start_unixtime);
$server_offset_tmp = _ical_chooseOffset($start_unixtime, 'Same as Server');
if (isset($tz_dtstart)) {
if ($tz = _ical_tz($tz_dtstart)) {
$offset_tmp = date('I', $start_unixtime) ? $tz->offset_dst : $tz->offset;
}
else {
$offset_tmp = '+0000';
}
}
else {
if (isset($calendar_tz)) {
if ($tz = _ical_tz($calendar_tz)) {
$offset_tmp = date('I', $start_unixtime) ? $tz->offset_dst : $tz->offset;
}
else {
$offset_tmp = '+0000';
}
}
else {
$offset_tmp = $server_offset_tmp;
}
}
$start_unixtime = _ical_calcTime($offset_tmp, $server_offset_tmp, $start_unixtime);
$start_date = date('Ymd', $start_unixtime);
$start_time = date('Hi', $start_unixtime);
unset($server_offset_tmp, $offset_tmp, $tz_dtstart);
}
break;
case 'DTEND':
$zulu_time = false;
if (substr($data, -1) == 'Z') {
$zulu_time = true;
}
$data = str_replace('T', '', $data);
$data = str_replace('Z', '', $data);
$field = str_replace(';VALUE=DATE-TIME', '', $field);
if (preg_match("/^DTEND;VALUE=DATE/i", $field) || ereg('^([0-9]{4})([0-9]{2})([0-9]{2})$', $data)) {
$allday_end = $data;
$end_date = $allday_end;
$end_unixtime = strtotime($data);
}
else {
if (preg_match("/^DTEND;TZID=/i", $field)) {
$tz_tmp = explode('=', $field);
$tz_dtend = $tz_tmp[1];
unset($tz_tmp);
}
elseif ($zulu_time) {
$tz_dtend = 'GMT';
}
preg_match('/([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{0,2})([0-9]{0,2})/', $data, $regs);
$end_date = $regs[1] . $regs[2] . $regs[3];
$end_time = $regs[4] . $regs[5];
$end_unixtime = mktime($regs[4], $regs[5], 0, $regs[2], $regs[3], $regs[1]);
$server_offset_tmp = _ical_chooseOffset($end_unixtime, 'Same as Server');
if (isset($tz_dtend)) {
if ($tz = _ical_tz($tz_dtend)) {
$offset_tmp = date('I', $end_unixtime) ? $tz->offset_dst : $tz->offset;
}
else {
$offset_tmp = '+0000';
}
}
else {
if (isset($calendar_tz)) {
if ($tz = _ical_tz($calendar_tz)) {
$offset_tmp = date('I', $end_unixtime) ? $tz->offset_dst : $tz->offset;
}
else {
$offset_tmp = '+0000';
}
}
else {
$offset_tmp = $server_offset_tmp;
}
}
$end_unixtime = _ical_calcTime($offset_tmp, $server_offset_tmp, $end_unixtime);
$end_date = date('Ymd', $end_unixtime);
$end_time = date('Hi', $end_unixtime);
unset($server_offset_tmp, $offset_tmp, $tz_dtend);
}
break;
case 'DURATION':
if (!stristr($field, '=DURATION')) {
ereg('^P([0-9]{1,2}[W])?([0-9]{1,2}[D])?([T]{0,1})?([0-9]{1,2}[H])?([0-9]{1,2}[M])?([0-9]{1,2}[S])?', $data, $duration);
$weeks = str_replace('W', '', $duration[1]);
$days = str_replace('D', '', $duration[2]);
$hours = str_replace('H', '', $duration[4]);
$minutes = str_replace('M', '', $duration[5]);
$seconds = str_replace('S', '', $duration[6]);
$the_duration = $weeks * 60 * 60 * 24 * 7 + $days * 60 * 60 * 24 + $hours * 60 * 60 + $minutes * 60 + $seconds;
}
break;
case 'SUMMARY':
$summary = $data;
break;
case 'DESCRIPTION':
$description = $data;
break;
case 'UID':
$uid = $data;
break;
case 'X-WR-CALNAME':
$actual_calname = $data;
break;
case 'X-WR-TIMEZONE':
$calendar_tz = $data;
break;
case 'LOCATION':
$location = $data;
break;
case 'URL':
$url = $data;
break;
}
}
}
return $items;
}
function ical_help($section) {
switch ($section) {
case 'admin/modules#description':
return t('iCalendar API for Events Modules');
break;
}
}
function _ical_tz($tz) {
include_once drupal_get_path('module', 'event') . '/event_timezones.inc';
foreach (event_get_timezones() as $delta => $zone) {
if ($tz == $zone['timezone']) {
}
return (object) $zone;
}
}
function _ical_chooseOffset($time, $timezone) {
if (!isset($timezone)) {
$timezone = '';
}
switch ($timezone) {
case '':
$offset = 'none';
break;
case 'Same as Server':
$offset = date('O', $time);
break;
default:
if ($tz = _ical_tz($timezone)) {
$offset = date('I', $time) ? $tz->offset_dst : $tz->offset;
}
else {
$offset = '+0000';
}
}
return $offset;
}
function _ical_calcTime($have, $want, $time) {
if ($have == 'none' || $want == 'none') {
return $time;
}
$have_secs = _ical_calcOffset($have);
$want_secs = _ical_calcOffset($want);
$diff = $want_secs - $have_secs;
$time += $diff;
return $time;
}
function _ical_calcOffset($offset_str) {
$sign = substr($offset_str, 0, 1);
$hours = substr($offset_str, 1, 2);
$mins = substr($offset_str, 3, 2);
$secs = (int) $hours * 3600 + (int) $mins * 60;
if ($sign == '-') {
$secs = 0 - $secs;
}
return $secs;
}
/**
* escape ical separators in quoted-printable encoded code
*/
function ical_quoted_printable_escaped($string) {
$replace = array(
";" => "\\;",
":" => "\\:",
);
return strtr(ical_quoted_printable_encode($string), $replace);
}
/**
* encode text using quoted-printable standard
*/
function ical_quoted_printable_encode($text, $line_max = 76) {
$hex = array(
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'A',
'B',
'C',
'D',
'E',
'F',
);
$lines = preg_split("/(?:\r\n|\r|\n)/", $text);
$eol = "\r\n";
$linebreak = "=0D=0A";
$escape = "=";
$output = "";
for ($x = 0; $x < count($lines); $x++) {
$line = $lines[$x];
$line_len = strlen($line);
$newline = "";
for ($i = 0; $i < $line_len; $i++) {
$c = substr($line, $i, 1);
$dec = ord($c);
// convert space at end of line
if ($dec == 32 && $i == $line_len - 1) {
$c = $escape . "20";
}
elseif ($dec == 61 || $dec < 32 || $dec > 126) {
$h2 = floor($dec / 16);
$h1 = floor($dec % 16);
$c = $escape . $hex["{$h2}"] . $hex["{$h1}"];
}
// see if new output line is needed
if (strlen($newline) + strlen($c) >= $line_max) {
$output .= $newline . $escape . $eol;
$newline = "";
}
$newline .= $c;
}
$output .= $newline;
// skip last line feed
if ($x < count($lines) - 1) {
$output .= $linebreak;
}
}
return trim($output);
}
Functions
Name | Description |
---|---|
ical_escape_text | Escape #text elements for safe iCal use |
ical_export | Turn an array of events into a valid iCalendar file |
ical_help | |
ical_import | Given the location of a valide iCalendar file, will return an array of event information |
ical_quoted_printable_encode | encode text using quoted-printable standard |
ical_quoted_printable_escaped | escape ical separators in quoted-printable encoded code |
_ical_calcOffset | |
_ical_calcTime | |
_ical_chooseOffset | |
_ical_tz |