freq = preg_split("/[\s,]+/", FREQUENCE);
if ($rrule)
$this->setRule($rrule, $start, $end);
}
function setRule($rrule, $start, $end) {
if (!($start && $end))
throw new Exception("Missing values for DTSTART and/or DTEND");
//print "$start:$end
";
//print var_export($rrule, TRUE) . "
";
$this->start = CaldavRessource::iCal2Timestamp($start);
$this->end = CaldavRessource::iCal2Timestamp($end);
//print CaldavRessource::timestamp2ICal($this->start, TRUE).":".CaldavRessource::timestamp2ICal($this->end, TRUE)."
";
$rules = explode(';', $rrule);
//print_r($rules);
if (count($rules) < 2) {
foreach ($rules as $rule) {
$pair = explode('=', $rule);
if (count($pair) < 2 || !in_array($pair[1], $this->freq)) {
$this->rules = array();
throw new Exception("$rrule: Invalid RRULE");
}
$this->rules[strtolower($pair[0])] = explode(',', $pair[1]);
}
}
else {
foreach ($rules as $rule) {
$pair = explode('=', $rule);
$this->rules[strtolower($pair[0])] = explode(',', $pair[1]);
}
}
if ($this->rules['until'][0] && $this->rules['count'][0]) {
$this->rules = array();
throw new Exception("COUNT and UNTIL cannot be present at the same time");
}
if (!in_array($this->rules['freq'][0], $this->freq)) {
trigger_error(
"[{$this->rules['freq'][0]}] Unsupported FREQ",
E_USER_NOTICE);
$this->rules = array();
}
}
private function getEnd($freq) {
$count = $this->getCount();
$until = $this->getUntil();
//print "$until
";
if ($count) {
$int = $this->getInterval();
$count = ($int) ? $int * $count : $count;
switch ($freq) {
case 'HOURLY': $str = "+$count hour"; break;
case 'DAILY': $str = "+$count day"; break;
case 'WEEKLY': $str = "+$count week"; break;
case 'MONTHLY': $str = "+$count month"; break;
case 'YEARLY': $str = "+$count year"; break;
}
$end = strtotime($str, $this->start);
return ($this->range_end && $this->range_end < $end) ?
$this->range_end : $end;
}
else if ($until) {
/*
* UNTIL has first occurrence at end time and
* last ocurrence ending at start time
*/
//print "$until:".$this->start."
";
$u_s = explode("T", CaldavRessource::timestamp2ICal($this->end));
$time_s = (int) substr($u_s[1], 0, 2);
$u_e = explode("T", $until);
$time_e = (int) substr($u_e[1], 0, 2);
$until = ($time_s != $time_e) ? "{$u_e[0]}T{$u_s[1]}" : $until;
//print "$time_s:$time_e:$until
";
$end = CaldavRessource::iCal2Timestamp($until);
//print CaldavRessource::timestamp2ICal($end)."
";
return ($this->range_end && $this->range_end < $end) ?
$this->range_end : $end;
}
else
return $this->range_end;
}
private function except($ts) {
$byhour = $this->getByHour();
if ($byhour) {
$res = TRUE;
$match = gmdate('G', $ts);
foreach ($byhour as $hour) {
if ($match == $hour)
$res = FALSE;
if (! $res)
return FALSE;
}
return TRUE;
}
$byday = $this->getByDay();
if ($byday) {
$res = TRUE;
$match = substr(strtolower(gmdate('D', $ts)), 0, 2);
foreach ($byday as $day) {
//print "$match:$day\n";
if ($match == strtolower($day))
$res = FALSE;
if (! $res)
return FALSE;
}
return TRUE;
}
$bymonth = $this->getByMonth();
if ($bymonth) {
$res = TRUE;
$match = gmdate('n', $ts);
foreach ($bymonth as $month) {
if ($match == $month)
$res = FALSE;
if (! $res)
return FALSE;
}
return TRUE;
}
$bymonthday = $this->getByMonthDay();
if ($bymonthday) {
$res = TRUE;
$match = gmdate('j', $ts);
foreach ($bymonthday as $monthday) {
if ($match + 1 == $monthday)
$res = FALSE;
if (! $res)
return FALSE;
}
return TRUE;
}
$byweekno = $this->getByWeekNo();
if ($byweekno) {
$res = TRUE;
// Missing to handle Anglo week numbers
// (week start on Sunday)
$match = gmdate('W', $ts);
foreach ($byweekno as $weekno) {
if ($match == $weekno)
$res = FALSE;
if (! $res)
return FALSE;
}
return TRUE;
}
$byyearday = $this->getByYearDay();
if ($byyearday) {
$res = TRUE;
$match = gmdate('z', $ts);
foreach ($byyearday as $yearday) {
if ($match == $yearday)
$res = FALSE;
if (! $res)
return FALSE;
}
return TRUE;
}
return FALSE;
}
private function hourly() {
$res = array();
$end = $this->getEnd('HOURLY');
if (! $end) {
/**
* we will maximum handle one month at a time unless
* a specific end date specifies otherwise
*/
$end = strtotime('+1 month', $this->start);
}
$int = ($this->getInterval()) ? $this->getInterval() : 1;
$c = $this->start;
for (; $c < $end; $c = strtotime("+$int hour", $c)) {
if (! $this->except($c))
array_push($res, CaldavRessource::timestamp2ICal($c));
}
return $res;
}
private function daily() {
$res = array();
$end = $this->getEnd('DAILY');
if (! $end) {
/**
* we will maximum handle one month at a time unless
* a specific end date specifies otherwise
*/
$end = strtotime('+1 month', $this->start);
}
$int = ($this->getInterval()) ? $this->getInterval() : 1;
$c = $this->start;
for (; $c < $end; $c = strtotime("+$int day", $c)) {
if (! $this->except($c))
array_push($res, CaldavRessource::timestamp2ICal($c));
}
return $res;
}
private function weekly() {
$res = array();
$end = $this->getEnd('WEEKLY');
//print "start: ".CaldavRessource::timestamp2ICal($this->start)." end: ".CaldavRessource::timestamp2ICal($end)."\n";
if (! $end) {
/**
* we will maximum handle 12 weeks at a time unless
* a specific end date specifies otherwise
*/
$end = strtotime('+12 week', $this->start);
}
$int = ($this->getInterval()) ? $this->getInterval() : 1;
$c = $this->start;
for (; $c < $end; $c = strtotime("+$int week", $c)) {
//print CaldavRessource::timestamp2ICal($c)."
";
if (! $this->except($c))
array_push($res, CaldavRessource::timestamp2ICal($c));
}
//print_r($res);
return $res;
}
private function monthly() {
$res = array();
$end = $this->getEnd('MONTHLY');
if (! $end) {
/**
* we will maximum handle 12 months at a time unless
* a specific end date specifies otherwise
*/
$end = strtotime('+12 month', $this->start);
}
$int = ($this->getInterval()) ? $this->getInterval() : 1;
$c = $this->start;
for (; $c < $end; $c = strtotime("+$int month", $c)) {
if (! $this->except($c))
array_push($res, CaldavRessource::timestamp2ICal($c));
}
return $res;
}
private function yearly() {
$res = array();
$end = $this->getEnd('YEARLY');
if (! $end) {
/**
* we will maximum handle 12 years at a time unless
* a specific end date specifies otherwise
*/
$end = strtotime('+12 year', $this->start);
}
$int = ($this->getInterval()) ? $this->getInterval() : 1;
$c = $this->start;
for (; $c < $end; $c = strtotime("+$int year", $c)) {
if (! $this->except($c))
array_push($res, CaldavRessource::timestamp2ICal($c));
}
return $res;
}
private function limitRange($dates) {
$res = array();
if (!$this->range_start && !$this->range_end) {
$res = $dates;
}
else if ($this->range_start && !$this->range_end) {
$start = CaldavRessource::timestamp2ICal($this->range_start);
foreach ($dates as $date) {
if (CaldavRessource::datecmp($start, $date) < 0)
array_push($res, $date);
}
}
else {
$start = CaldavRessource::timestamp2ICal($this->range_start);
$end = CaldavRessource::timestamp2ICal($this->range_end);
foreach ($dates as $date) {
if (CaldavRessource::datecmp($start, $date) < 0 &&
CaldavRessource::datecmp($end, $date) > 0)
array_push($res, $date);
}
}
return $res;
}
function getFreq() {
return strtoupper($this->rules['freq'][0]);
}
function getUntil() {
return strtoupper($this->rules['until'][0]);
}
function getCount() {
return strtoupper($this->rules['count'][0]);
}
function getInterval() {
return strtoupper($this->rules['interval'][0]);
}
function getBySecond() {
$l = $this->rules['bysecond'];
if ($l) {
foreach ($l as $val)
$list[] = strtoupper($val);
}
return $list;
}
function getByMinute() {
$l = $this->rules['byminute'];
if ($l) {
foreach ($l as $val)
$list[] = strtoupper($val);
}
return $list;
}
function getByHour() {
$l = $this->rules['byhour'];
if ($l) {
foreach ($l as $val)
$list[] = strtoupper($val);
}
return $list;
}
function getByDay() {
$l = $this->rules['byday'];
if ($l) {
foreach ($l as $val)
$list[] = strtoupper($val);
}
return $list;
}
function getByMonthDay() {
$l = $this->rules['bymonthday'];
if ($l) {
foreach ($l as $val)
$list[] = strtoupper($val);
}
return $list;
}
function getByYearDay() {
$l = $this->rules['byyearday'];
if ($l) {
foreach ($l as $val)
$list[] = strtoupper($val);
}
return $list;
}
function getByWeekNo() {
$l = $this->rules['byweekno'];
if ($l) {
foreach ($l as $val)
$list[] = strtoupper($val);
}
return $list;
}
function getByMonth() {
$l = $this->rules['bymonth'];
if ($l) {
foreach ($l as $val)
$list[] = strtoupper($val);
}
return $list;
}
function getBySetPos() {
return strtoupper($this->rules['bysetpos'][0]);
}
function getWKST() {
return strtoupper($this->rules['wkst'][0]);
}
function getAll() {
return $this->rules;
}
function getEventDates($startDate = NULL, $endDate = NULL) {
$dates = array();
$freq = $this->getFreq();
//print "$freq\n";
if (! in_array($freq, $this->freq))
return $dates;
if ($startDate && $endDate) {
$this->range_start = CaldavRessource::iCal2Timestamp($startDate);
$this->range_end = CaldavRessource::iCal2Timestamp($endDate);
if ($this->start > $this->range_end)
return $dates;
}
else if ($startDate) {
$this->range_start = CaldavRessource::iCal2Timestamp($startDate);
$this->range_end = NULL;
}
else {
$this->range_start = NULL;
$this->range_end = NULL;
}
switch ($freq) {
case 'HOURLY': $dates = $this->hourly(); break;
case 'DAILY': $dates = $this->daily(); break;
case 'WEEKLY': $dates = $this->weekly(); break;
case 'MONTHLY': $dates = $this->monthly(); break;
case 'YEARLY': $dates = $this->yearly(); break;
default: break;
}
//print_r($dates);
return (count($dates) > 0) ? $this->limitRange($dates) : $dates;
}
function getStartAndEnd() {
$res['start'] = $this->start;
$res['end'] = $this->end;
return $res;
}
function __toString() {
$str = "FREQ=" . $this->getFreq();
$until = $this->getUntil();
$count = $this->getCount();
if ($until)
$str .= ';UNTIL=' . $until;
if ($count)
$str .= ';COUNT=' . $count;
foreach ($this->rules as $k => $v) {
if ($k == 'freq' || $k == 'count' || $k == 'until')
continue;
$str .= ';' . strtoupper($k) . '=';
foreach($v as $rule) {
if ($str[strlen($str) - 1] != '=')
$str .= ',';
$str .= strtoupper($rule);
}
}
return $str;
}
}