[ Index ]
 

Code source de WebCalendar 1.0.5

Accédez au Source d'autres logiciels libres

Classes | Fonctions | Variables | Constantes | Tables | Statistiques

title

Body

[fermer]

/ -> import_ical.php (source)

   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  ?>


Généré le : Fri Nov 30 19:09:19 2007 par Balluche grâce à PHPXref 0.7
  Clicky Web Analytics