You are here

function date_ical_import in Date 5

Same name in this branch
  1. 5 date_api_ical.inc \date_ical_import()
  2. 5 date_ical.inc \date_ical_import()
Same name and namespace in other branches
  1. 5.2 date_api_ical.inc \date_ical_import()
  2. 6.2 date_api_ical.inc \date_ical_import()
  3. 6 date_api_ical.inc \date_ical_import()
  4. 7.3 date_api/date_api_ical.inc \date_ical_import()
  5. 7 date_api/date_api_ical.inc \date_ical_import()
  6. 7.2 date_api/date_api_ical.inc \date_ical_import()

Return an array of iCalendar information from an iCalendar file.

No timezone adjustment is performed in the import since the timezone conversion needed will vary depending on whether the value is being imported into the database (when it needs to be converted to UTC), is being viewed on a site that has user-configurable timezones (when it needs to be converted to the user's timezone), if it needs to be converted to the site timezone, or if it is a date without a timezone which should not have any timezone conversion applied.

Properties that have dates and times are converted to sub-arrays like: 'datetime' => date in YYYY-MM-DD HH:MM format, not timezone adjusted 'all_day' => whether this is an all-day event 'tz' => the timezone of the date, could be blank for absolute times that should get no timezone conversion.

Exception dates can have muliple values and are returned as arrays like the above for each exception date.

Most other properties are returned as PROPERTY => VALUE.

Each item in the VCALENDAR will return an array like: [0] => Array ( [TYPE] => VEVENT [UID] => 104 [SUMMARY] => An example event [URL] => http://example.com/node/1 [DTSTART] => Array ( [datetime] => 1997-09-07 09:00:00 [all_day] => 0 [tz] => US/Eastern ) [DTEND] => Array ( [datetime] => 1997-09-07 11:00:00 [all_day] => 0 [tz] => US/Eastern ) [RRULE] => Array ( [FREQ] => Array ( [0] => MONTHLY ) [BYDAY] => Array ( [0] => 1SU [1] => -1SU ) ) [EXDATE] => Array ( [0] = Array ( [datetime] => 1997-09-21 09:00:00 [all_day] => 0 [tz] => US/Eastern ) [1] = Array ( [datetime] => 1997-10-05 09:00:00 [all_day] => 0 [tz] => US/Eastern ) ) )

@todo figure out how to handle this if subgroups are nested, like a VALARM nested inside a VEVENT.

Parameters

$filename: Location (local or remote) of a valid iCalendar file

Return value

array An array with all the elements from the ical

2 calls to date_ical_import()
date_copy_import_ical_form_submit in ./date_copy.module
date_copy_import_ical_form_validate in ./date_copy.module
iCal import processing.

File

./date_api_ical.inc, line 171
Parse iCal imports and create iCal exports. This file must be included when these functions are needed.

Code

function date_ical_import($filename) {
  $items = array();
  include_once './' . drupal_get_path('module', 'date_api') . '/date.inc';

  // Fetch the iCal data. If file is a URL, use drupal_http_request. fopen
  // isn't always configured to allow network connections.
  if (substr($filename, 0, 4) == 'http') {

    // Fetch the ical data from the specified network location
    $icaldatafetch = drupal_http_request($filename);

    // Check the return result
    if ($icaldatafetch->error) {
      drupal_set_message('Request Error: ' . $icaldatafetch->error, 'error');
      return array();
    }

    // Break the return result into one array entry per lines
    $icaldatafolded = explode("\n", $icaldatafetch->data);
  }
  else {
    $icaldatafolded = @file($filename, FILE_IGNORE_NEW_LINES);
    if ($icaldatafolded === FALSE) {
      drupal_set_message('Failed to open file: ' . $filename, 'error');
      return array();
    }
  }

  // Verify this is iCal data
  if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') {
    drupal_set_message('Invalid calendar file:' . $filename, 'error');
    return array();
  }

  // "unfold" wrapped lines
  $icaldata = array();
  foreach ($icaldatafolded as $line) {
    $out = array();

    // See if this looks like the beginning of a new property or value.
    // If not, it is a continuation of the previous line.
    ereg("([A-Z]+)[:|;](.*)", $line, $out);
    if (empty($out)) {
      $line = array_pop($icaldata) . "\n" . $line;
    }
    $icaldata[] = $line;
  }
  $icaldatafolded = NULL;

  // Parse the iCal information
  $is_subgroup = FALSE;
  $skip = FALSE;
  foreach ($icaldata as $line) {
    $line = trim($line);
    $vcal .= $line . "\n";
    switch ($line) {
      case 'BEGIN:VEVENT':
      case 'BEGIN:VALARM':
      case 'BEGIN:VTODO':
      case 'BEGIN:VJOURNAL':
      case 'BEGIN:VVENUE':
      case 'BEGIN:VFREEBUSY':
      case 'BEGIN:VTIMEZONE':
        unset($subgroup);
        $type = str_replace('BEGIN:', '', $line);
        $subgroup['TYPE'] = $type;
        $is_subgroup = TRUE;
        break;
      case 'END:VEVENT':
      case 'END:VALARM':
      case 'END:VTODO':
      case 'END:VJOURNAL':
      case 'END:VVENUE':
      case 'END:VFREEBUSY':
      case 'END:VTIMEZONE':

        // Can't be sure whether DTSTART is before or after DURATION,
        // so parse DURATION at the end.
        if (array_key_exists('DURATION', $subgroup)) {
          date_ical_parse_duration($subgroup);
        }

        // Check for all-day events.
        if (array_key_exists('DTSTART', $subgroup) && !array_key_exists(DTEND, $subgroup)) {
          $subgroup['DTSTART']['all_day'] = 1;
        }
        $items[] = $subgroup;
        unset($subgroup);
        $is_subgroup = FALSE;
        break;
      default:
        unset($field, $data, $prop_pos, $property);
        ereg("([^:]+):(.*)", $line, $reg);
        $field = $reg[1];
        $data = $reg[2];
        $property = $field;
        $prop_pos = strpos($property, ';');
        if ($prop_pos !== false) {
          $property = substr($property, 0, $prop_pos);
        }
        $property = strtoupper(trim($property));
        switch ($property) {

          // Keep blank lines out of the results.
          case '':
            break;

          // Lots of properties have date values that must be parsed out.
          case 'CREATED':
          case 'LAST-MODIFIED':
          case 'DTSTART':
          case 'DTEND':
          case 'DTSTAMP':
          case 'RDATE':
          case 'TRIGGER':
          case 'FREEBUSY':
          case 'DUE':
          case 'COMPLETED':
            if (!$is_subgroup) {
              $items[$property] = date_ical_parse_date($field, $data);
            }
            else {
              $subgroup[$property] = date_ical_parse_date($field, $data);
            }
            break;
          case 'EXDATE':
            $subgroup[$property] = date_ical_parse_exceptions($field, $data);
            break;
          case 'DURATION':

            // Can't be sure whether DTSTART is before or after DURATION in
            // the VEVENT, so store the data and parse it at the end.
            $subgroup['DURATION'] = array(
              'DATA' => $data,
            );
            break;
          case 'RRULE':
          case 'EXRULE':
            $subgroup[$property] = date_ical_parse_rule($field, $data);
            break;
          case 'SUMMARY':
          case 'DESCRIPTION':
          case 'LOCATION':
            $subgroup[$property] = date_ical_parse_text($field, $data);
            break;

          // For all other properties, just store the property and the value.
          // This can be expanded on in the future if other properties should
          // be given special treatment.
          default:
            if (!$is_subgroup) {
              $items[$property] = $data;
            }
            else {
              $subgroup[$property] = $data;
            }
            break;
        }
    }
  }

  // Store the original text in the array for reference.
  $items['VCALENDAR'] = $vcal;
  return $items;
}