예제 #1
0
 function amr_events_exclude_in_progress($constrained)
 {
     // exclude any events that started before the start date
     global $amr_limits;
     foreach ($constrained as $i => $e) {
         if (amr_is_before($e['EventDate'], $amr_limits['start'])) {
             unset($constrained[$i]);
         }
     }
     return $constrained;
 }
예제 #2
0
function amr_process_RRULE($p, $start, $astart, $aend, $limit)
{
    /* RRULE a parsed array.  If the specified event repeats between the given start and
     * end times, return one or more nonrepeating date strings in array
     */
    global $amr_wkst, $amr_timeperiod_conv;
    /* converts daily to day etc */
    /* now we should have if they are there: $p[freq], $p[interval, $until, $wkst, $ count, $byweekno etc */
    /* check  / set limits  NB don't forget the distinction between the two kinds of limits  */
    $tz = date_timezone_get($start);
    if (isset($_GET['rdebug'])) {
        echo '<br />&nbsp;start=' . $start->format('c') . ' <br />astart=' . $astart->format('c') . '<br /> parameter passed: ';
        if (is_array($p)) {
            foreach ($p as $k => $i) {
                echo $k . ' ';
                if (is_object($i)) {
                    echo $i->format('c');
                } else {
                    print_r($i);
                }
                echo '<br />';
            }
        } else {
            echo '<br />rule passed';
            var_dump($p);
        }
    }
    if (!isset($p['COUNT'])) {
        $count = AMR_MAX_REPEATS;
    } else {
        $count = $p['COUNT'];
    }
    if (isset($_GET['cdebug'])) {
        echo '<br />Limiting the repeats to ' . $count;
    }
    $until = amr_newDateTime();
    $original_until = amr_newDateTime();
    if (!isset($p['UNTIL'])) {
        $until = clone $aend;
        $original_until = clone $aend;
    } else {
        $until = clone $p['UNTIL'];
        $original_until = clone $p['UNTIL'];
        if ($until > $aend) {
            $until = clone $aend;
        }
    }
    // 2014 07 09
    $original_start = amr_newDateTime();
    $original_start = clone $start;
    $next_start = amr_newDateTime();
    $next_start = clone $start;
    if (amr_is_before($until, $astart)) {
        return false;
    }
    /* if it ends before our overall start, then skip */
    /* now prepare out "intervals array for date incrementing eg: p[monthly] = 2 etc... Actualy there should only be 1 */
    if (isset($p['FREQ'])) {
        /* so know yearly, daily or weekly etc  - setup increments eg 2 yearsly or what */
        if (!isset($p['INTERVAL'])) {
            $p['INTERVAL'] = 1;
        }
        switch ($p['FREQ']) {
            case 'WEEKLY':
                $int['day'] = $p['INTERVAL'] * 7;
                break;
            default:
                $inttype = $amr_timeperiod_conv[$p['FREQ']];
                $int[$inttype] = $p['INTERVAL'];
        }
        $freq = $p['FREQ'];
    }
    /*  use the freq increment to get close to our listing start time.  If we are within one freq of our listing start, we should be safe in calculating the odd rrules. */
    /* NOTE we can only do this if we do not have the count or a bysetpos !!!!   */
    //	if (empty($int)) var_dump($p);
    if (empty($p['COUNT']) and empty($p['BYSETPOS']) and !empty($int)) {
        $next_start = amr_get_a_closer_start($next_start, $astart, $int);
    }
    // 20110301 the nbydays, especially the negs, require that one initially consider a wider valid range so as not to unintentionally exclude a date before the expand/contract has beeen applied .  Ie we might iterate to 28th and exclude, but actually once one has applied the -2Mo or some such rule, the date would have contracted into the valid range.  So apply restrictions later.
    $until = amr_increment_datetime($until, $int);
    unset($p['UNTIL']);
    /* unset so we can use other params more cleanly, we have count saved etc */
    unset($p['COUNT']);
    unset($p['FREQ']);
    unset($p['INTERVAL']);
    if (!empty($p['WKST'])) {
        $wkst = $p['WKST'];
        unset($p['WKST']);
    } else {
        $wkst = $amr_wkst;
    }
    if (count($p) === 0) {
        $p = null;
    }
    /* If that was all we had, get rid of it anyway */
    if (isset($p['NBYDAY'])) {
        /* if we separated these in the parsing process, merge them here,    NOOO - will cause problems with the +1's and bool */
        if (isset($p['BYDAY'])) {
            $p['BYDAY'] = array_merge($p['NBYDAY'], $p['BYDAY']);
        } else {
            $p['BYDAY'] = $p['NBYDAY'];
        }
        unset($p['NBYDAY']);
    }
    while ($next_start <= $until) {
        /* don't check astart here - may miss some */
        $datearray[] = amr_get_date_parts($next_start);
        if (isset($_GET['rdebug'])) {
            echo '<hr>Checked start against extra until (1 extra iteration to allow for negativebydays) etc ' . $next_start->format('c') . ' ' . $until->format('c');
            echo '<br />date array = ';
            var_dump($datearray);
        }
        switch ($freq) {
            /* the 'bys' are now in an array $p .  NOTE THE sequence here is important */
            case 'SECONDLY':
                if (isset($p['month'])) {
                    $datearray = amr_limit($datearray, $p['month'], 'month');
                }
                /* BYWEEK NO not applicable here */
                if (isset($p['BYYEARDAY'])) {
                    $datearray = amr_limit_by_yearday($datearray, $p['BYYEARDAY'], $tz);
                }
                if (isset($p['day'])) {
                    $datearray = amr_limit($datearray, $p['day'], 'day');
                }
                if (isset($p['BYDAY'])) {
                    $datearray = amr_limit_by_day_of_week($datearray, $p['BYDAY'], $tz);
                }
                //				foreach ($p as $i => $by) amr_limit_dates_withby($dates);
                if (isset($p['hour'])) {
                    $datearray = amr_limit($datearray, $p['hour'], 'hour');
                }
                if (isset($p['minute'])) {
                    $datearray = amr_limit($datearray, $p['minute'], 'minute');
                }
                if (isset($p['second'])) {
                    $datearray = amr_limit($datearray, $p['second'], 'second');
                }
                break;
            case 'MINUTELY':
                if (isset($p['month'])) {
                    $datearray = amr_limit($datearray, $p['month'], 'month');
                }
                /* BYWEEK NO not applicable here */
                if (isset($p['BYYEARDAY'])) {
                    $datearray = amr_limit_by_yearday($datearray, $p['BYYEARDAY'], $tz);
                }
                if (isset($p['day'])) {
                    $datearray = amr_limit($datearray, $p['day'], 'day');
                }
                if (isset($p['BYDAY'])) {
                    $datearray = amr_limit_by_day_of_week($datearray, $p['BYDAY'], $tz);
                }
                if (isset($p['hour'])) {
                    $datearray = amr_limit($datearray, $p['hour'], 'hour');
                }
                if (isset($p['minute'])) {
                    $datearray = amr_limit($datearray, $p['minute'], 'minute');
                }
                if (isset($p['second'])) {
                    $datearray = amr_expand($datearray, $p['second'], 'second', $tz);
                }
                break;
            case 'HOURLY':
                if (isset($p['month'])) {
                    $datearray = amr_limit($datearray, $p['month'], 'month');
                }
                /* BYWEEK NO not applicable here */
                if (isset($p['BYYEARDAY'])) {
                    $datearray = amr_limit_by_yearday($datearray, $p['BYYEARDAY'], $tz);
                }
                if (isset($p['day'])) {
                    $datearray = amr_limit($datearray, $p['day'], 'day');
                }
                if (isset($p['BYDAY'])) {
                    $datearray = amr_limit_by_day_of_week($datearray, $p['BYDAY'], $tz);
                }
                if (isset($p['hour'])) {
                    $datearray = amr_limit($datearray, $p['hour'], 'hour', $tz);
                }
                if (isset($p['minute'])) {
                    $datearray = amr_expand($datearray, $p['minute'], 'minute', $tz);
                }
                if (isset($p['second'])) {
                    $datearray = amr_expand($datearray, $p['second'], 'second', $tz);
                }
                break;
            case 'DAILY':
                if (isset($p['month'])) {
                    $datearray = amr_limit($datearray, $p['month'], 'month');
                }
                /* BYWEEK NO and BYYEARDAY not applicable here */
                if (isset($p['day'])) {
                    $datearray = amr_limit($datearray, $p['day'], 'day');
                }
                if (isset($p['BYDAY'])) {
                    $datearray = amr_limit_by_day_of_week($datearray, $p['BYDAY'], $tz);
                }
                if (isset($p['hour'])) {
                    $datearray = amr_expand($datearray, $p['hour'], 'hour', $tz);
                }
                if (isset($p['minute'])) {
                    $datearray = amr_expand($datearray, $p['minute'], 'minute', $tz);
                }
                if (isset($p['second'])) {
                    $datearray = amr_expand($datearray, $p['second'], 'second', $tz);
                }
                break;
            case 'WEEKLY':
                if (isset($p['month'])) {
                    $datearray = amr_limit($datearray, $p['month'], 'month');
                }
                /* BYWEEK NO and BYYEARDAY and BYMONTH DAY not applicable here */
                if (isset($p['BYDAY'])) {
                    $datearray = amr_expand_by_day_of_week_for_weekly($datearray, $p, $tz, $wkst);
                }
                if (isset($p['hour'])) {
                    $datearray = amr_expand($datearray, $p['hour'], 'hour', $tz);
                }
                if (isset($p['minute'])) {
                    $datearray = amr_expand($datearray, $p['minute'], 'minute', $tz);
                }
                if (isset($p['second'])) {
                    $datearray = amr_expand($datearray, $p['second'], 'second', $tz);
                }
                break;
            case 'MONTHLY':
                if (isset($p['month'])) {
                    $datearray = amr_limit($datearray, $p['month'], 'month');
                }
                /* BYWEEK NO and BYYEARDAY not applicable here */
                if (isset($p['day'])) {
                    $datearray = amr_expand($datearray, $p['day'], 'day', $tz);
                }
                if (isset($p['BYDAY']) or isset($p['NBYDAY'])) {
                    /* as per note 1  on page 44 of http://www.rfc-archive.org/getrfc.php?rfc=5545 */
                    if (isset($p['day'])) {
                        /* BYDAY limits if BYMONTH DAY is present , else a special expand for monthly */
                        $datearray = amr_limit_by_day_of_week($datearray, $p, $tz);
                    } else {
                        $datearray = amr_special_expand_by_day_of_week_and_month_note1($datearray, $p, $tz);
                    }
                }
                if (isset($p['hour'])) {
                    $datearray = amr_expand($datearray, $p['hour'], 'hour', $tz);
                }
                if (isset($p['minute'])) {
                    $datearray = amr_expand($datearray, $p['minute'], 'minute', $tz);
                }
                if (isset($p['second'])) {
                    $datearray = amr_expand($datearray, $p['second'], 'second', $tz);
                }
                break;
            case 'YEARLY':
                if (isset($p['month'])) {
                    $datearray = amr_expand($datearray, $p['month'], 'month', $tz);
                }
                if (isset($p['BYWEEKNO'])) {
                    $datearray = amr_expand_by_weekno($datearray, $p['BYWEEKNO'], $tz);
                }
                if (isset($p['BYYEARDAY'])) {
                    $datearray = amr_expand_by_yearday($datearray, $p['BYYEARDAY'], $tz);
                }
                if (isset($p['day'])) {
                    $datearray = amr_expand($datearray, $p['day'], 'day', $tz);
                }
                if (isset($p['BYDAY'])) {
                    if (isset($p['day']) or isset($p['BYYEARDAY'])) {
                        /*Note 2:  BYDAY limits if BYMONTH DAY or BYYEARDAY  is present */
                        $datearray = amr_limit_by_day_of_week($datearray, $p['BYDAY'], $tz);
                    } else {
                        $datearray = amr_expand_by_day_of_week_for_year($datearray, $p, $tz);
                    }
                }
                //				if (isset($p['NBYDAY'])) {
                //					if (isset($p['day']) or isset($p['BYYEARDAY'])) /*Note 2:  BYDAY limits if BYMONTH DAY or BYYEARDAY  is present */
                //												$datearray = amr_limit_by_day_of_week ($datearray, $p['NBYDAY'],$tz);
                //					else 						$datearray = amr_expand_by_day_of_week_for_year ($datearray, $p,$tz);
                //				}
                if (isset($p['hour'])) {
                    $datearray = amr_expand($datearray, $p['hour'], 'hour', $tz);
                }
                if (isset($p['minute'])) {
                    $datearray = amr_expand($datearray, $p['minute'], 'minute', $tz);
                }
                if (isset($p['second'])) {
                    $datearray = amr_expand($datearray, $p['second'], 'second', $tz);
                }
                break;
        }
        $datearray = amr_sort_date_array($datearray);
        if (isset($_GET['rdebug'])) {
            echo '<br /> We have in date array: ';
            print_r($datearray);
        }
        // There will only be > 1 if there was an expanding BY:
        if (!empty($datearray) and !empty($p['BYSETPOS'])) {
            $datearray = amr_limit_by_setpos($datearray, $p['BYSETPOS']);
            if (isset($_GET['rdebug'])) {
                echo '<br />Selected after bysetpos:';
                print_r($p['BYSETPOS']);
                echo '</br>';
                print_date_array($datearray);
            }
            $datearray = amr_sort_date_array($datearray);
            /* sort again as the set position may have trashed it */
        }
        //		$num_events = count($datearray);
        //		if (isset ($_GET['cdebug'])) {echo '<br />We have '. $num_events.' events.  We want max:'.$count;	}
        //		if ($num_events > $count)  $datearray = array_slice($datearray,0, $count);
        //		if (isset ($_GET['cdebug'])) {echo '<br />Limit date array, now have :'.count($datearray);
        //			echo '<br>From  '.$astart->format('Y m d h:i').' until '.$until->format('Y m d h:i');
        //		}
        if (!empty($datearray)) {
            foreach ($datearray as $d) {
                /* create the date objects  */
                $possdate = amr_create_date_from_parts($d, $tz);
                if (is_object($possdate)) {
                    if (isset($_GET['rdebug'])) {
                        echo '<br>Possdate=' . $possdate->format('Y m d h:i:s');
                    }
                    //					if 	(($possdate <= $until) and ($possdate >= $astart)) {
                    $repeats[] = $possdate;
                    //						if (isset ($_GET['rdebug'])) echo ' - saved';
                }
            }
        }
        unset($datearray);
        /* now get next start */
        $next_start = amr_increment_datetime($next_start, $int);
        if (isset($_GET['rdebug'])) {
            echo '<hr>Next start data after incrementing = ' . $next_start->format('Y m d l h:i:s');
        }
    }
    /* end while*/
    //-----------------------------------------------------------------------
    if (isset($_GET['rdebug'])) {
        echo '<hr>Stop now..checked start against extra until <br>start=' . $next_start->format('c') . '<br>until=' . $until->format('c') . ' the extra until!';
        if ($next_start > $until) {
            echo '<br /><b>php says start > extra until </b>';
        }
    }
    if (!empty($repeats)) {
        $repeats = amr_limit_occurences($repeats, $count);
        foreach ($repeats as $i => $d) {
            /* check if it is within date limits  */
            if (isset($_GET['rdebug'])) {
                echo '<br>*** Check for this rrule - original until. ' . '<br />-------astart = ' . $astart->format('c') . '<br />original start = ' . $original_start->format('c') . '<br />instancedate = ' . $d->format('c') . '<br />originaluntil= ' . $original_until->format('c') . '<br />';
            }
            if (!($d <= $original_until and $d >= $original_start)) {
                //note these are rrule limits, not the overall limits
                unset($repeats[$i]);
                if (isset($_GET['rdebug'])) {
                    echo '<br>Event instance not within rrule limits - <b>removed</b> ' . $d->format('Y m d h:i') . '<br />';
                }
            } else {
                if (isset($_GET['rdebug'])) {
                    echo '<br>Event instance within rrule limits ' . $d->format('Y m d h:i') . '<br />';
                }
            }
        }
    }
    if (isset($_GET['rdebug'])) {
        if (empty($repeats)) {
            echo '<b>No repeats!</b><hr>';
        } else {
            echo '<b>' . count($repeats) . ' repeats before further processing, exclusions etc</b><hr>';
            foreach ($repeats as $i => $r) {
                echo '<br />' . $r->format('c');
            }
            echo '<hr/>Need use debugexc to check exclusion logic';
        }
    }
    if (empty($repeats)) {
        return null;
    }
    return $repeats;
}
function amr_generate_repeats(&$event, $astart, $aend, $limit)
{
    /* takes an event and some parameters and generates the repeat events */
    $repeats = array();
    // and array of dates
    $newevents = array();
    // an array of events
    if (isset($event['DTSTART'])) {
        if (is_object($event['DTSTART'])) {
            $dtstart = $event['DTSTART'];
            $dt = empty($event['DTSTART']) ? '' : $event['DTSTART']->format('c');
            /* begin setting up the event key that will help us check for modifocations - semingly duplicates! - overwrite for repeats */
        } else {
            if (ICAL_EVENTS_DEBUG) {
                echo '<r><b>DTSTART is not an object</b>' . $event['DTSTART'];
            }
            return false;
            /* it is set, but it is not an aobject ? */
        }
    } else {
        /* possibly an undated, non repeating VTODO or Vjournal- no repeating to be done if no DTSTART, and no RDATE */
        $dt = '-nodtstart';
        if (!isset($event['RDATE'])) {
            if (isset($event['UID'])) {
                $newevents[$event['UID']] = $event;
            } else {
                amr_tell_admin_the_error('There is an invalid event.  It has no UID:' . print_r($event, true));
            }
            return $newevents;
            /* possibly an undated, non repeating VTODO or Vjournal- no repeating to be done if no DTSTART, and no RDATE */
        } else {
            echo 'This event is invalid.  It has no DTSTART, but does have RDATE.  Not allowed according to ical spec.';
            return false;
            /***check for repeating RDATEs if no start date */
        }
    }
    /* To handle modifications, use a key to the events, so can match any later mods with a repeating event we may have generated */
    $seq = empty($event['SEQUENCE']) ? '0' : $event['SEQUENCE'];
    /* begin setting up the event key that will help us check for modifications - semingly duplicates!*/
    if (!isset($event['UID'])) {
        $event['UID'] = 'NoUID';
    }
    /* there is no repeating rule, so just copy over */
    if (isset($event['RECURRENCE-ID'])) {
        /* a modification or exceptions to a repeating instance ? */
        //					$recdate = $dt;
        if (isset($_GET['debugexc'])) {
            echo '<br />RECURRENCE-ID:';
            var_dump($event['RECURRENCE-ID']);
        }
        if (is_array($event['RECURRENCE-ID'])) {
            /* just take first, should only be one */
            $recdateobj = $event['RECURRENCE-ID'][0];
            $recdate = $recdateobj->format('YmdHis');
            // purely identifies specifc instances of a repeating rule are affected by the exception/modification
            //20140721 - lost the month in ymd somehow - added back
            if (isset($_GET['debugexc'])) {
                echo '<br /> Flag recurrence modification for ' . $recdate;
            }
        } else {
            if (is_object($event['RECURRENCE-ID'])) {
                /* Then it is a date instance which has been modified .  We need to overwrite the appropriate repeating dates.  This is done later? *** */
                $recdateobj = $event['RECURRENCE-ID'];
                $recdate = $recdateobj->format('YmdHis');
                if (isset($_GET['debugexc'])) {
                    echo '<br />RecurrenceID date to check against event rrule.';
                    echo $recdate;
                }
            } else {
                /****  should deal with THISANDFUTURE or THISANDPRIOR  EG:
                		 RECURRENCE-ID;RANGE=THISANDPRIOR:19980401T133000Z */
                echo '<br>THISAND.... modification to repeating event encountered.  This cannot be dealt with yet';
                var_dump($event['RECURRENCE-ID']);
            }
        }
        if (amr_event_should_be_shown($event, $astart, $aend) or amr_falls_between($recdateobj, $astart, $aend) or amr_is_same_day($recdateobj, $astart) or amr_is_same_day($recdateobj, $aend)) {
            $key = $event['UID'] . ' ' . $recdate . ' ' . $seq . '999';
            /* By virtue of being a recurrence id it should override a non recurrence (ie normal) even if they have the same sequence */
            $newevents[$key] = $event;
            /* so we drop the old events used to generate the repeats */
            $newevents[$key]['EventDate'] = new Datetime();
            //if cloning dont need tz
            $newevents[$key]['EventDate'] = clone $dtstart;
            if (!amr_create_enddate($newevents[$key])) {
                if (ICAL_EVENTS_DEBUG) {
                    echo ' ** No end date - is it an alarm? ';
                }
            }
        } else {
            if (isset($_GET['debugexc'])) {
                echo '<br /> ' . $recdate . ' not in range and ' . $dtstart->format('c') . ' not in range';
                //					debug_print_event ($event);
            }
            return false;
            /* the modification and the instance that it relates to are not in our date range */
        }
    } else {
        /* It is not a recurrence id, may be a repeating, or solo */
        if (isset($dtstart)) {
            if (amr_is_before($dtstart, $aend)) {
                /* If the start is after our end limit, then skip this event */
                //var_dump($event);
                if (isset($event['RRULE']) or isset($event['RDATE'])) {
                    /* if have, must use dtstart in case we are dependent on it's characteristics,. We can exclude too early dates later on */
                    $repeats = amr_repeat_anevent($event, $astart, $aend, $limit);
                    /**** try for a more efficient start? */
                    if (isset($_GET['rdebug']) or ICAL_EVENTS_DEBUG) {
                        if (count($repeats) > 0) {
                            echo '<br>Create repeats: ' . count($repeats);
                        }
                    }
                    /* now need to convert back to a full event by copying the event data for each repeat */
                    if (is_array($repeats) and count($repeats) > 0) {
                        foreach ($repeats as $i => $r) {
                            $repkey = $event['UID'] . ' ' . $r->format('YmdHis') . ' ' . $seq;
                            /* Don't use timezone - some recurrence id's maybe created with universal dates */
                            if (isset($newevents[$repkey])) {
                                // error_log('Unexpected Duplication of Repeating Event '.$repkey.' - error in ical file or error in plugin?'); // only happened on weird rrule - may be valid anyway so as not to miss anything
                            }
                            $newevents[$repkey] = $event;
                            // copy the event data over - note objects will point to same object unless we clone   Use duration or new /clone Enddate
                            $newevents[$repkey]['EventDate'] = new Datetime();
                            //if cloning dont need tz
                            $newevents[$repkey]['EventDate'] = clone $r;
                            //							if (ICAL_EVENTS_DEBUG) {echo '<br>Created '.$newevents[$repkey]['EventDate']->format('YmdHis l');	}
                            if (!amr_create_enddate($newevents[$repkey])) {
                                if (ICAL_EVENTS_DEBUG) {
                                    echo ' ** No end date created, maybe just a start? ';
                                }
                            }
                        }
                    }
                } else {
                    $key = $event['UID'] . ' ' . $dt . ' ' . $seq;
                    /* No Recurrence id and no RRULE or RDATE */
                    $newevents[$key] = $event;
                    // copy the event data over - note objects will point to same object - is this an issue?   Use duration or new /clone Enddate
                    $newevents[$key]['EventDate'] = new Datetime();
                    //if cloning dont need tz
                    $newevents[$key]['EventDate'] = clone $dtstart;
                    if (isset($newevents[$key]['DURATION'])) {
                        amr_create_enddate($newevents[$key]);
                        //changed because EndDate not same as DTEND if all day
                    }
                }
            }
        } else {
            // no starting date
            $key = $event['UID'] . ' ' . $dt . ' ' . $seq;
            $newevents[$key] = $event;
            $newevents[$key]['EventDate'] = '';
        }
    }
    if (ICAL_EVENTS_DEBUG) {
        echo '<br />number of newevents = ' . count($newevents);
    }
    return $newevents;
}