685 lines
22 KiB
PHP
685 lines
22 KiB
PHP
|
<?php if(!defined('APP_ROOT')) exit('No direct script access allowed');
|
||
|
|
||
|
date_default_timezone_set('America/Chicago');
|
||
|
|
||
|
class Anvil_iCal {
|
||
|
var $calURL = '';
|
||
|
var $rawCalendar = '';
|
||
|
var $iCal;
|
||
|
var $dev_mode = true;
|
||
|
|
||
|
function __construct($calURL=false) {
|
||
|
if($calURL) {
|
||
|
$this->calURL = $calURL;
|
||
|
$this->fetchCalendar();
|
||
|
$this->createCalendarFromRaw();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function fetchCalendar() {
|
||
|
$ch = curl_init($this->calURL);
|
||
|
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||
|
$this->rawCalendar = curl_exec($ch);
|
||
|
curl_close($ch);
|
||
|
}
|
||
|
|
||
|
function createCalendarFromRaw() {
|
||
|
$this->iCal = new ICal($this->rawCalendar);
|
||
|
}
|
||
|
|
||
|
function getCalendar() {
|
||
|
return $this->iCal;
|
||
|
}
|
||
|
|
||
|
function getTimezone() {
|
||
|
return new DateTimeZone($this->iCal->cal['VCALENDAR']['X-WR-TIMEZONE']);
|
||
|
}
|
||
|
|
||
|
function getEvents() {
|
||
|
if(isset($this->iCal->cal['VEVENT'])) {
|
||
|
return $this->iCal->cal['VEVENT'];
|
||
|
}
|
||
|
return [];
|
||
|
}
|
||
|
|
||
|
function getUpcomingEvents() {
|
||
|
$ret = [];
|
||
|
$earliest = new DateTime(date('Y-m-d H:i:s', strtotime('now')));
|
||
|
$allEvents = $this->iCal->cal['VEVENT'];
|
||
|
foreach($allEvents as $anEvent) {
|
||
|
$tstDt = new DateTime(date('Y-m-d H:i:s', strtotime($anEvent['DTSTART'])));
|
||
|
if($tstDt <= $earliest) { continue; }
|
||
|
$ret[] = $anEvent;
|
||
|
}
|
||
|
return $ret;
|
||
|
}
|
||
|
|
||
|
function getNextEvent() {
|
||
|
$earliest = new DateTime(date('Y-m-d H:i:s', strtotime('2016-04-21 17:00:00')));
|
||
|
$dt = new DateTime();
|
||
|
foreach($this->getEvents() as $anEv) {
|
||
|
$tstDt = new DateTime(date('Y-m-d H:i:s', strtotime($anEv['DTSTART'])));
|
||
|
// $tstDt is the _STARTING_ date of the event
|
||
|
if($tstDt <= $earliest) { continue; }
|
||
|
$diff = $dt->diff($tstDt);
|
||
|
if(!isset($nextDt)) {
|
||
|
$nextDt = $tstDt;
|
||
|
$ret = $anEv;
|
||
|
} else if($dt < $tstDt && $tstDt < $nextDt) {
|
||
|
$nextDt = $tstDt;
|
||
|
$ret = $anEv;
|
||
|
}
|
||
|
}
|
||
|
if(isset($ret)) {
|
||
|
return $ret;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// getNextEventWithCurrent will get the next event, including ones that
|
||
|
// are occurring right now, but haven't ended yet.
|
||
|
function getNextEventWithCurrent() {
|
||
|
$dt = new DateTime();
|
||
|
foreach($this->getEvents() as $anEv) {
|
||
|
$tstDt = new DateTime(date('Y-m-d H:i:s', strtotime($anEv['DTSTART'])));
|
||
|
// $tstDt is the _STARTING_ date of the event
|
||
|
$diff = $dt->diff($tstDt);
|
||
|
if(!isset($nextDt)) {
|
||
|
$nextDt = $tstDt;
|
||
|
} else if($dt < $tstDt && $tstDt < $nextDt) {
|
||
|
$nextDt = $tstDt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class ICal {
|
||
|
private $timezone = 'UTC';
|
||
|
private $events = [];
|
||
|
private $recEvents = [];
|
||
|
|
||
|
public function __construct($ICalString) {
|
||
|
if(!$ICalString) {
|
||
|
return false;
|
||
|
}
|
||
|
$lines = explode("\r\n", $ICalString);
|
||
|
if(stristr($lines[0], 'BEGIN:VCALENDAR') === false) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// First, fix all multiline values
|
||
|
$badIdx = [];
|
||
|
foreach($lines as $idx => &$line) {
|
||
|
$line = ltrim(str_replace('\,',',',$line));
|
||
|
//$line = ltrim(str_replace('','<br/>',$line));
|
||
|
$add = $this->keyValueFromString($line);
|
||
|
if ($add === false) {
|
||
|
$badIdx[] = $idx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$newLines = [];
|
||
|
$lastGood = '';
|
||
|
foreach($lines as $idx => $aLine) {
|
||
|
if(in_array($idx, $badIdx)) {
|
||
|
$lastGood .= $aLine;
|
||
|
} else {
|
||
|
if(!empty($lastGood)) {
|
||
|
$newLines[] = $lastGood;
|
||
|
$lastGood = '';
|
||
|
}
|
||
|
$lastGood = $aLine;
|
||
|
}
|
||
|
}
|
||
|
$newLines[] = $lastGood;
|
||
|
$lines = $newLines;
|
||
|
|
||
|
for($idx = 0; $idx < count($lines); $idx++) {
|
||
|
$line = $lines[$idx];
|
||
|
if($line == 'BEGIN:VTIMEZONE') {
|
||
|
$i = $this->_parseFindNext('END:VTIMEZONE', $lines, $idx);
|
||
|
$this->timezone = $this->parseTimezone($i);
|
||
|
}
|
||
|
if($line == 'BEGIN:VEVENT') {
|
||
|
$i = $this->_parseFindNext('END:VEVENT', $lines, $idx);
|
||
|
if($i !== false) {
|
||
|
$newEvent = $this->parseEvent($i);
|
||
|
if($newEvent->isValid()) {
|
||
|
$this->events[] = $newEvent;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public function getEvents() {
|
||
|
return $this->events;
|
||
|
}
|
||
|
|
||
|
public function getEventsInRange($stDtTm, $endDtTm) {
|
||
|
$ret = [];
|
||
|
foreach($this->events as $anEv) {
|
||
|
|
||
|
$evStTm = $anEv->getStartDttm();
|
||
|
$evEndTm = $anEv->getEndDttm();
|
||
|
if($anEv->getRecurFlag() && $evStTm < $endDtTm) {
|
||
|
$evLength = $evStTm->diff($evEndTm);
|
||
|
// Recurrences are defined by the original startDttm
|
||
|
$recurUntil = $anEv->getRecurUntil();
|
||
|
if(!empty($recurUntil)) {
|
||
|
// So there is an end date
|
||
|
if($recurUntil < $stDtTm) {
|
||
|
// Past the recur until
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
$recurFreq = $anEv->getRecurFrequency();
|
||
|
if(!empty($recurFreq)) {
|
||
|
switch($recurFreq) {
|
||
|
case 'WEEKLY':
|
||
|
$dow = $anEv->getRecurByDay();
|
||
|
$newArr = [];
|
||
|
if(empty($dow)) {
|
||
|
// If 'recurByDay' is blank, just recur on the event start date
|
||
|
array_push($newArr, $evStTm->format('w'));
|
||
|
} else {
|
||
|
if(is_array($dow)) {
|
||
|
foreach($dow as &$ad) {
|
||
|
$ad = $this->shortDayToDOWNum($ad);
|
||
|
array_push($newArr, $ad);
|
||
|
}
|
||
|
} else {
|
||
|
$ad = $this->shortDayToDOWNum($dow);
|
||
|
array_push($newArr, $ad);
|
||
|
}
|
||
|
}
|
||
|
$dow = $newArr;
|
||
|
$evStDay = new DateTime($evStTm->format('Y-m-d'));
|
||
|
for($tstDt = new DateTime($stDtTm->format(DATE_RFC3339));
|
||
|
$tstDt <= $endDtTm;
|
||
|
$tstDt->add(new DateInterval('P1D'))) {
|
||
|
if(!in_array($tstDt->format('w'), $dow)) { continue; } // Same day of week
|
||
|
if($tstDt < $evStDay) { continue; } // After the recurrence started
|
||
|
if(!empty($recurUntil) && $tstDt > $recurUntil) { continue; } // Before it ended
|
||
|
$recurInt = $anEv->getRecurInterval();
|
||
|
if($recurInt != 0) {
|
||
|
// Figure out how many 'FREQ's have passed (weeks in this case)
|
||
|
// 7 Days in a Week, recurring every $recurInt weeks
|
||
|
$recurInt *= 7;
|
||
|
$daysSince = $tstDt->diff($evStTm)->days;
|
||
|
if($daysSince%$recurInt != 0) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
$recurCnt = $anEv->getRecurCount();
|
||
|
if($recurCnt != 0) {
|
||
|
// Recurring weekly
|
||
|
$recurInt = 7;
|
||
|
$daysSince = $tstDt->diff($evStDay)->days + 1;
|
||
|
if($daysSince/$recurInt > $recurCnt) {
|
||
|
// Too many occurrences already
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
$tstDt->setTime($evStTm->format('H'), $evStTm->format('i'), $evStTm->format('s'));
|
||
|
// The recurrence appears to be valid, check the exception dates
|
||
|
if($anEv->isExceptionDate($tstDt)) {
|
||
|
// An exception for this date
|
||
|
continue;
|
||
|
}
|
||
|
$rEv = new ICalEvent();
|
||
|
$rEv->setStartDttm(new DateTime($tstDt->format(DATE_RFC3339)));
|
||
|
$rEv->setEndDttm(new DateTime($tstDt->add($evLength)->format(DATE_RFC3339)));
|
||
|
$rEv->setDescription($anEv->getDescription());
|
||
|
$rEv->setSummary($anEv->getSummary());
|
||
|
$rEv->setLocation($anEv->getLocation());
|
||
|
$rEv->setICalTag("RecurringCopy", "true");
|
||
|
$ret[] = $rEv;
|
||
|
}
|
||
|
break;
|
||
|
case 'MONTHLY':
|
||
|
// TODO: TEST
|
||
|
$dom = $evStTm->format('d');
|
||
|
for($tstDt = new DateTime($stDtTm->format(DATE_RFC3339));
|
||
|
$tstDt <= $endDtTm;
|
||
|
$tstDt->add(new DateInterval('P1M'))) {
|
||
|
if($tstDt->format('d') != $dom) { continue; } // Same day of month
|
||
|
if($tstDt < $evStTm) { continue; } // After the recurrence started
|
||
|
if(!empty($recurUntil) && $tstDt > $recurUntil) { continue; } // Before it ended
|
||
|
// TODO: Check Recurrence Interval
|
||
|
$tstDt->setTime($evStTm->format('H'), $evStTm->format('i'), $evStTm->format('s'));
|
||
|
$evLength = $evStTm->diff($evEndTm);
|
||
|
$rEv = new ICalEvent();
|
||
|
$rEv->setStartDttm(new DateTime($tstDt->format(DATE_RFC3339)));
|
||
|
$rEv->setEndDttm(new DateTime($tstDt->add($evLength)->format(DATE_RFC3339)));
|
||
|
$rEv->setDescription($anEv->getDescription());
|
||
|
$rEv->setSummary($anEv->getSummary());
|
||
|
$rEv->setLocation($anEv->getLocation());
|
||
|
$rEv->setICalTag("RecurringCopy", "true");
|
||
|
$ret[] = $rEv;
|
||
|
}
|
||
|
break;
|
||
|
case 'YEARLY':
|
||
|
// TODO: TEST
|
||
|
$doy = $evStTm->format('z');
|
||
|
for($tstDt = new DateTime($stDtTm->format(DATE_RFC3339));
|
||
|
$tstDt <= $endDtTm;
|
||
|
$tstDt->add(new DateInterval('P1Y'))) {
|
||
|
if($tstDt->format('z') != $doy) { continue; } // Same day of year
|
||
|
if($tstDt < $evStTm) { continue; } // After the recurrence started
|
||
|
if(!empty($recurUntil) && $tstDt > $recurUntil) { continue; } // Before it ended
|
||
|
// TODO: Check Recurrence Interval
|
||
|
$tstDt->setTime($evStTm->format('H'), $evStTm->format('i'), $evStTm->format('s'));
|
||
|
$evLength = $evStTm->diff($evEndTm);
|
||
|
$rEv = new ICalEvent();
|
||
|
$rEv->setStartDttm(new DateTime($tstDt->format(DATE_RFC3339)));
|
||
|
$rEv->setEndDttm(new DateTime($tstDt->add($evLength)->format(DATE_RFC3339)));
|
||
|
$rEv->setDescription($anEv->getDescription());
|
||
|
$rEv->setSummary($anEv->getSummary());
|
||
|
$rEv->setLocation($anEv->getLocation());
|
||
|
$rEv->setICalTag("RecurringCopy", "true");
|
||
|
$ret[] = $rEv;
|
||
|
}
|
||
|
break;
|
||
|
case 'DAILY':
|
||
|
// TODO: TEST
|
||
|
for($tstDt = new DateTime($stDtTm->format(DATE_RFC3339));
|
||
|
$tstDt <= $endDtTm;
|
||
|
$tstDt->add(new DateInterval('P1D'))) {
|
||
|
if($tstDt < $evStTm) { continue; } // After the recurrence started
|
||
|
if(!empty($recurUntil) && $tstDt > $recurUntil) { continue; } // Before it ended
|
||
|
// TODO: Check Recurrence Interval
|
||
|
$tstDt->setTime($evStTm->format('H'), $evStTm->format('i'), $evStTm->format('s'));
|
||
|
$evLength = $evStTm->diff($evEndTm);
|
||
|
$rEv = new ICalEvent();
|
||
|
$rEv->setStartDttm(new DateTime($tstDt->format(DATE_RFC3339)));
|
||
|
$rEv->setEndDttm(new DateTime($tstDt->add($evLength)->format(DATE_RFC3339)));
|
||
|
$rEv->setDescription($anEv->getDescription());
|
||
|
$rEv->setSummary($anEv->getSummary());
|
||
|
$rEv->setLocation($anEv->getLocation());
|
||
|
$rEv->setICalTag("RecurringCopy", "true");
|
||
|
$ret[] = $rEv;
|
||
|
}
|
||
|
break;
|
||
|
case 'HOURLY':
|
||
|
// TODO: TEST
|
||
|
for($tstDt = new DateTime($stDtTm->format(DATE_RFC3339));
|
||
|
$tstDt <= $endDtTm;
|
||
|
$tstDt->add(new DateInterval('PT1H'))) {
|
||
|
if($tstDt < $evStTm) { continue; } // After the recurrence started
|
||
|
if(!empty($recurUntil) && $tstDt > $recurUntil) { continue; } // Before it ended
|
||
|
// TODO: Check Recurrence Interval
|
||
|
$evLength = $evStTm->diff($evEndTm);
|
||
|
$rEv = new ICalEvent();
|
||
|
$rEv->setStartDttm(new DateTime($tstDt->format(DATE_RFC3339)));
|
||
|
$rEv->setEndDttm(new DateTime($tstDt->add($evLength)->format(DATE_RFC3339)));
|
||
|
$rEv->setDescription($anEv->getDescription());
|
||
|
$rEv->setSummary($anEv->getSummary());
|
||
|
$rEv->setLocation($anEv->getLocation());
|
||
|
$rEv->setICalTag("RecurringCopy", "true");
|
||
|
$ret[] = $rEv;
|
||
|
}
|
||
|
break;
|
||
|
case 'MINUTELY':
|
||
|
// TODO: TEST
|
||
|
for($tstDt = new DateTime($stDtTm->format(DATE_RFC3339));
|
||
|
$tstDt <= $endDtTm;
|
||
|
$tstDt->add(new DateInterval('PT1M'))) {
|
||
|
if($tstDt < $evStTm) { continue; } // After the recurrence started
|
||
|
if(!empty($recurUntil) && $tstDt > $recurUntil) { continue; } // Before it ended
|
||
|
// TODO: Check Recurrence Interval
|
||
|
$evLength = $evStTm->diff($evEndTm);
|
||
|
$rEv = new ICalEvent();
|
||
|
$rEv->setStartDttm(new DateTime($tstDt->format(DATE_RFC3339)));
|
||
|
$rEv->setEndDttm(new DateTime($tstDt->add($evLength)->format(DATE_RFC3339)));
|
||
|
$rEv->setDescription($anEv->getDescription());
|
||
|
$rEv->setSummary($anEv->getSummary());
|
||
|
$rEv->setLocation($anEv->getLocation());
|
||
|
$rEv->setICalTag("RecurringCopy", "true");
|
||
|
$ret[] = $rEv;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
// Normal Event, just check the dates
|
||
|
// If any part of the event takes place in the range, append it
|
||
|
if(($evStTm >= $stDtTm && $evStTm < $endDtTm)
|
||
|
|| ($evEndTm > $stDtTm && $evEndTm <= $endDtTm)) {
|
||
|
$ret[] = $anEv;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
usort($ret, "_eventSortHelper");
|
||
|
return $ret;
|
||
|
}
|
||
|
|
||
|
|
||
|
public function parseTimezone($lines) {
|
||
|
$defaultTZ = 'UTC';
|
||
|
foreach($lines as $line) {
|
||
|
$line = trim($line);
|
||
|
if($line == "END:VTIMEZONE") {
|
||
|
break;
|
||
|
}
|
||
|
$add = $this->keyValueFromString($line);
|
||
|
if ($add === false) {
|
||
|
continue;
|
||
|
}
|
||
|
list($keyword, $value) = $add;
|
||
|
if($keyword == 'TZID') {
|
||
|
return $value;
|
||
|
}
|
||
|
}
|
||
|
return $defaultTZ;
|
||
|
}
|
||
|
|
||
|
|
||
|
// Parses and returns the first event out of $lines
|
||
|
public function parseEvent($lines) {
|
||
|
$newEvent = new ICalEvent();
|
||
|
foreach($lines as $line) {
|
||
|
$line = trim($line);
|
||
|
if($line == 'END:VEVENT') {
|
||
|
break;
|
||
|
}
|
||
|
$add = $this->keyValueFromString($line);
|
||
|
if($add === FALSE) {
|
||
|
continue;
|
||
|
}
|
||
|
list($keyword, $value) = $add;
|
||
|
$newEvent->setICalTag($keyword, $value);
|
||
|
if(stristr($keyword, "DTSTART")
|
||
|
|| stristr($keyword, "DTEND")
|
||
|
|| stristr($keyword, "EXDATE")) {
|
||
|
$tz = 'UTC';
|
||
|
if(stristr($keyword, ';')) {
|
||
|
$keywordPts = explode(';', $keyword);
|
||
|
$keyword = $keywordPts[0];
|
||
|
$tzPts = $keywordPts[1];
|
||
|
$tzPts = explode('=', $tzPts);
|
||
|
if($tzPts[0] == 'TZID') {
|
||
|
$tz = $tzPts[1];
|
||
|
}
|
||
|
}
|
||
|
if($keyword == 'EXDATE') {
|
||
|
// Exception Dates (could be an array)
|
||
|
if(stristr($value, ',')) {
|
||
|
$exDates = explode(',', $value);
|
||
|
foreach($exDates as $exDt) {
|
||
|
$date = new DateTime($exDt, new DateTimeZone($tz));
|
||
|
$date->setTimezone(new DateTimeZone($this->timezone));
|
||
|
$newEvent->addExceptionDate($date);
|
||
|
}
|
||
|
} else {
|
||
|
$date = new DateTime($value, new DateTimeZone($tz));
|
||
|
$date->setTimezone(new DateTimeZone($this->timezone));
|
||
|
$newEvent->addExceptionDate($date);
|
||
|
}
|
||
|
} else {
|
||
|
$date = new DateTime($value, new DateTimeZone($tz));
|
||
|
$date->setTimezone(new DateTimeZone($this->timezone));
|
||
|
if($keyword == 'DTSTART') {
|
||
|
$newEvent->setStartDttm($date);
|
||
|
} else if($keyword == 'DTEND') {
|
||
|
$newEvent->setEndDttm($date);
|
||
|
}
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
switch($keyword) {
|
||
|
case 'RRULE': // Recurrence Rule
|
||
|
// http://www.kanzaki.com/docs/ical/rrule.html
|
||
|
$pts = explode(';', $value);
|
||
|
foreach($pts as $recRules) {
|
||
|
$recRulePts = explode('=', $recRules);
|
||
|
switch($recRulePts[0]) {
|
||
|
case 'FREQ': // (MINUTELY, HOURLY, DAILY, WEEKLY, MONTHLY, YEARLY)
|
||
|
$newEvent->setRecurFrequency($recRulePts[1]);
|
||
|
break;
|
||
|
case 'INTERVAL': // 1 out of every x of FREQ that it recurs
|
||
|
$newEvent->setRecurInterval($recRulePts[1]);
|
||
|
break;
|
||
|
case 'COUNT': // Number of times it recurs
|
||
|
$newEvent->setRecurCount($recRulePts[1]);
|
||
|
break;
|
||
|
case 'UNTIL': // Recur until this date
|
||
|
// TODO: Create a DateTime
|
||
|
$date = new DateTime($recRulePts[1], new DateTimeZone('UTC'));
|
||
|
$date->setTimezone(new DateTimeZone($this->timezone));
|
||
|
$newEvent->setRecurUntil($date);
|
||
|
break;
|
||
|
case 'BYMONTH': // idx of months that it recurs (1 indexed)
|
||
|
$newEvent->setRecurByMonth($recRulePts[1]);
|
||
|
break;
|
||
|
case 'BYDAY': // (SU,MO,TU,WE,TH,FR,SA)
|
||
|
$newEvent->setRecurByDay($recRulePts[1]);
|
||
|
break;
|
||
|
case 'BYMONTHDAY': // idx of day of month, 1 indexed, <0 is from end
|
||
|
$newEvent->setRecurByMonthDay($recRulePts[1]);
|
||
|
break;
|
||
|
case 'BYYEARDAY': // idx of day of year
|
||
|
$newEvent->setRecurByYearDay($recRulePts[1]);
|
||
|
break;
|
||
|
case 'WKST': // Week Start?
|
||
|
$newEvent->setRecurWkSt($recRulePts[1]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 'DESCRIPTION': // Event Description
|
||
|
$newEvent->setDescription($value);
|
||
|
break;
|
||
|
case 'LOCATION': // Event Location
|
||
|
$newEvent->setLocation($value);
|
||
|
break;
|
||
|
case 'SUMMARY': // Event Summary
|
||
|
$newEvent->setSummary($value);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return $newEvent;
|
||
|
}
|
||
|
|
||
|
public function _parseFindNext($needle, $haystack, $start=0) {
|
||
|
$ret = [];
|
||
|
for($i = $start; $i < count($haystack); $i++) {
|
||
|
if(!empty(trim($haystack[$i]))) {
|
||
|
$ret[] = $haystack[$i];
|
||
|
if($haystack[$i] == $needle) {
|
||
|
return $ret;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// Didn't find it.
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
public function keyValueFromString($text) {
|
||
|
preg_match("/([^:]+)[:]([\w\W]*)/", $text, $matches);
|
||
|
if (count($matches) == 0) {
|
||
|
return false;
|
||
|
}
|
||
|
$matches = array_splice($matches, 1, 2);
|
||
|
return $matches;
|
||
|
}
|
||
|
|
||
|
// shortDayToDOWNum takes a 'Recur By Day' value (SU,MO,TU,WE,TH,FR,SA)
|
||
|
public function shortDayToDOWNum($shortDay) {
|
||
|
switch($shortDay) {
|
||
|
case 'SU': return 0;
|
||
|
case 'MO': return 1;
|
||
|
case 'TU': return 2;
|
||
|
case 'WE': return 3;
|
||
|
case 'TH': return 4;
|
||
|
case 'FR': return 5;
|
||
|
case 'SA': return 6;
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
class ICalEvent {
|
||
|
private $summary = '';
|
||
|
private $description = '';
|
||
|
private $location = '';
|
||
|
private $isRecurring = false;
|
||
|
private $_recurRules = [];
|
||
|
private $exceptionDates = [];
|
||
|
private $stDtTm;
|
||
|
private $endDtTm;
|
||
|
private $valid = false;
|
||
|
|
||
|
private $ICalTags = [];
|
||
|
|
||
|
public function __construct() { }
|
||
|
|
||
|
public function setSummary($s) { $this->summary = $s; }
|
||
|
public function getSummary() { return $this->summary; }
|
||
|
|
||
|
public function setDescription($s) { $this->description = $s; }
|
||
|
public function getDescription() { return $this->description; }
|
||
|
|
||
|
public function setStartDttm($dttm) { $this->stDtTm = $dttm; }
|
||
|
public function getStartDttm() { return $this->stDtTm; }
|
||
|
|
||
|
public function setEndDttm($dttm) { $this->endDtTm = $dttm; }
|
||
|
public function getEndDttm() { return $this->endDtTm; }
|
||
|
|
||
|
public function setLocation($loc) { $this->location = $loc; }
|
||
|
public function getLocation() { return $this->location; }
|
||
|
|
||
|
// getDuration returns a DateInterval for how long this event lasts
|
||
|
public function getDuration() {
|
||
|
return $this->stDtTm->diff($this->endDtTm);
|
||
|
}
|
||
|
|
||
|
public function isValid() {
|
||
|
return ($this->stDtTm < $this->endDtTm);
|
||
|
}
|
||
|
|
||
|
public function getRecurFlag() {
|
||
|
return $this->isRecurring;
|
||
|
}
|
||
|
|
||
|
public function getRecurRules() {
|
||
|
return $this->_recurRules;
|
||
|
}
|
||
|
|
||
|
public function getRecurRule($rule) {
|
||
|
if(isset($this->_recurRules[$rule])) {
|
||
|
return $this->_recurRules[$rule];
|
||
|
}
|
||
|
return '';
|
||
|
}
|
||
|
|
||
|
// Frequency to recur
|
||
|
public function setRecurFrequency($fr) {
|
||
|
if($fr == 'MINUTELY' || $fr == 'HOURLY' || $fr == 'DAILY'
|
||
|
|| $fr == 'WEEKLY' || $fr == 'MONTHLY' || $fr == 'YEARLY') {
|
||
|
$this->_recurRules['frequency'] = $fr;
|
||
|
$this->isRecurring = true;
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
public function getRecurFrequency() {
|
||
|
return $this->getRecurRule('frequency');
|
||
|
}
|
||
|
|
||
|
// One out of every $i of Frequency to occur
|
||
|
public function setRecurInterval($i) {
|
||
|
$this->_recurRules['interval'] = $i;
|
||
|
}
|
||
|
public function getRecurInterval() {
|
||
|
return $this->getRecurRule('interval');
|
||
|
}
|
||
|
|
||
|
// How many times it should recur
|
||
|
public function setRecurCount($i) {
|
||
|
$this->_recurRules['count'] = $i;
|
||
|
}
|
||
|
public function getRecurCount() {
|
||
|
return $this->getRecurRule('count');
|
||
|
}
|
||
|
|
||
|
// Date to stop recurring
|
||
|
public function setRecurUntil($dt) {
|
||
|
$this->_recurRules['until'] = $dt;
|
||
|
}
|
||
|
public function getRecurUntil() {
|
||
|
return $this->getRecurRule('until');
|
||
|
}
|
||
|
|
||
|
// array of 1-indexed months to recur on
|
||
|
public function setRecurByMonth($mos) {
|
||
|
$mos = is_array($mos)?$mos:[$mos];
|
||
|
$this->_recurRules['byMonth'] = $mos;
|
||
|
}
|
||
|
public function getRecurByMonth() {
|
||
|
return $this->getRecurRule('byMonth');
|
||
|
}
|
||
|
|
||
|
// array of abbreviated days to recur on (SU,MO,TU,WE,TH,FR,SA)
|
||
|
public function setRecurByDay($dys) {
|
||
|
$dys = is_array($dys)?$dys:[$dys];
|
||
|
$this->_recurRules['byDay'] = explode(',',$dys[0]);
|
||
|
}
|
||
|
public function getRecurByDay() {
|
||
|
return $this->getRecurRule('byDay');
|
||
|
}
|
||
|
|
||
|
// arary of 1-indexed day-of-months to recur on
|
||
|
public function setRecurByMonthDay($doms) {
|
||
|
$doms = is_array($doms)?$doms:[$doms];
|
||
|
$this->_recurRules['byMonthDay'] = $doms;
|
||
|
}
|
||
|
public function getRecurByMonthDay() {
|
||
|
return $this->getRecurRule('byMonthDay');
|
||
|
}
|
||
|
|
||
|
// array of 1-indexed day-of-years to recur on
|
||
|
public function setRecurByYearDay($doys) {
|
||
|
$doys = is_array($doys)?$doys:[$doys];
|
||
|
$this->_recurRules['byYearDay'] = $doys;
|
||
|
}
|
||
|
public function getRecurByYearDay() {
|
||
|
return $this->getRecurRule('byYearDay');
|
||
|
}
|
||
|
|
||
|
// Set the week start day for the recurrence
|
||
|
public function setRecurWkSt($wkst) {
|
||
|
$this->_recurRules['wkSt'] = $wkst;
|
||
|
}
|
||
|
public function getRecurWkSt() {
|
||
|
return $this->getRecurRule('wkSt');
|
||
|
}
|
||
|
|
||
|
public function setICalTag($key, $val) {
|
||
|
$this->ICalTags[$key] = $val;
|
||
|
}
|
||
|
|
||
|
public function addExceptionDate($dy) {
|
||
|
array_push($this->exceptionDates, $dy);
|
||
|
}
|
||
|
|
||
|
public function isExceptionDate($dy) {
|
||
|
foreach($this->exceptionDates as $exDt) {
|
||
|
if($dy == $exDt) {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function _eventSortHelper($a, $b) {
|
||
|
if($a->getStartDttm() == $b->getStartDttm()) {
|
||
|
return 0;
|
||
|
}
|
||
|
return ($a->getStartDttm() > $b->getStartDttm())?1:-1;
|
||
|
}
|
||
|
|
||
|
|