| [ Index ] |
PHP Cross Reference of Drupal 6 (yi-drupal) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * @file 4 * Parse iCal data. 5 * 6 * This file must be included when these functions are needed. 7 */ 8 /** 9 * Return an array of iCalendar information from an iCalendar file. 10 * 11 * No timezone adjustment is performed in the import since the timezone 12 * conversion needed will vary depending on whether the value is being 13 * imported into the database (when it needs to be converted to UTC), is being 14 * viewed on a site that has user-configurable timezones (when it needs to be 15 * converted to the user's timezone), if it needs to be converted to the 16 * site timezone, or if it is a date without a timezone which should not have 17 * any timezone conversion applied. 18 * 19 * Properties that have dates and times are converted to sub-arrays like: 20 * 'datetime' => date in YYYY-MM-DD HH:MM format, not timezone adjusted 21 * 'all_day' => whether this is an all-day event 22 * 'tz' => the timezone of the date, could be blank for absolute 23 * times that should get no timezone conversion. 24 * 25 * Exception dates can have muliple values and are returned as arrays 26 * like the above for each exception date. 27 * 28 * Most other properties are returned as PROPERTY => VALUE. 29 * 30 * Each item in the VCALENDAR will return an array like: 31 * [0] => Array ( 32 * [TYPE] => VEVENT 33 * [UID] => 104 34 * [SUMMARY] => An example event 35 * [URL] => http://example.com/node/1 36 * [DTSTART] => Array ( 37 * [datetime] => 1997-09-07 09:00:00 38 * [all_day] => 0 39 * [tz] => US/Eastern 40 * ) 41 * [DTEND] => Array ( 42 * [datetime] => 1997-09-07 11:00:00 43 * [all_day] => 0 44 * [tz] => US/Eastern 45 * ) 46 * [RRULE] => Array ( 47 * [FREQ] => Array ( 48 * [0] => MONTHLY 49 * ) 50 * [BYDAY] => Array ( 51 * [0] => 1SU 52 * [1] => -1SU 53 * ) 54 * ) 55 * [EXDATE] => Array ( 56 * [0] = Array ( 57 * [datetime] => 1997-09-21 09:00:00 58 * [all_day] => 0 59 * [tz] => US/Eastern 60 * ) 61 * [1] = Array ( 62 * [datetime] => 1997-10-05 09:00:00 63 * [all_day] => 0 64 * [tz] => US/Eastern 65 * ) 66 * ) 67 * [RDATE] => Array ( 68 * [0] = Array ( 69 * [datetime] => 1997-09-21 09:00:00 70 * [all_day] => 0 71 * [tz] => US/Eastern 72 * ) 73 * [1] = Array ( 74 * [datetime] => 1997-10-05 09:00:00 75 * [all_day] => 0 76 * [tz] => US/Eastern 77 * ) 78 * ) 79 * ) 80 * 81 * @param $filename 82 * Location (local or remote) of a valid iCalendar file 83 * @return array 84 * An array with all the elements from the ical 85 * @todo 86 * figure out how to handle this if subgroups are nested, 87 * like a VALARM nested inside a VEVENT. 88 */ 89 function date_ical_import($filename) { 90 // Fetch the iCal data. If file is a URL, use drupal_http_request. fopen 91 // isn't always configured to allow network connections. 92 if (substr($filename, 0, 4) == 'http') { 93 // Fetch the ical data from the specified network location 94 $icaldatafetch = drupal_http_request($filename); 95 // Check the return result 96 if ($icaldatafetch->error) { 97 watchdog('date ical', 'HTTP Request Error importing %filename: @error', array('%filename' => $filename, '@error' => $icaldatafetch->error)); 98 return false; 99 } 100 // Break the return result into one array entry per lines 101 $icaldatafolded = explode("\n", $icaldatafetch->data); 102 } 103 else { 104 $icaldatafolded = @file($filename, FILE_IGNORE_NEW_LINES); 105 if ($icaldatafolded === FALSE) { 106 watchdog('date ical', 'Failed to open file: %filename', array('%filename' => $filename)); 107 return false; 108 } 109 } 110 // Verify this is iCal data 111 if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') { 112 watchdog('date ical', 'Invalid calendar file: %filename', array('%filename' => $filename)); 113 return false; 114 } 115 return date_ical_parse($icaldatafolded); 116 } 117 118 /** 119 * Return an array of iCalendar information from an iCalendar file. 120 * 121 * As date_ical_import() but different param. 122 * 123 * @param $icaldatafolded 124 * an array of lines from an ical feed. 125 * @return array 126 * An array with all the elements from the ical. 127 */ 128 function date_ical_parse($icaldatafolded = array()) { 129 $items = array(); 130 131 // Verify this is iCal data 132 if (trim($icaldatafolded[0]) != 'BEGIN:VCALENDAR') { 133 watchdog('date ical', 'Invalid calendar file.'); 134 return false; 135 } 136 137 // "unfold" wrapped lines 138 $icaldata = array(); 139 foreach ($icaldatafolded as $line) { 140 $out = array(); 141 // See if this looks like the beginning of a new property or value. 142 // If not, it is a continuation of the previous line. 143 // The regex is to ensure that wrapped QUOTED-PRINTABLE data 144 // is kept intact. 145 if (!preg_match('/([A-Z]+)[:;](.*)/', $line, $out)) { 146 $line = array_pop($icaldata) . ($line); 147 } 148 $icaldata[] = $line; 149 } 150 unset($icaldatafolded); 151 152 // Parse the iCal information 153 $parents = array(); 154 $subgroups = array(); 155 $vcal = ''; 156 foreach ($icaldata as $line) { 157 $line = trim($line); 158 $vcal .= $line ."\n"; 159 // Deal with begin/end tags separately 160 if (preg_match('/(BEGIN|END):V(\S+)/', $line, $matches)) { 161 $closure = $matches[1]; 162 $type = 'V'. $matches[2]; 163 if ($closure == 'BEGIN') { 164 array_push($parents, $type); 165 array_push($subgroups, array()); 166 } 167 else if ($closure == 'END') { 168 end($subgroups); 169 $subgroup =& $subgroups[key($subgroups)]; 170 switch ($type) { 171 case 'VCALENDAR': 172 if (prev($subgroups) == false) { 173 $items[] = array_pop($subgroups); 174 } 175 else { 176 $parent[array_pop($parents)][] = array_pop($subgroups); 177 } 178 break; 179 // Add the timezones in with their index their TZID 180 case 'VTIMEZONE': 181 $subgroup = end($subgroups); 182 $id = $subgroup['TZID']; 183 unset($subgroup['TZID']); 184 185 // Append this subgroup onto the one above it 186 prev($subgroups); 187 $parent =& $subgroups[key($subgroups)]; 188 189 $parent[$type][$id] = $subgroup; 190 191 array_pop($subgroups); 192 array_pop($parents); 193 break; 194 // Do some fun stuff with durations and all_day events 195 // and then append to parent 196 case 'VEVENT': 197 case 'VALARM': 198 case 'VTODO': 199 case 'VJOURNAL': 200 case 'VVENUE': 201 case 'VFREEBUSY': 202 default: 203 // Can't be sure whether DTSTART is before or after DURATION, 204 // so parse DURATION at the end. 205 if (isset($subgroup['DURATION'])) { 206 date_ical_parse_duration($subgroup, 'DURATION'); 207 } 208 // Add a top-level indication for the 'All day' condition. 209 // Leave it in the individual date components, too, so it 210 // is always available even when you are working with only 211 // a portion of the VEVENT array, like in Feed API parsers. 212 $subgroup['all_day'] = FALSE; 213 if (!empty($subgroup['DTSTART']) && (!empty($subgroup['DTSTART']['all_day']) || 214 (empty($subgroup['DTEND']) && empty($subgroup['RRULE']) && empty($subgroup['RRULE']['COUNT'])))) { 215 // Many programs output DTEND for an all day event as the 216 // following day, reset this to the same day for internal use. 217 $subgroup['all_day'] = TRUE; 218 $subgroup['DTEND'] = $subgroup['DTSTART']; 219 } 220 // Add this element to the parent as an array under the 221 // component name 222 default: 223 prev($subgroups); 224 $parent =& $subgroups[key($subgroups)]; 225 226 $parent[$type][] = $subgroup; 227 228 array_pop($subgroups); 229 array_pop($parents); 230 break; 231 } 232 } 233 } 234 // Handle all other possibilities 235 else { 236 // Grab current subgroup 237 end($subgroups); 238 $subgroup =& $subgroups[key($subgroups)]; 239 240 // Split up the line into nice pieces for PROPERTYNAME, 241 // PROPERTYATTRIBUTES, and PROPERTYVALUE 242 preg_match('/([^;:]+)(?:;([^:]*))?:(.+)/', $line, $matches); 243 $name = !empty($matches[1]) ? strtoupper(trim($matches[1])) : ''; 244 $field = !empty($matches[2]) ? $matches[2] : ''; 245 $data = !empty($matches[3]) ? $matches[3] : ''; 246 $parse_result = ''; 247 switch ($name) { 248 // Keep blank lines out of the results. 249 case '': 250 break; 251 252 // Lots of properties have date values that must be parsed out. 253 case 'CREATED': 254 case 'LAST-MODIFIED': 255 case 'DTSTART': 256 case 'DTEND': 257 case 'DTSTAMP': 258 case 'FREEBUSY': 259 case 'DUE': 260 case 'COMPLETED': 261 $parse_result = date_ical_parse_date($field, $data); 262 break; 263 264 case 'EXDATE': 265 case 'RDATE': 266 $parse_result = date_ical_parse_exceptions($field, $data); 267 break; 268 269 case 'TRIGGER': 270 // A TRIGGER can either be a date or in the form -PT1H. 271 if (!empty($field)) { 272 $parse_result = date_ical_parse_date($field, $data); 273 } 274 else { 275 $parse_result = array('DATA' => $data); 276 } 277 break; 278 279 case 'DURATION': 280 // Can't be sure whether DTSTART is before or after DURATION in 281 // the VEVENT, so store the data and parse it at the end. 282 $parse_result = array('DATA' => $data); 283 break; 284 285 case 'RRULE': 286 case 'EXRULE': 287 $parse_result = date_ical_parse_rrule($field, $data); 288 break; 289 290 case 'SUMMARY': 291 case 'DESCRIPTION': 292 $parse_result = date_ical_parse_text($field, $data); 293 break; 294 295 case 'LOCATION': 296 $parse_result = date_ical_parse_location($field, $data); 297 break; 298 299 // For all other properties, just store the property and the value. 300 // This can be expanded on in the future if other properties should 301 // be given special treatment. 302 default: 303 $parse_result = $data; 304 break; 305 } 306 307 // Store the result of our parsing 308 $subgroup[$name] = $parse_result; 309 } 310 } 311 return $items; 312 } 313 314 /** 315 * Parse a ical date element. 316 * 317 * Possible formats to parse include: 318 * PROPERTY:YYYYMMDD[T][HH][MM][SS][Z] 319 * PROPERTY;VALUE=DATE:YYYYMMDD[T][HH][MM][SS][Z] 320 * PROPERTY;VALUE=DATE-TIME:YYYYMMDD[T][HH][MM][SS][Z] 321 * PROPERTY;TZID=XXXXXXXX;VALUE=DATE:YYYYMMDD[T][HH][MM][SS] 322 * PROPERTY;TZID=XXXXXXXX:YYYYMMDD[T][HH][MM][SS] 323 * 324 * The property and the colon before the date are removed in the import 325 * process above and we are left with $field and $data. 326 * 327 * @param $field 328 * The text before the colon and the date, i.e. 329 * ';VALUE=DATE:', ';VALUE=DATE-TIME:', ';TZID=' 330 * @param $data 331 * The date itself, after the colon, in the format YYYYMMDD[T][HH][MM][SS][Z] 332 * 'Z', if supplied, means the date is in UTC. 333 * 334 * @return array 335 * $items array, consisting of: 336 * 'datetime' => date in YYYY-MM-DD HH:MM format, not timezone adjusted 337 * 'all_day' => whether this is an all-day event with no time 338 * 'tz' => the timezone of the date, could be blank if the ical 339 * has no timezone; the ical specs say no timezone 340 * conversion should be done if no timezone info is 341 * supplied 342 * @todo 343 * Another option for dates is the format PROPERTY;VALUE=PERIOD:XXXX. The period 344 * may include a duration, or a date and a duration, or two dates, so would 345 * have to be split into parts and run through date_ical_parse_date() and 346 * date_ical_parse_duration(). This is not commonly used, so ignored for now. 347 * It will take more work to figure how to support that. 348 */ 349 function date_ical_parse_date($field, $data) { 350 $items = array('datetime' => '', 'all_day' => '', 'tz' => ''); 351 if (empty($data)) { 352 return $items; 353 } 354 // Make this a little more whitespace independent 355 $data = trim($data); 356 357 // Turn the properties into a nice indexed array of 358 // array(PROPERTYNAME => PROPERTYVALUE); 359 $field_parts = preg_split('/[;:]/', $field); 360 $properties = array(); 361 foreach ($field_parts as $part) { 362 if (strpos($part, '=') !== false) { 363 $tmp = explode('=', $part); 364 $properties[$tmp[0]] = $tmp[1]; 365 } 366 } 367 368 // Make this a little more whitespace independent 369 $data = trim($data); 370 371 // Record if a time has been found 372 $has_time = false; 373 374 // If a format is specified, parse it according to that format 375 if (isset($properties['VALUE'])) { 376 switch ($properties['VALUE']) { 377 case 'DATE': 378 preg_match (DATE_REGEX_ICAL_DATE, $data, $regs); 379 $datetime = date_pad($regs[1]) .'-'. date_pad($regs[2]) .'-'. date_pad($regs[3]); // Date 380 break; 381 case 'DATE-TIME': 382 preg_match (DATE_REGEX_ICAL_DATETIME, $data, $regs); 383 $datetime = date_pad($regs[1]) .'-'. date_pad($regs[2]) .'-'. date_pad($regs[3]); // Date 384 $datetime .= ' '. date_pad($regs[4]) .':'. date_pad($regs[5]) .':'. date_pad($regs[6]); // Time 385 $has_time = true; 386 break; 387 } 388 } 389 // If no format is specified, attempt a loose match 390 else { 391 preg_match (DATE_REGEX_LOOSE, $data, $regs); 392 $datetime = date_pad($regs[1]) .'-'. date_pad($regs[2]) .'-'. date_pad($regs[3]); // Date 393 if (isset($regs[4])) { 394 $has_time = true; 395 $has_time = TRUE; 396 $datetime .= ' ' . (!empty($regs[5]) ? date_pad($regs[5]) : '00') . 397 ':' . (!empty($regs[6]) ? date_pad($regs[6]) : '00') . 398 ':' . (!empty($regs[7]) ? date_pad($regs[7]) : '00'); // Time 399 } 400 } 401 402 // Use timezone if explicitly declared 403 if (isset($properties['TZID'])) { 404 $tz = $properties['TZID']; 405 // Fix commonly used alternatives like US-Eastern which should be US/Eastern. 406 $tz = str_replace('-', '/', $tz); 407 // Unset invalid timezone names. 408 module_load_include('install', 'date_timezone'); 409 $tz = _date_timezone_replacement($tz); 410 if (!date_timezone_is_valid($tz)) { 411 $tz = ''; 412 } 413 } 414 // If declared as UTC with terminating 'Z', use that timezone 415 else if (strpos($data, 'Z') !== false) { 416 $tz = 'UTC'; 417 } 418 // Otherwise this date is floating... 419 else { 420 $tz = ''; 421 } 422 423 $items['datetime'] = $datetime; 424 $items['all_day'] = $has_time ? false : true; 425 $items['tz'] = $tz; 426 return $items; 427 } 428 429 /** 430 * Parse an ical repeat rule. 431 * 432 * @return array 433 * Array in the form of PROPERTY => array(VALUES) 434 * PROPERTIES include FREQ, INTERVAL, COUNT, BYDAY, BYMONTH, BYYEAR, UNTIL 435 */ 436 function date_ical_parse_rrule($field, $data) { 437 $data = preg_replace("/RRULE.*:/", '', $data); 438 $items = array('DATA' => $data); 439 $rrule = explode(';', $data); 440 foreach ($rrule as $key => $value) { 441 $param = explode('=', $value); 442 // Must be some kind of invalid data. 443 if (count($param) != 2) { 444 continue; 445 } 446 if ($param[0] == 'UNTIL') { 447 $values = date_ical_parse_date('', $param[1]); 448 } 449 else { 450 $values = explode(',', $param[1]); 451 } 452 // Different treatment for items that can have multiple values and those that cannot. 453 if (in_array($param[0], array('FREQ', 'INTERVAL', 'COUNT', 'WKST'))) { 454 $items[$param[0]] = $param[1]; 455 } 456 else { 457 $items[$param[0]] = $values; 458 } 459 } 460 return $items; 461 } 462 463 /** 464 * Parse exception dates (can be multiple values). 465 * 466 * @return array 467 * an array of date value arrays. 468 */ 469 function date_ical_parse_exceptions($field, $data) { 470 $data = str_replace($field.':', '', $data); 471 $items = array('DATA' => $data); 472 $ex_dates = explode(',', $data); 473 foreach ($ex_dates as $ex_date) { 474 $items[] = date_ical_parse_date('', $ex_date); 475 } 476 return $items; 477 } 478 479 /** 480 * Parse the duration of the event. 481 * Example: 482 * DURATION:PT1H30M 483 * DURATION:P1Y2M 484 * 485 * @param $subgroup 486 * array of other values in the vevent so we can check for DTSTART 487 */ 488 function date_ical_parse_duration(&$subgroup, $field = 'DURATION') { 489 $items = $subgroup[$field]; 490 $data = $items['DATA']; 491 preg_match('/^P(\d{1,4}[Y])?(\d{1,2}[M])?(\d{1,2}[W])?(\d{1,2}[D])?([T]{0,1})?(\d{1,2}[H])?(\d{1,2}[M])?(\d{1,2}[S])?/', $data, $duration); 492 $items['year'] = isset($duration[1]) ? str_replace('Y', '', $duration[1]) : ''; 493 $items['month'] = isset($duration[2]) ?str_replace('M', '', $duration[2]) : ''; 494 $items['week'] = isset($duration[3]) ?str_replace('W', '', $duration[3]) : ''; 495 $items['day'] = isset($duration[4]) ?str_replace('D', '', $duration[4]) : ''; 496 $items['hour'] = isset($duration[6]) ?str_replace('H', '', $duration[6]) : ''; 497 $items['minute'] = isset($duration[7]) ?str_replace('M', '', $duration[7]) : ''; 498 $items['second'] = isset($duration[8]) ?str_replace('S', '', $duration[8]) : ''; 499 $start_date = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['datetime'] : date_format(date_now(), DATE_FORMAT_ISO); 500 $timezone = array_key_exists('DTSTART', $subgroup) ? $subgroup['DTSTART']['tz'] : variable_get('date_default_timezone_name', NULL); 501 if (empty($timezone)) { 502 $timezone = 'UTC'; 503 } 504 $date = date_make_date($start_date, $timezone); 505 $date2 = drupal_clone($date); 506 foreach ($items as $item => $count) { 507 if ($count > 0) { 508 date_modify($date2, '+'. $count .' '. $item); 509 } 510 } 511 $format = isset($subgroup['DTSTART']['type']) && $subgroup['DTSTART']['type'] == 'DATE' ? 'Y-m-d' : 'Y-m-d H:i:s'; 512 $subgroup['DTEND'] = array( 513 'datetime' => date_format($date2, DATE_FORMAT_DATETIME), 514 'all_day' => isset($subgroup['DTSTART']['all_day']) ? $subgroup['DTSTART']['all_day'] : 0, 515 'tz' => $timezone, 516 ); 517 $duration = date_format($date2, 'U') - date_format($date, 'U'); 518 $subgroup['DURATION'] = array('DATA' => $data, 'DURATION' => $duration); 519 } 520 521 /** 522 * Parse and clean up ical text elements. 523 */ 524 function date_ical_parse_text($field, $data) { 525 if (strstr($field, 'QUOTED-PRINTABLE')) { 526 $data = quoted_printable_decode($data); 527 } 528 // Strip line breaks within element 529 $data = str_replace(array("\r\n ", "\n ", "\r "), '', $data); 530 // Put in line breaks where encoded 531 $data = str_replace(array("\\n", "\\N"), "\n", $data); 532 // Remove other escaping 533 $data = stripslashes($data); 534 return $data; 535 } 536 537 /** 538 * Parse location elements. 539 * 540 * Catch situations like the upcoming.org feed that uses 541 * LOCATION;VENUE-UID="http://upcoming.yahoo.com/venue/104/":111 First Street... 542 * or more normal LOCATION;UID=123:111 First Street... 543 * Upcoming feed would have been improperly broken on the ':' in http:// 544 * so we paste the $field and $data back together first. 545 * 546 * Use non-greedy check for ':' in case there are more of them in the address. 547 */ 548 function date_ical_parse_location($field, $data) { 549 if (preg_match('/UID=[?"](.+)[?"][*?:](.+)/', $field .':'. $data, $matches)) { 550 $location = array(); 551 $location['UID'] = $matches[1]; 552 $location['DESCRIPTION'] = stripslashes($matches[2]); 553 return $location; 554 } 555 else { 556 // Remove other escaping 557 $location = stripslashes($data); 558 return $location; 559 } 560 } 561 562 /** 563 * Return a date object for the ical date, adjusted to its local timezone. 564 * 565 * @param $ical_date 566 * an array of ical date information created in the ical import. 567 * @param $to_tz 568 * the timezone to convert the date's value to. 569 * @return object 570 * a timezone-adjusted date object 571 */ 572 function date_ical_date($ical_date, $to_tz = FALSE) { 573 // If the ical date has no timezone, must assume it is stateless 574 // so treat it as a local date. 575 if (empty($ical_date['datetime'])) { 576 return NULL; 577 } 578 elseif (empty($ical_date['tz'])) { 579 $from_tz = date_default_timezone_name(); 580 } 581 else { 582 $from_tz = $ical_date['tz']; 583 } 584 $date = date_make_date($ical_date['datetime'], $from_tz); 585 if ($to_tz && $ical_date['tz'] != '' && $to_tz != $ical_date['tz']) { 586 date_timezone_set($date, timezone_open($to_tz)); 587 } 588 return $date; 589 } 590 591 /** 592 * Escape #text elements for safe iCal use 593 * 594 * @param $text 595 * Text to escape 596 * 597 * @return 598 * Escaped text 599 * 600 */ 601 function date_ical_escape_text($text) { 602 $text = drupal_html_to_text($text); 603 $text = trim($text); 604 // TODO Per #38130 the iCal specs don't want : and " escaped 605 // but there was some reason for adding this in. Need to watch 606 // this and see if anything breaks. 607 //$text = str_replace('"', '\"', $text); 608 //$text = str_replace(":", "\:", $text); 609 $text = preg_replace("/\\\b/","\\\\", $text); 610 $text = str_replace(",", "\,", $text); 611 $text = str_replace(";", "\;", $text); 612 $text = str_replace("\n", "\\n ", $text); 613 return trim($text); 614 } 615 616 /** 617 * Build an iCal RULE from $form_values. 618 * 619 * @param $form_values 620 * an array constructed like the one created by date_ical_parse_rrule() 621 * 622 * [RRULE] => Array ( 623 * [FREQ] => Array ( 624 * [0] => MONTHLY 625 * ) 626 * [BYDAY] => Array ( 627 * [0] => 1SU 628 * [1] => -1SU 629 * ) 630 * [UNTIL] => Array ( 631 * [datetime] => 1997-21-31 09:00:00 632 * [all_day] => 0 633 * [tz] => US/Eastern 634 * ) 635 * ) 636 * [EXDATE] => Array ( 637 * [0] = Array ( 638 * [datetime] => 1997-09-21 09:00:00 639 * [all_day] => 0 640 * [tz] => US/Eastern 641 * ) 642 * [1] = Array ( 643 * [datetime] => 1997-10-05 09:00:00 644 * [all_day] => 0 645 * [tz] => US/Eastern 646 * ) 647 * ) 648 * [RDATE] => Array ( 649 * [0] = Array ( 650 * [datetime] => 1997-09-21 09:00:00 651 * [all_day] => 0 652 * [tz] => US/Eastern 653 * ) 654 * [1] = Array ( 655 * [datetime] => 1997-10-05 09:00:00 656 * [all_day] => 0 657 * [tz] => US/Eastern 658 * ) 659 * ) 660 * 661 */ 662 function date_api_ical_build_rrule($form_values) { 663 $RRULE = ''; 664 if (empty($form_values) || !is_array($form_values)) { 665 return $RRULE; 666 } 667 //grab the RRULE data and put them into iCal RRULE format 668 $RRULE .= 'RRULE:FREQ='. (!array_key_exists('FREQ', $form_values) ? 'DAILY' : $form_values['FREQ']); 669 $RRULE .= ';INTERVAL='. (!array_key_exists('INTERVAL', $form_values) ? 1 : $form_values['INTERVAL']); 670 671 // Unset the empty 'All' values. 672 if (array_key_exists('BYDAY', $form_values)) unset($form_values['BYDAY']['']); 673 if (array_key_exists('BYMONTH', $form_values)) unset($form_values['BYMONTH']['']); 674 if (array_key_exists('BYMONTHDAY', $form_values)) unset($form_values['BYMONTHDAY']['']); 675 676 if (array_key_exists('BYDAY', $form_values) && $BYDAY = implode(",", $form_values['BYDAY'])) { 677 $RRULE .= ';BYDAY='. $BYDAY; 678 } 679 if (array_key_exists('BYMONTH', $form_values) && $BYMONTH = implode(",", $form_values['BYMONTH'])) { 680 $RRULE .= ';BYMONTH='. $BYMONTH; 681 } 682 if (array_key_exists('BYMONTHDAY', $form_values) && $BYMONTHDAY = implode(",", $form_values['BYMONTHDAY'])) { 683 $RRULE .= ';BYMONTHDAY='. $BYMONTHDAY; 684 } 685 // The UNTIL date is supposed to always be expressed in UTC. 686 if (array_key_exists('UNTIL', $form_values) && array_key_exists('datetime', $form_values['UNTIL']) && !empty($form_values['UNTIL']['datetime'])) { 687 $until = date_ical_date($form_values['UNTIL'], 'UTC'); 688 $RRULE .= ';UNTIL='. date_format($until, DATE_FORMAT_ICAL) .'Z'; 689 } 690 // Our form doesn't allow a value for COUNT, but it may be needed by 691 // modules using the API, so add it to the rule. 692 if (array_key_exists('COUNT', $form_values)) { 693 $RRULE .= ';COUNT='. $form_values['COUNT']; 694 } 695 696 // iCal rules presume the week starts on Monday unless otherwise specified, 697 // so we'll specify it. 698 if (array_key_exists('WKST', $form_values)) { 699 $RRULE .= ';WKST='. $form_values['WKST']; 700 } 701 else { 702 $RRULE .= ';WKST='. date_repeat_dow2day(variable_get('date_first_day', 1)); 703 } 704 705 // Exceptions dates go last, on their own line. 706 if (isset($form_values['EXDATE']) && is_array($form_values['EXDATE'])) { 707 $ex_dates = array(); 708 foreach ($form_values['EXDATE'] as $value) { 709 $ex_date = date_convert($value['datetime'], DATE_DATETIME, DATE_ICAL); 710 if (!empty($ex_date)) { 711 $ex_dates[] = $ex_date; 712 } 713 } 714 if (!empty($ex_dates)) { 715 sort($ex_dates); 716 $RRULE .= chr(13) . chr(10) .'EXDATE:'. implode(',', $ex_dates); 717 } 718 } 719 elseif (!empty($form_values['EXDATE'])) { 720 $RRULE .= chr(13) . chr(10) .'EXDATE:'. $form_values['EXDATE']; 721 } 722 723 // Exceptions dates go last, on their own line. 724 if (isset($form_values['RDATE']) && is_array($form_values['RDATE'])) { 725 $ex_dates = array(); 726 foreach ($form_values['RDATE'] as $value) { 727 $ex_date = date_convert($value['datetime'], DATE_DATETIME, DATE_ICAL); 728 if (!empty($ex_date)) { 729 $ex_dates[] = $ex_date; 730 } 731 } 732 if (!empty($ex_dates)) { 733 sort($ex_dates); 734 $RRULE .= chr(13) . chr(10) .'RDATE:'. implode(',', $ex_dates); 735 } 736 } 737 elseif (!empty($form_values['RDATE'])) { 738 $RRULE .= chr(13) . chr(10) .'RDATE:'. $form_values['RDATE']; 739 } 740 741 return $RRULE; 742 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Jul 9 18:01:44 2012 | Cross-referenced by PHPXref 0.7 |