Compare commits

...

4 commits

11 changed files with 258 additions and 3120 deletions

15
README.md Normal file
View file

@ -0,0 +1,15 @@
# Webseite
Das Repository enthält die Webseite das Vereins "Hackspace Jena". Der größte
Teil der Webseite ist statisches HTML, ergänzt um einige dynamische
Elemente zur Anzeige des Raumstatuses und der aktuellen Termine.
## Installation
Zum Betrieb der Webseite ist ist in Webserver und PHP notwendig. Die
Auswertung der Termine erfolgt mittels der VObject Bibliothek von
[https://sabre.io](https://sabre.io), welche auch in Nextcloud enthalten
ist. Debian stellt die Bibliothe in dem Paket php-sabre-vobject bereit. Nach
der Installation und Konfiguration des Websevers inklusive PHP wird das Repo
in das Dokumentroot des Webservers kopiert.

View file

@ -14,13 +14,13 @@ BEGIN:VEVENT
SUMMARY:"Chaostreff" SUMMARY:"Chaostreff"
UID:0000000002@kraut.space UID:0000000002@kraut.space
CLASS:PUBLIC CLASS:PUBLIC
DESCRIPTION:"Offene Runde" DESCRIPTION:Offene Runde
DTEND;TZID=CET:20200623T235900 DTEND;TZID=CET:20200623T235900
DTSTAMP;TZID=CET:20200623T125900 DTSTAMP;TZID=CET:20200623T125900
DTSTART;TZID=CET:20200623T200000 DTSTART;TZID=CET:20200623T200000
GEO:50.9292035\,11.5825763 GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena" LOCATION:Krautgasse 26, 07743 Jena und online unter https://kraut.space/chaostreff
URL;VALUE="HTTPS://kraut.space/chaostreff" URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:chaostreff:start
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY RRULE:FREQ=WEEKLY
@ -29,28 +29,28 @@ BEGIN:VEVENT
SUMMARY:"Brettspielrunde" SUMMARY:"Brettspielrunde"
UID:0000000003@kraut.space UID:0000000003@kraut.space
CLASS:PUBLIC CLASS:PUBLIC
DESCRIPTION:"Brettspielerei" DESCRIPTION:Brettspielerei
DTEND;TZID=CET:20220518T235900 DTSTAMP;TZID=CET:20221116T125900
DTSTAMP;TZID=CET:20220518T125900 DTSTART;TZID=CET:20221116T200000
DTSTART;TZID=CET:20220518T200000 DTEND;TZID=CET:20221116T235900
GEO:50.9292035\,11.5825763 GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena" LOCATION:Krautgasse 26, 07743 Jena
URL;VALUE="HTTPS://kraut.space/brettspielerei" URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:brettspielerei
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,36,38,40,42,44,46,48,50,52 RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=WE;BYWEEKNO=2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,36,38,40,42,44,46,48,50,52
END:VEVENT END:VEVENT
BEGIN:VEVENT BEGIN:VEVENT
SUMMARY:"Linux User Group" SUMMARY:"Linux User Group"
UID:0000000004@kraut.space UID:0000000004@kraut.space
CLASS:PUBLIC CLASS:PUBLIC
DESCRIPTION:"Alles rund um Linux" DESCRIPTION:Alles rund um Linux
DTEND;TZID=CET:20200625T235900 DTEND;TZID=CET:20200625T235900
DTSTAMP;TZID=CET:20200623T125900 DTSTAMP;TZID=CET:20200623T125900
DTSTART;TZID=CET:20200625T200000 DTSTART;TZID=CET:20200625T200000
GEO:50.9292035\,11.5825763 GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena" LOCATION:Krautgasse 26, 07743 Jena und online unter https://kraut.space/lug
URL;VALUE="HTTPS://kraut.space/lug" URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:lug:start
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY RRULE:FREQ=WEEKLY
@ -59,13 +59,13 @@ BEGIN:VEVENT
SUMMARY:"Gaming am Freitag" SUMMARY:"Gaming am Freitag"
UID:0000000005@kraut.space UID:0000000005@kraut.space
CLASS:PUBLIC CLASS:PUBLIC
DESCRIPTION:"Der Stammtisch für Videospielkultur" DESCRIPTION:Der Stammtisch für Videospielkultur
DTEND;TZID=CET:20220527T235900 DTEND;TZID=CET:20220527T235900
DTSTAMP;TZID=CET:20220527T125900 DTSTAMP;TZID=CET:20220527T125900
DTSTART;TZID=CET:20220527T190000 DTSTART;TZID=CET:20220527T190000
GEO:50.9292035\,11.5825763 GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena" LOCATION:Krautgasse 26, 07743 Jena
URL;VALUE="HTTPS://kraut.space/gamingamfreitag" URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:gaming
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53 RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53
@ -74,15 +74,15 @@ BEGIN:VEVENT
SUMMARY:"Kinderbasteln" SUMMARY:"Kinderbasteln"
UID:0000000006@kraut.space UID:0000000006@kraut.space
CLASS:PUBLIC CLASS:PUBLIC
DESCRIPTION:"Natur und Technik für Vor- und Grundschulkinder" DESCRIPTION:Natur und Technik für Vor- und Grundschulkinder
DTEND;TZID=CET:20220611T120000 DTEND;TZID=CET:20220611T120000
DTSTAMP;TZID=CET:20220611T100000 DTSTAMP;TZID=CET:20220611T100000
DTSTART;TZID=CET:20220611T100000 DTSTART;TZID=CET:20220611T100000
GEO:50.9292035\,11.5825763 GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena" LOCATION:Krautgasse 26, 07743 Jena
URL;VALUE="HTTPS://kraut.space/kinderbasteln" URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:kinderbasteln
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:basteln@kraut.space ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:basteln@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53 RRULE:WKST=MO;FREQ=WEEKLY;BYDAY=2SA,4SA
END:VEVENT END:VEVENT
END:VCALENDAR END:VCALENDAR

View file

@ -1,344 +1,192 @@
<?php <?php
/** /**
* Datei: getEvents.php * file: getEvents.php
* Autor: bernd@nr18.space * date: 20.11.2022
* Letze Änderung: 08.07.2020 * user: bernd@nr18.space
* Kurzbeschreibung:
* Enthält Funktionen zum Parsen und Ausgeben einer iCalendar Kalenderdatei.
* Die Bibliothek zum Parsen des iCalendarfiles stammt von ZContent.
* Der Quelltext liegt auf https://github.com/zcontent/icalendar. Da sie
* auf calendar.org verlinkt war, dachte ich eigentlich, daß sie gut wäre.
*/ */
require_once("../src/lib/zapcallib.php");
ini_set('log_errors', 1);
ini_set('error_log', '../log/events.log');
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING & ~E_DEPRECATED);
use Sabre\VObject;
include '/usr/share/php/Sabre/VObject/autoload.php';
define ("ICAL_FILE", "krautspace.ics");
function printEventList(): bool
{
/** /**
* Die Startfuktion für die Ausgabe der Termine als Liste in index.php. * Reads the content of the given ical file and creates with this string a
* Nach erfolgreicher initialisierung läuft die Funktion durch das Array * vcalendar object.
* der Events (ZCalNode´s vom Typ 'VEVENT') ruft für jedes Element erst *
* die Funktion zur Umwandlung in ein assoziatives Array und dann die * @return vCalendar object | null
* Ausgabefunktion auf. Gibt einen Boolean zurück.
*/ */
$events = initEvents(); function initCalendar(): ?object {
$helper = new ZDateHelper(); try {
date_default_timezone_set("UTC"); $data = file_get_contents(ICAL_FILE);
$vcalendar = VObject\Reader::read(
/** $data
* Startdatum für wiederkehrende Termine aktualisieren );
* return $vcalendar;
* @var ZCiCalNode $event } catch (Throwable $th) {
*/ error_log("Failed to read calendar file.");
foreach ($events as $event) error_log($th->getMessage(), 0);
{ return null;
/**
* @var ZCiCalDataNode $eventDTStart
*/
$eventDTStart = $event->data['DTSTART'];
/** @var string[] $eventDTStartValues */
$eventDTStartValues = $eventDTStart->value;
$event_start = $eventDTStartValues[0] ?? '';
$unix_start = $helper->fromiCaltoUnixDateTime($event_start);
$rrule = $event->data['RRULE']->value[0];
//todo rrule always set
if (EventIsPast($unix_start) === true AND isset ($rrule))
{
$new_unix = calculateNextStart($unix_start, $rrule);
$date = date('Ymd', $new_unix);
$time = date('His', $new_unix);
$connector = 'T';
$new_start = "{$date}{$connector}{$time}";
$event->data['DTSTART']->value[0] = $new_start;
}
} }
/**
* Eventliste nach Startdatum sortieren
*/
usort($events, 'compareEventStart');
/**
* Termine ausgeben
*/
foreach ($events as $event)
{
printListItem($event);
}
return true;
} }
function printListItem(ZCiCalNode $event): bool
/** /**
* Die Ausgabefunktion für die Ausgabe der Termine als Liste. Hier wird die * Grabs all VEVENTS from vCalendar object, append they to a list and
* Zeitangabe des iCal-Formates in Datum, Uhrzeit und Wochentag umgewandelt. * returns the list.
* Anschließend erfolgt die Ausgabe der einzelnen Teile. *
* @param vCalendar object
* @return list | null
*/ */
{ function grabEvents(object $vcalendar): ?array {
date_default_timezone_set("UTC"); $eventlist = [];
$helper = new ZDateHelper(); try {
foreach ($vcalendar->VEVENT as $event) {
$eventlist[] = $event;
}
} catch (Throwable $th) {
error_log("Failed to grab evens.");
error_log($th->getMessage(), 0);
return null;
}
return $eventlist;
}
/**
* Becomes an instance from recurrency rule iterator and an datetime object.
* Until the iterators date is in future, we call for the next date.
*
* @param iterator object
* @param datetime
* @return datetime | null
*/
function getNextDate(object $rriterator, DateTime $now): ?DateTime {
foreach ($rriterator as $item) {
if ($item > $now) {
return $item;
}
}
return null;
}
/**
* Main function to display the events.
*
* @param array
* @param object
*/
function printEvent(array $eventarray, object $date_helper) {
$start_datetime = $eventarray[0];
$event = $eventarray[1];
$day = toGerman($start_datetime->format("l"));
$start = $start_datetime->format("d.m.Y H:i");
$hyph = " - "; $hyph = " - ";
$uhr = " Uhr"; $uhr = " Uhr";
$komma = ", "; $komma = ", ";
$dateline = "{$day}{$komma}{$start}{$uhr}{$hyph}";
$event_start = $event->data['DTSTART']->value[0]; if ($event->URL != "") {
$event_url = lowerURL($event->data['URL']->parameter['value']); printHeadline($dateline, $event->SUMMARY, $event->URL);
$event_title = $event->data['SUMMARY']->value[0]; } else {
$event_location = trim($event->data['LOCATION']->value[0], '"'); printHeadline($dateline, $event->SUMMARY);
$event_descr = trim($event->data['DESCRIPTION']->value[0], '"'); }
if ($event->DESCRIPTION != "") {
$unix = $helper->fromiCaltoUnixDateTime($event_start); printDescription($event->DESCRIPTION);
$event_date = date('d.m.Y', $unix); }
$event_time = date('H:i', $unix); if ($event->LOCATION != "") {
$event_day = toGerman(date('l', $unix)); printLocation($event->LOCATION);
$dateline = "{$event_day}{$komma}{$event_date}{$hyph}{$event_time}{$uhr}"; }
printBottomline();
displayHeadline($dateline, $event_title);
displayLocation($event_location);
displayDescription($event_descr);
displayURL($event_url);
return true;
}
function displayHeadline(string $dateline, $event_title): bool
{
echo "\n<section class='termin'>\n";
echo "<p class='headline'>" . $dateline . ": " . $event_title . "</p>\n";
return true;
}
function displayLocation(string $location): bool
{
echo "<ul class='events'>\n";
echo "<li>$location</li>\n";
return true;
}
function displayDescription(string $description): bool
{
echo "<li>$description</li>\n";
return true;
}
function displayURL(string $url): bool
{
$stripped = trim($url, '"');
echo "<li><a href=" . $url . ">" . $stripped . "</a></li>\n";
echo "</ul>\n";
echo "</section>\n";
return true;
} }
/** /**
* Die Startfuktion für die Ausgabe der Termine als Tabelle in termine.php * Outputs the opening tags for section and ul, the date and time, and
* summary. ifi a url is given, the summary is a link to the corresponding
* wiki page.
*
* @param string
* @param string
*/ */
function printHeadline(string $dateline, string $summary, string $url=null) {
function printEventTable(): bool echo("\n<section class='termin'>");
{ if ($url == null) {
$events = initEvents(); echo("\n<p class='headline'>$dateline$summary</p>");
printTableHead(); } else {
foreach ($events as $event) echo("\n<p class='headline'>$dateline<a href='$url'>$summary</a></p>");
{
$event_array = getEventArray($event);
printTableItem($event_array);
} }
echo "\t</tbody>\n"; echo("\n<ul class='events'>");
echo "</table>\n";
return true;
}
function printTableHead()
{
echo "\n\r<table class='w3-table w3-bordered'>\n";
echo "\t<thead>\n";
echo "\t<tr>\n";
echo "\t\t<th>Datum</th>\n";
echo "\t\t<th>Wochentag</th>\n";
echo "\t\t<th>Zeit</th>\n";
echo "\t\t<th>Ort</th>\n";
echo "\t\t<th>Titel</th>\n";
echo "\t\t<th>Beschreibung</th>\n";
echo "\t</tr>\n";
echo "\t</thead>\n";
echo "\t<tbody>\n";
}
function printTableItem($event_array): bool
{
date_default_timezone_set("UTC");
$time = $event_array['DTSTART'];
$helper = new ZDateHelper();
$unix = $helper->fromiCaltoUnixDateTime($time);
$event_date = date('d.m.Y', $unix);
$event_time = date('H:i', $unix);
$event_day = toGerman(date('l', $unix));
$event_uid = $event_array['UID'];
$event_url = lowerURL($event_array['URL']);
$event_title = trim($event_array['SUMMARY'], '"');
$event_descr = trim($event_array['DESCRIPTION'], '"');
$event_location = trim($event_array['LOCATION'], '"');
echo "\t<tr id='" . $event_uid . "'>\n";
echo "\t\t<td>" . $event_date . "</td>\n";
echo "\t\t<td>" . $event_day . "</td>\n";
echo "\t\t<td>" . $event_time . " Uhr</td>\n";
echo "\t\t<td>" . $event_location . "</td>\n";
echo "\t\t<td>" . $event_title . "</td>\n";
echo "\t\t<td>" . $event_descr;
printURL($event_url);
echo "\t</tr>\n";
return true;
}
function printURL(string $url): bool
{
$stripped = trim($url, '"');
if ($url != '')
{
echo "</br><a class='event' href=" . $url . ">" . $stripped . "</a></td>\n";
}
else
{
echo "</td>\n";
}
return true;
} }
/** /**
* Funktionen, die von beiden Ausgaben benutzt werden. * Outputs the events description.
*
* @param string
*/ */
function printDescription(string $description) {
/** echo("\n<li>$description</li>");
* @return ZCiCalNode[]|null
*/
function initEvents(): ?array
/**
* Allgemeingültige Funktion zur Initialisierung. Enthält die Schritte, die
* von beiden Ausgaben gleichermaßen gebraucht werden.
* - Erstellen des iCalendar Objekts (initCalendar).
* - Schaut, ob der Kalender überhaupt Events enthält (printEventCount).
* - Sammel alle Events in einer Liste (grabEvents).
* Gibt zweidimmensionales assoziatives Array oder Null zurück.
*/
{
$iCalObj = initCalendar();
if (!isset ($iCalObj))
{
printError("Fehler beim Initialisieren des Kalenders");
return null;
}
$count = printEventCount($iCalObj);
if ($count == 0 or $count == false)
{
return null;
}
$events = grabEvents($iCalObj);
return $events;
} }
function initCalendar(): ?ZCiCal
/** /**
* Erstellt das Kalenderobjekt vom Typ ZCiCal. * Outputs the events location.
* Gibt das Kalenderobjekt oder Null zurück. *
* @param string
*/ */
{ function printLocation(string $location) {
$iCalFile = '../public/krautspace.ics'; $location = makeLinks($location);
$iCalString = file_get_contents($iCalFile); echo("\n<li>$location</li>");
if ($iCalString == false)
{
printError("Kann Kalenderdatei nicht lesen");
return null;
}
$iCalObj = new ZCiCal($iCalString);
return $iCalObj;
} }
function printEventCount(ZCiCal $iCalObj): ?int
/** /**
* Gibt die Anzahl der Events zurück, die das übergebene * Outputs the closing tags for ul and section.
* Kalenderobjekt enthält. Im Fehlerfall wird Null zurück
* gegeben.
*/ */
{ function printBottomline() {
$eventCount = $iCalObj->countEvents(); echo("\n</ul>");
if (!isset ($eventCount)) echo("\n</section>\n");
{
printError("Fehler beim Parsen des Kalenders");
return null;
}
// echo "<p>$eventCount anstehende Events</p>";
return $eventCount;
} }
function grabEvents(ZCiCal $iCalObj): ?array
{
/** /**
* Läuft durch das iCalendar objekt und sammelt alle Nodes vom Typ * Helper function to sort the events chronologically. Compares the first
* 'VEVENT' ein. Gibt ein Array mit Objekten vom Typ 'ZCiCalNode' zurück. * entry from the event array (DateTime object).
* Im Fehlerfall wird Null zurück gegeben. *
* @param array
* @param array
* @return integer
*/ */
$events = []; function compareEventStart(array $event_a, array $event_b): int {
if (isset ($iCalObj->tree->child)) // echo("Compare " . $event_a[0] . " and " . $event_b[0] . "\n");
{ $a = $event_a[0];
foreach ($iCalObj->tree->child as $node) $b = $event_b[0];
{ return $a <=> $b;
if ($node->getName() == "VEVENT")
{
$events[] = $node;
}
}
}
else
{
printError("Cant find nodes");
return null;
}
return $events;
} }
function getEventArray(ZCiCalNode $node): array
{
/** /**
* Bekommt eine Event Node vom Typ 'ZiCalNode' übergeben und extrahiert * Becomes the description string and makes urls contained in this string
* daraus die gewünschten Elemente. Bildet daraus ein zweidimmensionales * clickable. If anything goes wrong it returns the origin string.
* assoziatives Array. Gibt dieses Array zurück. *
* Wird derzeit nur von der tabellarischen Ausgabe referenziert, welche * @param string
+ momentan nicht genutzt wird. * @return string
*/ */
/** function makeLinks(string $description) {
* @var ZCiCalNode $node try {
* @var ZCiCalDataNode $event $reg_pattern = "/(((http|https)\:\/\/)|(www\.))[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,5}(\:[a-zA-Z0-9]+)?(\/\S*)?/";
*/ return $new = preg_replace($reg_pattern, '<a href="$0" target="_blank" rel="noopener noreferrer">$0</a>', $description);
$event = $node->data; } catch (Throwable $th) {
$event_array = []; return $description;
$keys = array('DTSTART', 'SUMMARY', 'DESCRIPTION', 'URL', 'LOCATION');
foreach ($keys as $key)
{
$event_array[$key] = $event[$key]->value[0];
if ($key === 'DTSTART')
{
if (isset ($event[$key]->parameter['tzid']))
{
$event_array['TZ'] = $event[$key]->parameter['tzid'];
}
}
else if ($key === 'URL')
{
$event_array[$key] = $event[$key]->parameter['value'];
}
} }
return $event_array;
} }
function printError($errMsg) /**
{ * Translates the english weekday names to german.
echo "\n\r<p>$errMsg</p>\n\r"; *
return true; * @param string
} * @return string | null
*/
function toGerman(string $day): string function toGerman(string $day): ?string
{ {
switch ($day) switch ($day)
{ {
@ -357,131 +205,91 @@ function toGerman(string $day): string
case 'Sunday': case 'Sunday':
return 'Sonntag'; return 'Sonntag';
default: default:
return '?'; return null;
} }
} }
function lowerURL(string $url): string
{
$old = array('HTTPS', 'HTTP', 'FTP', 'WWW', 'SSH');
$new = array('https', 'http', 'ftp', 'www', 'ssh');
$new_url = str_replace($old, $new, $url);
return $new_url;
}
function calculateNextStart(int $unix_start, string $rrule): int ///////////////////////////////////////////////////////////////////////////
/** /// start des programmes
* Berechnet für wiederkehrende Termine den aktuell nächsten Termin. ///////////////////////////////////////////////////////////////////////////
* dabei werden zur Zeit nur der der Zeitraum zwischen zwei Terminen
* und eine mögliche Anzahl der Termine berücksichtigt. Gibt den neuen
* Termin als Unix-Zeitstempel zurück.
*/
{
$counter = 0;
$rule_array = getRuleArray($rrule);
if (isset ($rule_array['COUNT']))
{
$count = $rule_array['COUNT'];
}
if (isset ($rule_array['FREQ']))
{
$frequency = $rule_array['FREQ'];
}
if (isset ($rule_array['INTERVAL']))
{
$interval = $rule_array['INTERVAL'];
}
if (isset ($rule_array['UNTIL']))
{
//todo implement
$until_string = $rule_array['UNTIL'];
}
$freq_offset = getOffset($frequency);
if (isset ($interval))
{
$offset = $freq_offset * $interval;
}
else
{
$offset = $freq_offset;
}
while ($unix_start <= time())
{
if (isset ($count))
{
if ($counter >= $count)
{
break;
}
}
$unix_start = $unix_start + $offset;
$counter = $counter + 1;
}
return $unix_start;
}
function getOffset(string $frequence): int
{
switch ($frequence)
{
case 'HOURLY':
return 3600;
case 'DAILY':
return 86400;
case 'WEEKLY':
return 604800;
default:
return 1;
}
}
function getRuleArray(string $rrule): array
/**
* Zerlegt den String einer RRULE und gibt die einzelnen Elemente als
* assoziatives Array zurück.
*/
{
$rule_array = [];
$rule_strings = explode(';', $rrule);
foreach ($rule_strings as $r_string)
{
$rule = explode('=', $r_string);
$rule_array[$rule[0]] = $rule[1];
}
return $rule_array;
}
function EventIsPast(int $unix_start): bool
/**
* Prüft, ob die übergebenen Unixzeit älter als der aktuelle Tag ist. Gibt
* Wahr oder Falsch zurück.
*/
{
$event_date = date('d.m.Y', $unix_start);
$day_end = strtotime($event_date) + 86400;
$actual_date = time();
if ($day_end < $actual_date)
{
return true;
}
return false;
}
/** /**
* Bekommt zwei Eventnodes übergeben und vergleicht deren Startdatum. Die * The main function.
* Funktion wird intern von ausort() benutzt, um das Array mit den Eventnodes
* nach Datum zu sortieren.
* *
* @param ZCiCalNode $event_a
* @param ZCiCalNode $event_b
* @return int
*/ */
function compareEventStart(ZCiCalNode $event_a, ZCiCalNode $event_b): int function printEventList(): bool {
{ error_log("getEvents called");
$a = $event_a->data['DTSTART']->value[0]; date_default_timezone_set("Europe/Berlin");
$b = $event_b->data['DTSTART']->value[0]; $today_datetime = new DateTime();
return $a <=> $b; date_time_set($today_datetime, 0, 0, 0, 0);
$date_helper = new VObject\DateTimeParser();
$eventlist = [];
$next_events = [];
// einlesen der kalenderdatei
$vcalendar = initCalendar();
if ($vcalendar == null) {
error_log("getEvents unsuccessful terminated");
return false;
}
// die events aus dem kalender herausziehen
$eventlist = grabEvents($vcalendar);
if ($eventlist == null) {
error_log("gabEvent returns null");
return false;
}
elseif (count($eventlist) == 0) {
echo("\n<p>Keine Termine gefunden</p>\n");
return false;
}
// durch die liste der events laufen. wir holen uns den starttermin und
// wandeln ihn in ein datetime objekt um. liegt das in der vergangenheit
// und der termin hat eine rrule, holen wir uns einen iterator über die
// rrule (dazu brauchen wir die uid) und versuche den nächsten gültigen
// termin zu bekommen. gibt es einen gültigen termin, wird das event mit
// dem neuen starttermin an die liste der relevanten termine angehängt.
// ist der starttermin von anfang an in der zukunft, dann wird er
// natürlich auch angehängt.
foreach ($eventlist as $event) {
$next_event = [];
$e_uid = $event->UID;
$e_start = $event->DTSTART;
$e_summary = $event->SUMMARY;
$e_description = $event->DESCRIPTION;
$e_location = $event->LOCATION;
$e_url = $event->URL;
$start_datetime = $date_helper->parseDateTime($e_start);
if ($start_datetime < $today_datetime) {
if (isset($event->RRULE)) {
$rriter = new VObject\RecurrenceIterator($vcalendar, $e_uid);
$start_datetime = getNextDate($rriter, $today_datetime);
if ($start_datetime == null) {
continue;
} else {
array_push($next_events, array($start_datetime, $event));
}
}
} else {
array_push($next_events, array($start_datetime, $event));
}
}
// liste der anstehenden events nach dem begin sortieren
usort($next_events, "compareEventStart");
// die sortierte liste ausgeben
foreach ($next_events as $event) {
printEvent($event, $date_helper);
}
error_log("getEvents successful terminated");
return true;
} }

View file

@ -1,127 +0,0 @@
# Zap Calendar iCalendar Library
(https://github.com/zcontent/icalendar)
The Zap Calendar iCalendar Library is a PHP library for supporting the iCalendar (RFC 5545) standard.
This PHP library is for reading and writing iCalendar formatted feeds and
files. Features of the library include:
- Read AND write support for iCalendar files
- Object based creation and manipulation of iCalendar files
- Supports expansion of RRULE to a list of repeating dates
- Supports adding timezone info to iCalendar file
All iCalendar data is stored in a PHP object tree.
This allows any property to be added to the iCalendar feed without
requiring specialized library function calls.
With power comes responsibility. Missing or invalid properties can cause
the resulting iCalendar file to be invalid. Visit [iCalendar.org](http://icalendar.org) to view valid
properties and test your feed using the site's [iCalendar validator tool](http://icalendar.org/validator.html).
Library API documentation can be found at http://icalendar.org/zapcallibdocs
See the examples folder for programs that read and write iCalendar
files. At its simpliest, you need to include the library at the top of your program:
```php
require_once($path_to_library . "/zapcallib.php");
```
Create an ical object using the ZCiCal object:
```php
$icalobj = new ZCiCal();
```
Add an event object:
```php
$eventobj = new ZCiCalNode("VEVENT", $icalobj->curnode);
```
Add a start and end date to the event:
```php
// add start date
$eventobj->addNode(new ZCiCalDataNode("DTSTART:" . ZCiCal::fromSqlDateTime("2020-01-01 12:00:00")));
// add end date
$eventobj->addNode(new ZCiCalDataNode("DTEND:" . ZCiCal::fromSqlDateTime("2020-01-01 13:00:00")));
```
Write the object in iCalendar format using the export() function call:
```php
echo $icalobj->export();
```
This example will not validate since it is missing some required elements.
Look at the simpleevent.php example for the minimum # of elements
needed for a validated iCalendar file.
To create a multi-event iCalendar file, simply create multiple event objects. For example:
```php
$icalobj = new ZCiCal();
$eventobj1 = new ZCiCalNode("VEVENT", $icalobj->curnode);
$eventobj1->addNode(new ZCiCalDataNode("SUMMARY:Event 1"));
...
$eventobj2 = new ZCiCalNode("VEVENT", $icalobj->curnode);
$eventobj2->addNode(new ZCiCalDataNode("SUMMARY:Event 2"));
...
```
To read an existing iCalendar file/feed, create the ZCiCal object with a string representing the contents of the iCalendar file:
```php
$icalobj = new ZCiCal($icalstring);
```
Large iCalendar files can be read in chunks to reduce the amount of memory needed to hold the iCalendar feed in memory. This example reads 500 events at a time:
```php
$icalobj = null;
$eventcount = 0;
$maxevents = 500;
do
{
$icalobj = newZCiCal($icalstring, $maxevents, $eventcount);
...
$eventcount +=$maxevents;
}
while($icalobj->countEvents() >= $eventcount);
```
You can read the events from an imported (or created) iCalendar object in this manner:
```php
foreach($icalobj->tree->child as $node)
{
if($node->getName() == "VEVENT")
{
foreach($node->data as $key => $value)
{
if($key == "SUMMARY")
{
echo "event title: " . $value->getValues() . "\n";
}
}
}
}
```
## Known Limitations
- Since the library utilizes objects to read and write iCalendar data, the
size of the iCalendar data is limited to the amount of available memory on the machine.
The ZCiCal() object supports reading a range of events to minimize memory
space.
- The library ignores timezone info when importing files, instead utilizing PHP's timezone
library for calculations (timezones are supported when exporting files).
Imported timezones need to be aliased to a [PHP supported timezone](http://php.net/manual/en/timezones.php).
- At this time, the library does not support the "BYSETPOS" option in RRULE items.
- At this time, the maximum date supported is 2036 to avoid date math issues
with 32 bit systems.
- Repeating events are limited to a maximum of 5,000 dates to avoid memory or infinite loop issues

View file

@ -1,568 +0,0 @@
<?php
/**
* date.php - date helper class
*
* @package ZapCalLib
* @author Dan Cogliano <http://zcontent.net>
* @copyright Copyright (C) 2006 - 2017 by Dan Cogliano
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
* @link http://icalendar.org/php-library.html
*/
// No direct access
defined('_ZAPCAL') or die( 'Restricted access' );
/**
* Zap Calendar Date Helper Class
*
* Helper class for various date functions
*/
class ZDateHelper {
/**
* Find the number of days in a month
*
* @param int $month Month is between 1 and 12 inclusive
*
* @param int $year is between 1 and 32767 inclusive
*
* @return int
*/
static function DayInMonth($month, $year) {
$daysInMonth = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
if ($month != 2) return $daysInMonth[$month - 1];
return (checkdate($month, 29, $year)) ? 29 : 28;
}
/**
* Is given date today?
*
* @param int $date date in Unix timestamp format
*
* @param int $tzid PHP recognized timezone (default is UTC)
*
* @return bool
*/
static function isToday($date, $tzid = "UTC") {
$dtz = new DateTimeZone($tzid);
$dt = new DateTime("now", $dtz);
$now = time() + $dtz->getOffset($dt);
return gmdate('Y-m-d', $date) == gmdate('Y-m-d', $now);
}
/**
* Is given date before today?
*
* @param int $date date in Unix timestamp format
*
* @param int $tzid PHP recognized timezone (default is UTC)
*
* @return bool
*/
static function isBeforeToday($date, $tzid = "UTC"){
$dtz = new DateTimeZone($tzid);
$dt = new DateTime("now", $dtz);
$now = time() + $dtz->getOffset($dt);
return mktime(0,0,0,date('m',$now),date('d',$now),date('Y',$now)) >
mktime(0,0,0,date('m',$date),date('d',$date),date('Y',$now));
}
/**
* Is given date after today?
*
* @param int $date date in Unix timestamp format
*
* @param int $tzid PHP recognized timezone (default is UTC)
*
* @return bool
*/
static function isAfterToday($date, $tzid = "UTC"){
$dtz = new DateTimeZone($tzid);
$dt = new DateTime("now", $dtz);
$now = time() + $dtz->getOffset($dt);
return mktime(0,0,0,date('m',$now),date('d',$now),date('Y',$now)) <
mktime(0,0,0,date('m',$date),date('d',$date),date('Y',$now));
}
/**
* Is given date tomorrow?
*
* @param int $date date in Unix timestamp format
*
* @param int $tzid PHP recognized timezone (default is UTC)
*
* @return bool
*/
static function isTomorrow($date, $tzid = "UTC") {
$dtz = new DateTimeZone($tzid);
$dt = new DateTime("now", $dtz);
$now = time() + $dtz->getOffset($dt);
return gmdate('Y-m-d', $date) == gmdate('Y-m-d', $now + 60 * 60 * 24);
}
/**
* Is given date in the future?
*
* This routine differs from isAfterToday() in that isFuture() will
* return true for date-time values later in the same day.
*
* @param int $date date in Unix timestamp format
*
* @param int $tzid PHP recognized timezone (default is UTC)
*
* @return bool
*/
static function isFuture($date, $tzid = "UTC"){
$dtz = new DateTimeZone($tzid);
$dt = new DateTime("now", $dtz);
$now = time() + $dtz->getOffset($dt);
return $date > $now;
}
/**
* Is given date in the past?
*
* This routine differs from isBeforeToday() in that isPast() will
* return true for date-time values earlier in the same day.
*
* @param int $date date in Unix timestamp format
*
* @param int $tzid PHP recognized timezone (default is UTC)
*
* @return bool
*/
static function isPast($date, $tzid = "UTC") {
$dtz = new DateTimeZone($tzid);
$dt = new DateTime("now", $dtz);
$now = time() + $dtz->getOffset($dt);
return $date < $now;
}
/**
* Return current Unix timestamp in local timezone
*
* @param string $tzid PHP recognized timezone
*
* @return int
*/
static function now($tzid = "UTC"){
$dtz = new DateTimeZone($tzid);
$dt = new DateTime("now", $dtz);
$now = time() + $dtz->getOffset($dt);
return $now;
}
/**
* Is given date fall on a weekend?
*
* @param int $date Unix timestamp
*
* @return bool
*/
static function isWeekend($date) {
$dow = gmdate('w',$date);
return $dow == 0 || $dow == 6;
}
/**
* Format Unix timestamp to SQL date-time
*
* @param int $t Unix timestamp
*
* @return string
*/
static function toSqlDateTime($t = 0)
{
date_default_timezone_set('GMT');
if($t == 0)
return gmdate('Y-m-d H:i:s',self::now());
return gmdate('Y-m-d H:i:s', $t);
}
/**
* Format Unix timestamp to SQL date
*
* @param int $t Unix timestamp
*
* @return string
*/
static function toSqlDate($t = 0)
{
date_default_timezone_set('GMT');
if($t == 0)
return gmdate('Y-m-d',self::now());
return gmdate('Y-m-d', $t);
}
/**
* Format iCal date-time string to Unix timestamp
*
* @param string $datetime in iCal time format ( YYYYMMDD or YYYYMMDDTHHMMSS or YYYYMMDDTHHMMSSZ )
*
* @return int Unix timestamp
*/
static function fromiCaltoUnixDateTime($datetime) {
// first check format
$formats = array();
$formats[] = "/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]/";
$formats[] = "/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]/";
$formats[] = "/[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]T[0-9][0-9][0-9][0-9][0-9][0-9]Z/";
$ok = false;
foreach($formats as $format){
if(preg_match($format,$datetime)){
$ok = true;
break;
}
}
if(!$ok)
return null;
$year = substr($datetime,0,4);
$month = substr($datetime,4,2);
$day = substr($datetime,6,2);
$hour = 0;
$minute = 0;
$second = 0;
if(strlen($datetime) > 8 && $datetime[8] == "T") {
$hour = substr($datetime,9,2);
$minute = substr($datetime,11,2);
$second = substr($datetime,13,2);
}
return gmmktime($hour, $minute, $second, $month, $day, $year);
}
/**
* Format Unix timestamp to iCal date-time string
*
* @param int $datetime Unix timestamp
*
* @return string
*/
static function fromUnixDateTimetoiCal($datetime){
date_default_timezone_set('GMT');
return gmdate("Ymd\THis",$datetime);
}
/**
* Convert iCal duration string to # of seconds
*
* @param string $duration iCal duration string
*
* return int
*/
static function iCalDurationtoSeconds($duration) {
$secs = 0;
if($duration[0] == "P") {
$duration = str_replace(array("H","M","S","T","D","W","P"),array("H,","M,","S,","","D,","W,",""),$duration);
$dur2 = explode(",",$duration);
foreach($dur2 as $dur){
$val=intval($dur);
if(strlen($dur) > 0){
switch($dur{strlen($dur) - 1}) {
case "H":
$secs += 60*60 * $val;
break;
case "M":
$secs += 60 * $val;
break;
case "S":
$secs += $val;
break;
case "D":
$secs += 60*60*24 * $val;
break;
case "W":
$secs += 60*60*24*7 * $val;
break;
}
}
}
}
return $secs;
}
/**
* Check if day falls within date range
*
* @param int $daystart start of day in Unix timestamp format
*
* @param int $begin Unix timestamp of starting date range
*
* @param int $end Unix timestamp of end date range
*
* @return bool
*/
static function inDay($daystart, $begin, $end)
{
//$dayend = $daystart + 60*60*24 - 60;
// add 1 day to determine end of day
// don't use 24 hours, since twice a year DST Sundays are 23 hours and 25 hours in length
// adding 1 day takes this into account
$dayend = self::addDate($daystart, 0,0,0,0,1,0);
$end = max($begin, $end); // $end can't be less than $begin
$inday =
($daystart <= $begin && $begin < $dayend)
||($daystart < $end && $end < $dayend)
||($begin <= $daystart && $end > $dayend)
;
return $inday;
}
/**
* Convert SQL date or date-time to Unix timestamp
*
* @param string $datetime SQL date or date-time
*
* @return int Unix date-time timestamp
*/
static function toUnixDate($datetime)
{
$year = substr($datetime,0,4);
$month = substr($datetime,5,2);
$day = substr($datetime,8,2);
return mktime(0, 0, 0, $month, $day, $year);
}
/**
* Convert SQL date or date-time to Unix date timestamp
*
* @param string $datetime SQL date or date-time
*
* @return int Unix timestamp
*/
static function toUnixDateTime($datetime)
{
// convert to absolute dates if neccessary
$datetime = self::getAbsDate($datetime);
$year = substr($datetime,0,4);
$month = substr($datetime,5,2);
$day = substr($datetime,8,2);
$hour = 0;
$minute = 0;
$second = 0;
if(strlen($datetime) > 10) {
$hour = substr($datetime,11,2);
$minute = substr($datetime,14,2);
$second = substr($datetime,17,2);
}
return gmmktime($hour, $minute, $second, $month, $day, $year);
}
/**
* Date math: add or substract from current date to get a new date
*
* @param int $date date to add or subtract from
*
* @param int $hour add or subtract hours from date
*
* @param int $min add or subtract minutes from date
*
* @param int $sec add or subtract seconds from date
*
* @param int $month add or subtract months from date
*
* @param int $day add or subtract days from date
*
* @param int $year add or subtract years from date
*
* @param string $tzid PHP recognized timezone (default is UTC)
*/
static function addDate($date, $hour, $min, $sec, $month, $day, $year, $tzid = "UTC") {
date_default_timezone_set($tzid);
$sqldate = self::toSQLDateTime($date);
$tdate = array();
$tdate["year"] = substr($sqldate,0,4);
$tdate["mon"] = substr($sqldate,5,2);
$tdate["mday"] = substr($sqldate,8,2);
$tdate["hours"] = substr($sqldate,11,2);
$tdate["minutes"] = substr($sqldate,14,2);
$tdate["seconds"] = substr($sqldate,17,2);
$newdate=mktime($tdate["hours"] + $hour, $tdate["minutes"] + $min, $tdate["seconds"] + $sec, $tdate["mon"] + $month, $tdate["mday"] + $day, $tdate["year"] + $year);
date_default_timezone_set("UTC");
//echo self::toSQLDateTime($date) . " => " . self::toSQLDateTime($newdate) . " ($hour:$min:$sec $month/$day/$year)<br/>\n";
return $newdate;
}
/**
* Date math: get date from week and day in specifiec month
*
* This routine finds actual dates for the second Tuesday of the month, last Friday of the month, etc.
* For second Tuesday, use $week = 1, $wday = 2
* for last Friday, use $week = -1, $wday = 5
*
* @param int $date Unix timestamp
*
* @param int $week week number, 0 is first week, -1 is last
*
* @param int $wday day of week, 0 is Sunday, 6 is Saturday
*
* @param string $tzid PHP supported timezone
*
* @return int Unix timestamp
*/
static function getDateFromDay($date, $week, $wday,$tzid="UTC") {
//echo "getDateFromDay(" . self::toSqlDateTime($date) . ",$week,$wday)<br/>\n";
// determine first day in month
$tdate = getdate($date);
$monthbegin = gmmktime(0,0,0, $tdate["mon"],1,$tdate["year"]);
$monthend = self::addDate($monthbegin, 0,0,0,1,-1,0,$tzid); // add 1 month and subtract 1 day
$day = self::addDate($date,0,0,0,0,1 - $tdate["mday"],0,$tzid);
$month = array(array());
while($day <= $monthend) {
$tdate=getdate($day);
$month[$tdate["wday"]][]=$day;
//echo self::toSQLDateTime($day) . "<br/>\n";
$day = self::addDate($day, 0,0,0,0,1,0,$tzid); // add 1 day
}
$dayinmonth=0;
if($week >= 0)
$dayinmonth = $month[$wday][$week];
else
$dayinmonth = $month[$wday][count($month[$wday]) - 1];
//echo "return " . self::toSQLDateTime($dayinmonth);
//exit;
return $dayinmonth;
}
/**
* Convert UTC date-time to local date-time
*
* @param string $sqldate SQL date-time string
*
* @param string $tzid PHP recognized timezone (default is "UTC")
*
* @return string SQL date-time string
*/
static function toLocalDateTime($sqldate, $tzid = "UTC" ){
try
{
$timezone = new DateTimeZone($tzid);
}
catch(Exception $e)
{
// bad time zone specified
return $sqldate;
}
$udate = self::toUnixDateTime($sqldate);
$daydatetime = new DateTime("@" . $udate);
$tzoffset = $timezone->getOffset($daydatetime);
return self::toSqlDateTime($udate + $tzoffset);
}
/**
* Convert local date-time to UTC date-time
*
* @param string $sqldate SQL date-time string
*
* @param string $tzid PHP recognized timezone (default is "UTC")
*
* @return string SQL date-time string
*/
static function toUTCDateTime($sqldate, $tzid = "UTC" ){
date_default_timezone_set("UTC");
try
{
$date = new DateTime($sqldate, $tzid);
}
catch(Exception $e)
{
// bad time zone specified
return $sqldate;
}
$offset = $date->getOffsetFromGMT();
if($offset >= 0)
$date->sub(new DateInterval("PT".$offset."S"));
else
$date->add(new DateInterval("PT".abs($offset)."S"));
return $date->toSql(true);
}
/**
* Convert from a relative date to an absolute date
*
* Examples of relative dates are "-2y" for 2 years ago, "18m"
* for 18 months after today. Relative date uses "y", "m" and "d" for
* year, month and day. Relative date can be combined into comma
* separated list, i.e., "-1y,-1d" for 1 year and 1 day ago.
*
* @param string $date relative date string (i.e. "1y" for 1 year from today)
*
* @param string $rdate reference date, or blank for current date (in SQL date-time format)
*
* @return string in SQL date-time format
*/
static function getAbsDate($date,$rdate = ""){
if(str_replace(array("y","m","d","h","n"),"",strtolower($date)) != strtolower($date)){
date_default_timezone_set("UTC");
if($rdate == "")
$udate = time();
else
$udate = self::toUnixDateTime($rdate);
$values=explode(",",strtolower($date));
$y = 0;
$m = 0;
$d = 0;
$h = 0;
$n = 0;
foreach($values as $value){
$rtype = substr($value,strlen($value)-1);
$rvalue = intval(substr($value,0,strlen($value) - 1));
switch($rtype){
case 'y':
$y = $rvalue;
break;
case 'm':
$m = $rvalue;
break;
case 'd':
$d = $rvalue;
break;
case 'h':
$h = $rvalue;
break;
case 'n':
$n = $rvalue;
break;
}
// for "-" values, move to start of day , otherwise, move to end of day
if($rvalue[0] == '-')
$udate = mktime(0,0,0,date('m',$udate),date('d',$udate),date('Y',$udate));
else
$udate = mktime(0,-1,0,date('m',$udate),date('d',$udate)+1,date('Y',$udate));
$udate = self::addDate($udate,$h,$n,0,$m,$d,$y);
}
$date = self::toSqlDateTime($udate);
}
return $date;
}
/**
* Format Unix timestamp to iCal date-time format
*
* @param int $datetime Unix timestamp
*
* @return string iCal date-time string
*/
static function toiCalDateTime($datetime = null){
date_default_timezone_set('UTC');
if($datetime == null)
$datetime = time();
return gmdate("Ymd\THis",$datetime);
}
/**
* Format Unix timestamp to iCal date format
*
* @param int $datetime Unix timestamp
*
* @return string iCal date-time string
*/
static function toiCalDate($datetime = null){
date_default_timezone_set('UTC');
if($datetime == null)
$datetime = time();
return gmdate("Ymd",$datetime);
}
}

View file

@ -1,32 +0,0 @@
<?php
/**
* framework.php - framework file
*
* @package ZapCalLib
* @author Dan Cogliano <http://zcontent.net>
* @copyright Copyright (C) 2006 - 2017 by Dan Cogliano
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
* @link http://icalendar.org/php-library.html
*/
// No direct access
defined('_ZAPCAL') or die( 'Restricted access' );
/**
* set MAXYEAR to 2036 for 32 bit systems, can be higher for 64 bit systems
*
* @var integer
*/
define('_ZAPCAL_MAXYEAR', 2036);
/**
* set MAXREVENTS to maximum # of repeating events
*
* @var integer
*/
define('_ZAPCAL_MAXREVENTS', 5000);
require_once(_ZAPCAL_BASE . '/includes/date.php');
require_once(_ZAPCAL_BASE . '/includes/recurringdate.php');
require_once(_ZAPCAL_BASE . '/includes/ical.php');
require_once(_ZAPCAL_BASE . '/includes/timezone.php');

View file

@ -1,986 +0,0 @@
<?php
/**
* ical.php create iCalendar data structure
*
* @package ZapCalLib
* @author Dan Cogliano <http://zcontent.net>
* @copyright Copyright (C) 2006 - 2017 by Dan Cogliano
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
* @link http://icalendar.org/php-library.html
*/
// No direct access
defined('_ZAPCAL') or die( 'Restricted access' );
/**
* Object for storing an unfolded iCalendar line
*
* The ZCiCalDataNode class contains data from an unfolded iCalendar line
*
*/
class ZCiCalDataNode {
/**
* The name of the node
*
* @var string
*/
var $name = "";
/**
* Node parameters (before the colon ":")
*
* @var array
*/
var $parameter=array();
/**
* Node values (after the colon ":")
*
* @var array
*/
var $value=array();
/**
* Create an object from an unfolded iCalendar line
*
* @param string $line An unfolded iCalendar line
*
* @return void
*
*/
function __construct( $line ) {
//echo "ZCiCalDataNode($line)<br/>\n";
//separate line into parameters and value
// look for colon separating name or parameter and value
// first change any escaped colons temporarily to make it easier
$tline = str_replace("\\:", "`~", $line);
// see if first colon is inside a quoted string
$i = 0;
$datafind = false;
$inquotes = false;
while(!$datafind && ($i < strlen($tline))) {
//echo "$i: " . $tline[$i] . ", ord() = " . ord($tline{$i}) . "<br>\n";
if(!$inquotes && $tline[$i] == ':')
$datafind=true;
else{
$i += 1;
if(substr($tline,$i,1) == '"')
$inquotes = !$inquotes;
}
}
if($datafind){
$value = str_replace("`~","\\:",substr($line,$i+1));
// fix escaped characters (don't see double quotes in spec but Apple apparently uses it in iCal)
$value = str_replace(array('\\N' , '\\n', '\\"' ), array("\n", "\n" , '"'), $value);
$tvalue = str_replace("\\,", "`~", $value);
//echo "value: " . $tvalue . "<br>\n";
$tvalue = explode(",",$tvalue);
$value = str_replace("`~","\\,",$tvalue);
$this->value = $value;
}
$parameter = trim(substr($line,0,$i));
$parameter = str_replace("\\;", "`~", $parameter);
$parameters = explode(";", $parameter);
$parameters = str_replace("`~", "\\;", $parameters);
$this->name = array_shift($parameters);
foreach($parameters as $parameter){
$pos = strpos($parameter,"=");
if($pos > 0){
$param = substr($parameter,0,$pos);
$paramvalue = substr($parameter,$pos+1);
$tvalue = str_replace("\\,", "`~", $paramvalue);
//$tvalue = explode(",",$tvalue);
$paramvalue = str_replace("`~","\\,",$tvalue);
$this->parameter[strtolower($param)] = $paramvalue;
//$this->paramvalue[] = $paramvalue;
}
}
}
/**
* getName()
*
* Return the name of the object
*
* @return string
*/
function getName(){
return $this->name;
}
/**
* Get $ith parameter from array
* @param int $i
*
* @return var
*/
function getParameter($i){
return $this->parameter[$i];
}
/**
* Get parameter array
*
* @return array
*/
function getParameters(){
return $this->parameter;
}
/**
* Get comma separated values
*
* @return string
*/
function getValues(){
return implode(",",$this->value);
}
}
/**
* Object for storing a list of unfolded iCalendar lines (ZCiCalDataNode objects)
*
* @property object $parentnode Parent of this node
*
* @property array $child Array of children for this node
*
* @property data $data Array of data for this node
*
* @property object $next Next sibling of this node
*
* @property object $prev Previous sibling of this node
*/
class ZCiCalNode {
/**
* The name of the node
*
* @var string
*/
var $name="";
/**
* The parent of this node
*
* @var object
*/
var $parentnode=null;
/**
* Array of children for this node
*
* @var array
*/
var $child= array();
/**
* Array of $data for this node
*
* @var array
*/
var $data= array();
/**
* Next sibling of this node
*
* @var object
*/
var $next=null;
/**
* Previous sibling of this node
*
* @var object
*/
var $prev=null;
/**
* Create ZCiCalNode
*
* @param string $_name Name of node
*
* @param object $_parent Parent node for this node
*
* @param bool $first Is this the first child for this parent?
*/
function __construct( $_name, & $_parent, $first = false) {
$this->name = $_name;
$this->parentnode = $_parent;
if($_parent != null){
if(count($this->parentnode->child) > 0) {
if($first)
{
$first = & $this->parentnode->child[0];
$first->prev = & $this;
$this->next = & $first;
}
else
{
$prev =& $this->parentnode->child[count($this->parentnode->child)-1];
$prev->next =& $this;
$this->prev =& $prev;
}
}
if($first)
{
array_unshift($this->parentnode->child, $this);
}
else
{
$this->parentnode->child[] =& $this;
}
}
/*
echo "creating " . $this->getName();
if($_parent != null)
echo " child of " . $_parent->getName() . "/" . count($this->parentnode->child);
echo "<br/>";
*/
}
/**
* Return the name of the object
*
* @return string
*/
function getName() {
return $this->name;
}
/**
* Add node to list
*
* @param object $node
*
*/
function addNode($node) {
if(array_key_exists($node->getName(), $this->data))
{
if(!is_array($this->data[$node->getName()]))
{
$this->data[$node->getName()] = array($this->data[$node->getName()]);
}
$this->data[$node->getName()][] = $node;
}
else
{
$this->data[$node->getName()] = $node;
}
}
/**
* Get Attribute
*
* @param int $i array id of attribute to get
*
* @return string
*/
function getAttrib($i) {
return $this->attrib[$i];
}
/**
* Set Attribute
*
* @param string $value value of attribute to set
*
*/
function setAttrib($value) {
$this->attrib[] = $value;
}
/**
* Get the parent object of this object
*
* @return object parent of this object
*/
function &getParent() {
return $this->parentnode;
}
/**
* Get the first child of this object
*
* @return object The first child
*/
function &getFirstChild(){
static $nullguard = null;
if(count($this->child) > 0) {
//echo "moving from " . $this->getName() . " to " . $this->child[0]->getName() . "<br/>";
return $this->child[0];
}
else
return $nullguard;
}
/**
* Print object tree in HTML for debugging purposes
*
* @param object $node select part of tree to print, or leave blank for full tree
*
* @param int $level Level of recursion (usually leave this blank)
*
* @return string - HTML formatted display of object tree
*/
function printTree(& $node=null, $level=1){
$level += 1;
$html = "";
if($node == null)
$node = $this->parentnode;
if($level > 5)
{
die("levels nested too deep<br/>\n");
//return;
}
for($i = 0 ; $i < $level; $i ++)
$html .= "+";
$html .= $node->getName() . "<br/>\n";
foreach ($node->child as $c){
$html .= $node->printTree($c,$level);
}
$level -= 1;
return $html;
}
/**
* export tree to icalendar format
*
* @param object $node Top level node to export
*
* @param int $level Level of recursion (usually leave this blank)
*
* @return string iCalendar formatted output
*/
function export(& $node=null, $level=0){
$txtstr = "";
if($node == null)
$node = $this;
if($level > 5)
{
//die("levels nested too deep<br/>\n");
throw new Exception("levels nested too deep");
}
$txtstr .= "BEGIN:" . $node->getName() . "\r\n";
if(property_exists($node,"data"))
foreach ($node->data as $d){
if(is_array($d))
{
foreach ($d as $c)
{
//$txtstr .= $node->export($c,$level + 1);
$p = "";
$params = @$c->getParameters();
if(count($params) > 0)
{
foreach($params as $key => $value){
$p .= ";" . strtoupper($key) . "=" . $value;
}
}
$txtstr .= $this->printDataLine($c, $p);
}
}
else
{
$p = "";
$params = @$d->getParameters();
if(count($params) > 0)
{
foreach($params as $key => $value){
$p .= ";" . strtoupper($key) . "=" . $value;
}
}
$txtstr .= $this->printDataLine($d, $p);
/*
$values = $d->getValues();
// don't think we need this, Sunbird does not like it in the EXDATE field
//$values = str_replace(",", "\\,", $values);
$line = $d->getName() . $p . ":" . $values;
$line = str_replace(array("<br>","<BR>","<br/>","<BR/"),"\\n",$line);
$line = str_replace(array("\r\n","\n\r","\n","\r"),'\n',$line);
//$line = str_replace(array(',',';','\\'), array('\\,','\\;','\\\\'),$line);
//$line =strip_tags($line);
$linecount = 0;
while (strlen($line) > 0) {
$linewidth = ($linecount == 0? 75 : 74);
$linesize = (strlen($line) > $linewidth? $linewidth: strlen($line));
if($linecount > 0)
$txtstr .= " ";
$txtstr .= substr($line,0,$linesize) . "\r\n";
$linecount += 1;
$line = substr($line,$linewidth);
}
*/
}
//echo $line . "\n";
}
if(property_exists($node,"child"))
foreach ($node->child as $c){
$txtstr .= $node->export($c,$level + 1);
}
$txtstr .= "END:" . $node->getName() . "\r\n";
return $txtstr;
}
/**
* print an attribute line
* @param object $d attributes
* @param object $p properties
*
*/
function printDataLine($d, $p)
{
$txtstr = "";
$values = $d->getValues();
// don't think we need this, Sunbird does not like it in the EXDATE field
//$values = str_replace(",", "\\,", $values);
$line = $d->getName() . $p . ":" . $values;
$line = str_replace(array("<br>","<BR>","<br/>","<BR/"),"\\n",$line);
$line = str_replace(array("\r\n","\n\r","\n","\r"),'\n',$line);
//$line = str_replace(array(',',';','\\'), array('\\,','\\;','\\\\'),$line);
//$line =strip_tags($line);
$linecount = 0;
while (strlen($line) > 0) {
$linewidth = ($linecount == 0? 75 : 74);
$linesize = (strlen($line) > $linewidth? $linewidth: strlen($line));
if($linecount > 0)
$txtstr .= " ";
$txtstr .= substr($line,0,$linesize) . "\r\n";
$linecount += 1;
$line = substr($line,$linewidth);
}
return $txtstr;
}
}
/**
*
* The main iCalendar object containing ZCiCalDataNodes and ZCiCalNodes.
*
*/
class ZCiCal {
/**
* The root node of the object tree
*
* @var object
*/
var $tree=null;
/**
* The most recently created node in the tree
*
* @var object
*/
var $curnode=null;
/**
* The main iCalendar object containing ZCiCalDataNodes and ZCiCalNodes.
*
* use maxevents and startevent to read events in multiple passes (to save memory)
*
* @param string $data icalendar feed string (empty if creating new feed)
*
* @param int $maxevents maximum # of events to read
*
* @param int $startevent starting event to read
*
* @return void
*
*
*/
function __construct($data = "", $maxevents = 1000000, $startevent = 0) {
if($data != ""){
// unfold lines
// first change all eol chars to "\n"
$data = str_replace(array("\r\n", "\n\r", "\n", "\r"), "\n", $data);
// now unfold lines
//$data = str_replace(array("\n ", "\n "),"!?", $data);
$data = str_replace(array("\n ", "\n "),"", $data);
// replace special iCal chars
$data = str_replace(array("\\\\","\,"),array("\\",","), $data);
// parse each line
$lines = explode("\n", $data);
$linecount = 0;
$eventcount = 0;
$eventpos = 0;
foreach($lines as $line) {
//$line = str_replace("!?", "\n", $line); // add nl back into descriptions
// echo ($linecount + 1) . ": " . $line . "<br/>";
if(substr($line,0,6) == "BEGIN:") {
// start new object
$name = substr($line,6);
if($name == "VEVENT")
{
if($eventcount < $maxevents && $eventpos >= $startevent)
{
$this->curnode = new ZCiCalNode($name, $this->curnode);
if($this->tree == null)
$this->tree = $this->curnode;
}
}
else
{
$this->curnode = new ZCiCalNode($name, $this->curnode);
if($this->tree == null)
$this->tree = $this->curnode;
}
//echo "new node: " . $this->curnode->name . "<br/>\n";
/*
if($this->curnode->getParent() != null)
echo "parent of " . $this->curnode->getName() . " is " . $this->curnode->getParent()->getName() . "<br/>";
else
echo "parent of " . $this->curnode->getName() . " is null<br/>";
*/
}
else if(substr($line,0,4) == "END:") {
$name = substr($line,4);
if($name == "VEVENT")
{
if($eventcount < $maxevents && $eventpos >= $startevent)
{
$eventcount++;
if($this->curnode->getName() != $name) {
//panic, mismatch in iCal structure
//die("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
throw new Exception("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
}
if($this->curnode->getParent() != null) {
//echo "moving up from " . $this->curnode->getName() ;
$this->curnode = & $this->curnode->getParent();
//echo " to " . $this->curnode->getName() . "<br/>";
//echo $this->curnode->getName() . " has " . count($this->curnode->child) . " children<br/>";
}
}
$eventpos++;
}
else
{
if($this->curnode->getName() != $name) {
//panic, mismatch in iCal structure
//die("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
throw new Exception("Can't read iCal file structure, expecting " . $this->curnode->getName() . " but reading $name instead");
}
if($this->curnode->getParent() != null) {
//echo "moving up from " . $this->curnode->getName() ;
$this->curnode = & $this->curnode->getParent();
//echo " to " . $this->curnode->getName() . "<br/>";
//echo $this->curnode->getName() . " has " . count($this->curnode->child) . " children<br/>";
}
}
}
else {
$datanode = new ZCiCalDataNode($line);
if($this->curnode->getName() == "VEVENT")
{
if($eventcount < $maxevents && $eventpos >= $startevent)
{
if($datanode->getName() == "EXDATE")
{
if(!array_key_exists($datanode->getName(),$this->curnode->data))
{
$this->curnode->data[$datanode->getName()] = $datanode;
}
else
{
$this->curnode->data[$datanode->getName()]->value[] = $datanode->value[0];
}
}
else
{
if(!array_key_exists($datanode->getName(),$this->curnode->data))
{
$this->curnode->data[$datanode->getName()] = $datanode;
}
else
{
$tnode = $this->curnode->data[$datanode->getName()];
$this->curnode->data[$datanode->getName()] = array();
$this->curnode->data[$datanode->getName()][] = $tnode;
$this->curnode->data[$datanode->getName()][] = $datanode;
}
}
}
}
else
{
if($datanode->getName() == "EXDATE")
{
if(!array_key_exists($datanode->getName(),$this->curnode->data))
{
$this->curnode->data[$datanode->getName()] = $datanode;
}
else
{
$this->curnode->data[$datanode->getName()]->value[] = $datanode->value[0];
}
}
else
{
if(!array_key_exists($datanode->getName(),$this->curnode->data))
{
$this->curnode->data[$datanode->getName()] = $datanode;
}
else
{
$tnode = $this->curnode->data[$datanode->getName()];
$this->curnode->data[$datanode->getName()] = array();
$this->curnode->data[$datanode->getName()][] = $tnode;
$this->curnode->data[$datanode->getName()][] = $datanode;
}
}
}
}
$linecount++;
}
}
else {
$name = "VCALENDAR";
$this->curnode = new ZCiCalNode($name, $this->curnode);
$this->tree = $this->curnode;
$datanode = new ZCiCalDataNode("VERSION:2.0");
$this->curnode->data[$datanode->getName()] = $datanode;
$datanode = new ZCiCalDataNode("PRODID:-//ZContent.net//ZapCalLib 1.0//EN");
$this->curnode->data[$datanode->getName()] = $datanode;
$datanode = new ZCiCalDataNode("CALSCALE:GREGORIAN");
$this->curnode->data[$datanode->getName()] = $datanode;
$datanode = new ZCiCalDataNode("METHOD:PUBLISH");
$this->curnode->data[$datanode->getName()] = $datanode;
}
}
/**
* CountEvents()
*
* Return the # of VEVENTs in the object
*
* @return int
*/
function countEvents() {
$count = 0;
if(isset($this->tree->child)){
foreach($this->tree->child as $child){
if($child->getName() == "VEVENT")
$count++;
}
}
return $count;
}
/**
* CountVenues()
*
* Return the # of VVENUEs in the object
*
* @return int
*/
function countVenues() {
$count = 0;
if(isset($this->tree->child)){
foreach($this->tree->child as $child){
if($child->getName() == "VVENUE")
$count++;
}
}
return $count;
}
/**
* Export object to string
*
* This function exports all objects to an iCalendar string
*
* @return string an iCalendar formatted string
*/
function export() {
return $this->tree->export($this->tree);
}
/**
* Get first event in object list
* Use getNextEvent() to navigate through list
*
* @return object The first event, or null
*/
function &getFirstEvent() {
static $nullguard = null;
if ($this->countEvents() > 0){
$child = $this->tree->child[0];
$event=false;
while(!$event && $child != null){
if($child->getName() == "VEVENT")
$event = true;
else
$child = $child->next;
}
return $child;
}
else
return $nullguard;
}
/**
* Get next event in object list
*
* @param object $event The current event object
*
* @return object Returns the next event or null if past last event
*/
function &getNextEvent($event){
do{
$event = $event->next;
} while($event != null && $event->getName() != "VEVENT");
return $event;
}
/**
* Get first venue in object list
* Use getNextVenue() to navigate through list
*
* @return object The first venue, or null
*/
function &getFirstVenue() {
static $nullguard = null;
if ($this->countVenues() > 0){
$child = $this->tree->child[0];
$event=false;
while(!$event && $child != null){
if($child->getName() == "VVENUE")
$event = true;
else
$child = $child->next;
}
return $child;
}
else
return $nullguard;
}
/**
* Get next venue in object list
*
* @param object $venue The current venue object
*
* @return object Returns the next venue or null if past last venue
*/
function &getNextVenue($venue){
do{
$venue = $venue->next;
} while($venue != null && $venue->getName() != "VVENUE");
return $venue;
}
/**
* Get first child in object list
* Use getNextSibling() and getPreviousSibling() to navigate through list
*
* @param object $thisnode The parent object
*
* @return object The child object
*/
function &getFirstChild(& $thisnode){
$nullvalue = null;
if(count($thisnode->child) > 0) {
//echo "moving from " . $thisnode->getName() . " to " . $thisnode->child[0]->getName() . "<br/>";
return $thisnode->child[0];
}
else
return $nullvalue;
}
/**
* Get next sibling in object list
*
* @param object $thisnode The current object
*
* @return object Returns the next sibling
*/
function &getNextSibling(& $thisnode){
return $thisnode->next;
}
/**
* Get previous sibling in object list
*
* @param object $thisnode The current object
*
* @return object Returns the previous sibling
*/
function &getPrevSibling(& $thisnode){
return $thisnode->prev;
}
/**
* Read date/time in iCal formatted string
*
* @param string iCal formated date/time string
*
* @return int Unix timestamp
* @deprecated Use ZDateHelper::toUnixDateTime() instead
*/
function toUnixDateTime($datetime){
$year = substr($datetime,0,4);
$month = substr($datetime,4,2);
$day = substr($datetime,6,2);
$hour = 0;
$minute = 0;
$second = 0;
if(strlen($datetime) > 8 && $datetime[8] == "T") {
$hour = substr($datetime,9,2);
$minute = substr($datetime,11,2);
$second = substr($datetime,13,2);
}
$d1 = mktime($hour, $minute, $second, $month, $day, $year);
}
/**
* fromUnixDateTime()
*
* Take Unix timestamp and format to iCal date/time string
*
* @param int $datetime Unix timestamp, leave blank for current date/time
*
* @return string formatted iCal date/time string
* @deprecated Use ZDateHelper::fromUnixDateTimetoiCal() instead
*/
static function fromUnixDateTime($datetime = null){
date_default_timezone_set('UTC');
if($datetime == null)
$datetime = time();
return date("Ymd\THis",$datetime);
}
/**
* fromUnixDate()
*
* Take Unix timestamp and format to iCal date string
*
* @param int $datetime Unix timestamp, leave blank for current date/time
*
* @return string formatted iCal date string
* @deprecated Use ZDateHelper::fromUnixDateTimetoiCal() instead
*/
static function fromUnixDate($datetime = null){
date_default_timezone_set('UTC');
if($datetime == null)
$datetime = time();
return date("Ymd",$datetime);
}
/**
* Format into iCal time format from SQL date or SQL date-time format
*
* @param string $datetime SQL date or SQL date-time string
*
* @return string iCal formatted string
* @deprecated Use ZDateHelper::fromSqlDateTime() instead
*/
static function fromSqlDateTime($datetime = ""){
if($datetime == "")
$datetime = ZDateHelper::toSqlDateTime();
if(strlen($datetime) > 10)
return sprintf('%04d%02d%02dT%02d%02d%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2),
substr($datetime,11,2),substr($datetime,14,2),substr($datetime,17,2));
else
return sprintf('%04d%02d%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2));
}
/**
* Format iCal time format to either SQL date or SQL date-time format
*
* @param string $datetime icalendar formatted date or date-time
* @return string SQL date or SQL date-time string
* @deprecated Use ZDateHelper::toSqlDateTime() instead
*/
static function toSqlDateTime($datetime = ""){
if($datetime == "")
return ZDateHelper::toSqlDateTime();
if(strlen($datetime) > 10)
return sprintf('%04d-%02d-%02d %02d:%02d:%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2),
substr($datetime,11,2),substr($datetime,14,2),substr($datetime,17,2));
else
return sprintf('%04d-%02d-%02d',substr($datetime,0,4),substr($datetime,5,2),substr($datetime,8,2));
}
/**
* Pull timezone data from node and put in array
*
* Returning array contains the following array keys: tzoffsetfrom, tzoffsetto, tzname, dtstart, rrule
*
* @param array $node timezone object
*
* @return array
*/
static function getTZValues($node){
$tzvalues = array();
$tnode = @$node->data['TZOFFSETFROM'];
if($tnode != null){
$tzvalues["tzoffsetfrom"] = $tnode->getValues();
}
$tnode = @$node->data['TZOFFSETTO'];
if($tnode != null){
$tzvalues["tzoffsetto"] = $tnode->getValues();
}
$tnode = @$node->data['TZNAME'];
if($tnode != null){
$tzvalues["tzname"] = $tnode->getValues();
}
else
$tzvalues["tzname"] = "";
$tnode = @$node->data['DTSTART'];
if($tnode != null){
$tzvalues["dtstart"] = ZDateHelper::fromiCaltoUnixDateTime($tnode->getValues());
}
$tnode = @$node->data['RRULE'];
if($tnode != null){
$tzvalues["rrule"] = $tnode->getValues();
//echo "rule: " . $tzvalues["rrule"] . "<br/>\n";
}
else{
// no rule specified, let's create one from based on the date
$date = getdate($tzvalues["dtstart"]);
$month = $date["mon"];
$day = $date["mday"];
$tzvalues["rrule"] = "FREQ=YEARLY;INTERVAL=1;BYMONTH=$month;BYMONTHDAY=$day";
}
return $tzvalues;
}
/**
* Escape slashes, commas and semicolons in strings
*
* @param string $content
*
* @return string
*/
static function formatContent($content)
{
$content = str_replace(array('\\' , ',' , ';' ), array('\\\\' , '\\,' , '\\;' ),$content);
return $content;
}
}
?>

View file

@ -1,6 +0,0 @@
<html>
<head>
</head>
<body>
</body>
</html>

View file

@ -1,796 +0,0 @@
<?php
/**
* recurringdate.php - create list of dates from recurring rule
*
* @package ZapCalLib
* @author Dan Cogliano <http://zcontent.net>
* @copyright Copyright (C) 2006 - 2017 by Dan Cogliano
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
* @link http://icalendar.org/php-library.html
*/
// No direct access
defined('_ZAPCAL') or die( 'Restricted access' );
/**
* Zap Calendar Recurring Date Helper Class
*
* Class to expand recurring rule to a list of dates
*/
class ZCRecurringDate {
/**
* rules string
*
* @var string
*/
var $rules = "";
/**
* start date in Unix Timestamp format (local timezone)
*
* @var integer
*/
var $startdate = null;
/**
* repeating frequency type (i.e. "y" for yearly, "m" for monthly)
*
* @var string
*/
var $freq = null;
/**
* timezone of event (using PHP timezones)
*
* @var string
*/
var $tzid = null;
/**
* repeat mode ('c': count, 'u': until)
*
* @var string
*/
var $repeatmode=null;
/**
* repeat until date (in UTC Unix Timestamp format)
*
* @var integer
*/
var $until=null;
/**
* repeat count when repeat mode is 'c'
*
* @var integer
*/
var $count=0;
/**
* array of repeat by seconds values
*
* @var array
*/
var $bysecond=array();
/**
* array of repeat by minutes values
*
* @var array
*/
var $byminute=array();
/**
* array of repeat by hour values
*
* @var array
*/
var $byhour=array();
/**
* array of repeat by day values
*
* @var array
*/
var $byday=array();
/**
* array of repeat by month day values
*
* @var array
*/
var $bymonthday=array();
/**
* array of repeat by month values
*
* @var array
*/
var $bymonth=array();
/**
* array of repeat by year values
*
* @var array
*/
var $byyear=array();
/**
* array of repeat by setpos values
*
* @var array
*/
var $bysetpos=array();
/**
* inteval of repeating event (i.e. every 2 weeks, every 6 months)
*
* @var integer
*/
var $interval = 1;
/**
* debug level (for testing only)
*
* @var integer
*/
var $debug = 0;
/**
* error string (future use)
*
* @var string
*/
var $error;
/**
* array of exception dates in Unix Timestamp format (UTC dates)
*
* @var array
*/
var $exdates=array();
/**
* Expand recurring rule to a list of dates
*
* @param string $rules iCalendar rules string
* @param integer $startdate start date in Unix Timestamp format
* @param array $exdates array of exception dates
* @param string $tzid timezone of event (using PHP timezones)
*/
function __construct($rules, $startdate, $exdates = array(),$tzid = "UTC"){
if(strlen($rules) > 0){
//move exdates to event timezone for comparing with event date
for($i = 0; $i < count($exdates); $i++)
{
$exdates[$i] = ZDateHelper::toUnixDateTime(ZDateHelper::toLocalDateTime(ZDateHelper::toSQLDateTime($exdates[$i]),$tzid));
}
$rules=str_replace("\'","",$rules);
$this->rules = $rules;
if($startdate == null){
// if not specified, use start date of beginning of last year
$tdate=getdate();
$startdate=mktime(0,0,0,1,1,$tdate["year"] - 1);
}
$this->startdate = $startdate;
$this->tzid = $tzid;
$this->exdates = $exdates;
$rules=explode(";", $rules);
$ruletype = "";
foreach($rules as $rule){
$item=explode("=",$rule);
//echo $item[0] . "=" . $item[1] . "<br/>\n";
switch($item[0]){
case "FREQ":
switch($item[1]){
case "YEARLY":
$this->freq="y";
break;
case "MONTHLY":
$this->freq="m";
break;
case "WEEKLY":
$this->freq="w";
break;
case "DAILY":
$this->freq="d";
break;
case "HOURLY":
$this->freq="h";
break;
case "MINUTELY":
$this->freq="i";
break;
case "SECONDLY":
$this->freq="s";
break;
}
break;
case "INTERVAL":
$this->interval = $item[1];
break;
case "BYSECOND":
$this->bysecond = explode(",",$item[1]);
$ruletype = $item[0];
break;
case "BYMINUTE":
$this->byminute = explode(",",$item[1]);
$ruletype = $item[0];
break;
case "BYHOUR":
$this->byhour = explode(",",$item[1]);
$ruletype = $item[0];
break;
case "BYDAY":
$this->byday = explode(",",$item[1]);
$ruletype = $item[0];
break;
case "BYMONTHDAY":
$this->bymonthday = explode(",",$item[1]);
$ruletype = $item[0];
break;
case "BYMONTH":
$this->bymonth = explode(",",$item[1]);
$ruletype = $item[0];
break;
case "BYYEAR":
$this->byyear = explode(",",$item[1]);
$ruletype = $item[0];
break;
case "COUNT":
$this->count = intval($item[1]);
$this->repeatmode = "c";
break;
case "BYSETPOS":
$this->bysetpos = explode(",",$item[1]);
break;
case "UNTIL":
$this->until = ZDateHelper::fromiCaltoUnixDateTime($item[1]);
$this->repeatmode = "u";
break;
}
}
if(count($this->bysetpos) > 0){
switch($ruletype){
case "BYYEAR":
$this->byyear = $this->bySetPos($this->byyear,$this->bysetpos);
break;
case "BYMONTH":
$this->bymonth = $this->bySetPos($this->bymonth,$this->bysetpos);
break;
case "BYMONTHDAY":
$this->bymonthday = $this->bySetPos($this->bymonthday,$this->bysetpos);
break;
case "BYDAY":
$this->byday = $this->bySetPos($this->byday,$this->bysetpos);
break;
case "BYHOUR":
$this->byhour = $this->bySetPos($this->byhour,$this->bysetpos);
break;
case "BYMINUTE":
$this->byminute = $this->bySetPos($this->byminute,$this->bysetpos);
break;
case "BYSECOND":
$this->bysecond = $this->bySetPos($this->bysecond,$this->bysetpos);
break;
}
}
}
}
/**
* bysetpos rule support
*
* @param array $bytype
* @param array $bysetpos
*
* @return array
*/
function bySetPos($bytype, $bysetpos){
$result = array();
for($i=0; $i < count($bysetpos); $i++){
for($j=0; $j < count($bytype); $j++){
$result[] = $bysetpos[$i] . $bytype[$j];
}
}
return $result;
}
/**
* save error
*
* @param string $msg
*/
function setError($msg){
$this->error = $msg;
}
/**
* get error message
*
* @return string error message
*/
function getError(){
return $this->error;
}
/**
* set debug level (0: none, 1: minimal, 2: more output)
*
* @param integer $level
*
*/
function setDebug($level)
{
$this->debug = $level;
}
/**
* display debug message
*
* @param integer $level
* @param string $msg
*/
function debug($level, $msg){
if($this->debug >= $level)
echo $msg . "<br/>\n";
}
/**
* Get repeating dates by year
*
* @param integer $startdate start date of repeating events, in Unix timestamp format
* @param integer $enddate end date of repeating events, in Unix timestamp format
* @param array $rdates array to contain expanded repeating dates
* @param string $tzid timezone of event (using PHP timezones)
*
* @return integer count of dates
*/
private function byYear($startdate, $enddate, &$rdates, $tzid="UTC"){
self::debug(1,"byYear(" . ZDateHelper::toSqlDateTime($startdate) . ","
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
$count = 0;
if(count($this->byyear) > 0){
foreach($this->byyear as $year){
$t = getdate($startdate);
$wdate = mktime($t[hours],$t[minutes],$t[seconds],$t[month],$t[mday],$year);
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
$count = $this->byMonth($wdate, $enddate, $rdates, $tzid);
if($count == 0) {
$rdates[] = $wdate;
$count++;
}
}
}
}
else if(!$this->maxDates($rdates))
$count = $this->byMonth($startdate, $enddate, $rdates, $tzid);
self::debug(1,"byYear() returned " . $count );
return $count;
}
/**
* Get repeating dates by month
*
* @param integer $startdate start date of repeating events, in Unix timestamp format
* @param integer $enddate end date of repeating events, in Unix timestamp format
* @param array $rdates array to contain expanded repeating dates
* @param string $tzid timezone of event (using PHP timezones)
*
* @return integer count of dates
*/
private function byMonth($startdate, $enddate, &$rdates, $tzid="UTC"){
self::debug(1,"byMonth(" . ZDateHelper::toSqlDateTime($startdate) . ","
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
$count = 0;
if(count($this->bymonth) > 0){
foreach($this->bymonth as $month){
$t = getdate($startdate);
$wdate = mktime($t["hours"],$t["minutes"],$t["seconds"],$month,$t["mday"],$t["year"]);
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
$count = $this->byMonthDay($wdate, $enddate, $rdates, $tzid);
if($count == 0) {
$rdates[] = $wdate;
$count++;
}
}
}
}
else if(!$this->maxDates($rdates))
$count = $this->byMonthDay($startdate, $enddate, $rdates, $tzid);
self::debug(1,"byMonth() returned " . $count );
return $count;
}
/**
* Get repeating dates by month day
*
* @param integer $startdate start date of repeating events, in Unix timestamp format
* @param integer $enddate end date of repeating events, in Unix timestamp format
* @param array $rdates array to contain expanded repeating dates
* @param string $tzid timezone of event (using PHP timezones)
*
* @return integer count of dates
*/
private function byMonthDay($startdate, $enddate, &$rdates, $tzid="UTC"){
self::debug(1,"byMonthDay(" . ZDateHelper::toSqlDateTime($startdate) . ","
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
$count = 0;
self::debug(1,"start date: " . ZDateHelper::toSqlDateTime($startdate));
if(count($this->bymonthday) > 0){
foreach($this->bymonthday as $day){
$day = intval($day);
$t = getdate($startdate);
$wdate = mktime($t['hours'],$t['minutes'],$t['seconds'],$t['mon'],$day,$t['year']);
self::debug(2,"mktime(" . $t['hours'] . ", " . $t['minutes']
. ", " . $t['mon'] . ", " . $day . ", " . $t['year'] . ") returned $wdate");
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
$count = $this->byDay($wdate, $enddate, $rdates, $tzid);
if($count == 0) {
$rdates[] = $wdate;
$count++;
}
}
}
}
else if(!$this->maxDates($rdates)) {
self::debug(1,"start date: " . ZDateHelper::toSqlDateTime($startdate));
$count = $this->byDay($startdate, $enddate, $rdates, $tzid);
}
self::debug(1,"byMonthDay() returned " . $count );
return $count;
}
/**
* Get repeating dates by day
*
* @param integer $startdate start date of repeating events, in Unix timestamp format
* @param integer $enddate end date of repeating events, in Unix timestamp format
* @param array $rdates array to contain expanded repeating dates
* @param string $tzid timezone of event (using PHP timezones)
*
* @return integer count of dates
*/
private function byDay($startdate, $enddate, &$rdates, $tzid="UTC"){
self::debug(1,"byDay(" . ZDateHelper::toSqlDateTime($startdate) . ","
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
$days = array(
"SU" => 0,
"MO" => 1,
"TU" => 2,
"WE" => 3,
"TH" => 4,
"FR" => 5,
"SA" => 6);
$idays = array(
0 => "SU",
1 => "MO",
2 => "TU",
3 => "WE",
4 => "TH",
5 => "FR",
6 => "SA");
$count = 0;
if(count($this->byday) > 0){
if(empty($this->byday[0]))
{
$this->byday[0] = $idays[date("w",$startdate)];
}
foreach($this->byday as $tday){
$t = getdate($startdate);
$day = substr($tday,strlen($tday) - 2);
if(strlen($day) < 2)
{
// missing start day, use current date for DOW
$day = $idays[date("w",$startdate)];
}
if(strlen($tday) > 2) {
$imin = 1;
$imax = 5; // max # of occurances in a month
if(strlen($tday) > 2)
$imin = $imax = substr($tday,0,strlen($tday) - 2);
self::debug(2,"imin: $imin, imax: $imax, tday: $tday, day: $day, daynum: {$days[$day]}");
for($i = $imin; $i <= $imax; $i++){
$wdate = ZDateHelper::getDateFromDay($startdate,$i-1,$days[$day],$tzid);
self::debug(2,"getDateFromDay(" . ZDateHelper::toSqlDateTime($startdate)
. ",$i,{$days[$day]}) returned " . ZDateHelper::toSqlDateTime($wdate));
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
$count = $this->byHour($wdate, $enddate, $rdates);
if($count == 0){
$rdates[] = $wdate;
$count++;
//break;
}
}
}
}
else {
// day of week version
$startdate_dow = date("w",$startdate);
$datedelta = $days[$day] - $startdate_dow;
self::debug(2, "start_dow: $startdate_dow, datedelta: $datedelta");
if($datedelta >= 0)
{
$wdate = ZDateHelper::addDate($startdate,0,0,0,0,$datedelta,0,$this->tzid);
self::debug(2, "wdate: " . ZDateHelper::toSqlDateTime($wdate));
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
$count = $this->byHour($wdate, $enddate, $rdates);
if($count == 0){
$rdates[] = $wdate;
$count++;
self::debug(2,"adding date " . ZDateHelper::toSqlDateTime($wdate) );
}
}
}
}
}
}
else if(!$this->maxDates($rdates))
$count = $this->byHour($startdate, $enddate, $rdates);
self::debug(1,"byDay() returned " . $count );
return $count;
}
/**
* Get repeating dates by hour
*
* @param integer $startdate start date of repeating events, in Unix timestamp format
* @param integer $enddate end date of repeating events, in Unix timestamp format
* @param array $rdates array to contain expanded repeating dates
* @param string $tzid timezone of event (using PHP timezones)
*
* @return integer count of dates
*/
private function byHour($startdate, $enddate, &$rdates, $tzid="UTC"){
self::debug(1,"byHour(" . ZDateHelper::toSqlDateTime($startdate) . ","
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
$count = 0;
if(count($this->byhour) > 0){
foreach($this->byhour as $hour){
$t = getdate($startdate);
$wdate = mktime($hour,$t["minutes"],$t["seconds"],$t["mon"],$t["mday"],$t["year"]);
self::debug(2,"checking date/time " . ZDateHelper::toSqlDateTime($wdate));
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
$count = $this->byMinute($wdate, $enddate, $rdates);
if($count == 0) {
$rdates[] = $wdate;
$count++;
}
}
}
}
else if(!$this->maxDates($rdates))
$count = $this->byMinute($startdate, $enddate, $rdates);
self::debug(1,"byHour() returned " . $count );
return $count;
}
/**
* Get repeating dates by minute
*
* @param integer $startdate start date of repeating events, in Unix timestamp format
* @param integer $enddate end date of repeating events, in Unix timestamp format
* @param array $rdates array to contain expanded repeating dates
* @param string $tzid timezone of event (using PHP timezones)
*
* @return integer count of dates
*/
private function byMinute($startdate, $enddate, &$rdates, $tzid="UTC"){
self::debug(1,"byMinute(" . ZDateHelper::toSqlDateTime($startdate) . ","
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
$count = 0;
if(count($this->byminute) > 0){
foreach($this->byminute as $minute){
$t = getdate($startdate);
$wdate = mktime($t["hours"],$minute,$t["seconds"],$t["mon"],$t["mday"],$t["year"]);
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
$count = $this->bySecond($wdate, $enddate, $rdates);
if($count == 0) {
$rdates[] = $wdate;
$count++;
}
}
}
}
else if(!$this->maxDates($rdates))
$count = $this->bySecond($startdate, $enddate, $rdates);
self::debug(1,"byMinute() returned " . $count );
return $count;
}
/**
* Get repeating dates by second
*
* @param integer $startdate start date of repeating events, in Unix timestamp format
* @param integer $enddate end date of repeating events, in Unix timestamp format
* @param array $rdates array to contain expanded repeating dates
* @param string $tzid timezone of event (using PHP timezones)
*
* @return integer count of dates
*/
private function bySecond($startdate, $enddate, &$rdates, $tzid="UTC"){
self::debug(1,"bySecond(" . ZDateHelper::toSqlDateTime($startdate) . ","
. ZDateHelper::toSqlDateTime($enddate) . "," . count($rdates) . " dates)");
$count = 0;
if(count($this->bysecond) > 0){
foreach($this->bysecond as $second){
$t = getdate($startdate);
$wdate = mktime($t["hours"],$t["minutes"],$second,$t["mon"],$t["mday"],$t["year"]);
if($startdate <= $wdate && $wdate < $enddate && !$this->maxDates($rdates)){
$rdates[] = $wdate;
$count++;
}
}
}
self::debug(1,"bySecond() returned " . $count );
return $count;
}
/**
* Determine if the loop has reached the end date
*
* @param array $rdates array of repeating dates
*
* @return boolean
*/
private function maxDates($rdates){
if($this->repeatmode == "c" && count($rdates) >= $this->count)
return true; // exceeded count
else if(count($rdates) > 0 && $this->repeatmode == "u" && $rdates[count($rdates) - 1] > $this->until){
return true; //past date
}
return false;
}
/**
* Get array of dates from recurring rule
*
* @param $maxdate integer maximum date to appear in repeating dates in Unix timestamp format
*
* @return array
*/
public function getDates($maxdate = null){
//$this->debug = 2;
self::debug(1,"getDates()");
$nextdate = $enddate = $this->startdate;
$rdates = array();
$done = false;
$eventcount = 0;
$loopcount = 0;
self::debug(2,"freq: " . $this->freq . ", interval: " . $this->interval);
while(!$done){
self::debug(1,"<b>*** Frequency ({$this->freq}) loop pass $loopcount ***</b>");
switch($this->freq){
case "y":
if($eventcount > 0)
{
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,0,$this->interval,$this->tzid);
self::debug(2,"addDate() returned " . ZDateHelper::toSqlDateTime($nextdate));
if(!empty($this->byday)){
$t = getdate($nextdate);
$nextdate = gmmktime($t["hours"],$t["minutes"],$t["seconds"],$t["mon"],1,$t["year"]);
}
self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")");
}
$enddate=ZDateHelper::addDate($nextdate,0,0,0,0,0,1);
break;
case "m":
if($eventcount > 0)
{
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0,$this->tzid);
self::debug(2,"addDate() returned " . ZDateHelper::toSqlDateTime($nextdate));
}
if(count($this->byday) > 0)
{
$t = getdate($nextdate);
if($t["mday"] > 28)
{
//check for short months when using month by day, make sure we do not overshoot the counter and skip a month
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0,$this->tzid);
$t2 = getdate($nextdate);
if($t2["mday"] < $t["mday"])
{
// oops, skipped a month, backup to previous month
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$t2["mday"] - $t["mday"],0,$this->tzid);
}
}
$t = getdate($nextdate);
$nextdate = mktime($t["hours"],$t["minutes"],$t["seconds"],$t["mon"],1,$t["year"]);
}
self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")");
$enddate=ZDateHelper::addDate($nextdate,0,0,0,$this->interval,0,0);
break;
case "w":
if($eventcount == 0)
$nextdate=$nextdate;
else {
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval*7,0,$this->tzid);
if(count($this->byday) > 0){
$dow = date("w", $nextdate);
// move to beginning of week (Sunday)
$bow = 0;
$diff = $bow - $dow;
if($diff > 0)
$diff = $diff - 7;
$nextdate = ZDateHelper::addDate($nextdate,0,0,0,0,$diff,0);
}
self::debug(2,"nextdate set to $nextdate (". ZDateHelper::toSQLDateTime($nextdate) . ")");
}
$enddate=ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval*7,0);
break;
case "d":
$nextdate=($eventcount==0?$nextdate:
ZDateHelper::addDate($nextdate,0,0,0,0,$this->interval,0,$this->tzid));
$enddate=ZDateHelper::addDate($nextdate,0,0,0,0,1,0);
break;
}
$count = $this->byYear($nextdate,$enddate,$rdates,$this->tzid);
$eventcount += $count;
if($maxdate > 0 && $maxdate < $nextdate)
{
array_pop($rdates);
$done = true;
}
else if($count == 0 && !$this->maxDates($rdates)){
$rdates[] = $nextdate;
$eventcount++;
}
if($this->maxDates($rdates))
$done = true;
$year = date("Y", $nextdate);
if($year > _ZAPCAL_MAXYEAR)
{
$done = true;
}
$loopcount++;
if($loopcount > _ZAPCAL_MAXYEAR){
$done = true;
throw new Exception("Infinite loop detected in getDates()");
}
}
if($this->repeatmode == "u" && $rdates[count($rdates) - 1] > $this->until){
// erase last item
array_pop($rdates);
}
$count1 = count($rdates);
$rdates = array_unique($rdates);
$count2 = count($rdates);
$dups = $count1 - $count2;
$excount = 0;
foreach($this->exdates as $exdate)
{
if($pos = array_search($exdate,$rdates))
{
array_splice($rdates,$pos,1);
$excount++;
}
}
self::debug(1,"getDates() returned " . count($rdates) . " dates, removing $dups duplicates, $excount exceptions");
if($this->debug >= 2)
{
self::debug(2,"Recurring Dates:");
foreach($rdates as $rdate)
{
$d = getdate($rdate);
self::debug(2,ZDateHelper::toSQLDateTime($rdate) . " " . $d["wday"] );
}
self::debug(2,"Exception Dates:");
foreach($this->exdates as $exdate)
{
self::debug(2, ZDateHelper::toSQLDateTime($exdate));
}
//exit;
}
return $rdates;
}
}

View file

@ -1,142 +0,0 @@
<?php
/**
* timezone.php - create timezone data for use in icalendar file
*
* @package ZapCalLib
* @author Dan Cogliano <http://zcontent.net>
* @copyright Copyright (C) 2006 - 2017 by Dan Cogliano
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
* @link http://icalendar.org/php-library.html
*/
// No direct access
defined('_ZAPCAL') or die( 'Restricted access' );
/**
* Zap Calendar Time Zone Helper Class
*
* Class to help create timezone section of iCalendar file
*
* @copyright Copyright (C) 2006 - 2016 by Dan Cogliano
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
class ZCTimeZoneHelper {
/**
* getTZNode creates VTIMEZONE section in an iCalendar file
*
* @param @startyear int start year of date range
*
* @param @endyear int end year of date range
*
* @param $tzid string PHP timezone, use underscore for multiple words (i.e. "New_York" for "New York")
*
* @param $parentnode object iCalendar object where VTIMEZONE will be created
*
* @return object return VTIMEZONE object
*/
static function getTZNode($startyear, $endyear, $tzid, $parentnode)
{
$tzmins = array();
$tzmaxs = array();
if(!array_key_exists($tzid,$tzmins) || $tzmins[$tzid] > $startyear)
{
$tzmins[$tzid] = $startyear;
}
if(!array_key_exists($tzid,$tzmaxs) || $tzmaxs[$tzid] < $endyear)
{
$tzmaxs[$tzid] = $endyear;
}
foreach(array_keys($tzmins) as $tzid)
{
$tmin = $tzmins[$tzid] - 1;
if(array_key_exists($tzid,$tzmaxs))
{
$tmax = $tzmaxs[$tzid] + 1;
}
else
{
$tmax = $tzmins[$tzid] + 1;
}
$tstart = gmmktime(0,0,0,1,1,$tmin);
$tend = gmmktime(23,59,59,12,31,$tmax);
$tz = new DateTimeZone($tzid);
$transitions = $tz->getTransitions($tstart,$tend);
$tzobj = new ZCiCalNode("VTIMEZONE", $parentnode, true);
$datanode = new ZCiCalDataNode("TZID:" . str_replace("_"," ",$tzid));
$tzobj->data[$datanode->getName()] = $datanode;
$count = 0;
$lasttransition = null;
if(count($transitions) == 1)
{
// not enough transitions found, probably UTC
// lets add fake transition at end for those systems that need it (i.e. Outlook)
$t2 = array();
$t2["isdst"] = $transitions[0]["isdst"];
$t2["offset"] = $transitions[0]["offset"];
$t2["ts"] = $tstart;
$t2["abbr"] = $transitions[0]["abbr"];
$transitions[] = $t2;
}
foreach($transitions as $transition)
{
$count++;
if($count == 1)
{
$lasttransition = $transition;
continue; // skip first item
}
if($transition["isdst"] == 1)
{
$tobj = new ZCiCalNode("DAYLIGHT", $tzobj);
}
else
{
$tobj = new ZCiCalNode("STANDARD", $tzobj);
}
//$tzobj->data[$tobj->getName()] == $tobj;
// convert timestamp to local time zone
$ts = ZDateHelper::toUnixDateTime(ZDateHelper::toLocalDateTime(ZDateHelper::toSQLDateTime($transition["ts"]),$tzid));
$datanode = new ZCiCalDataNode("DTSTART:".ZDateHelper::toICalDateTime($ts));
$tobj->data[$datanode->getName()] = $datanode;
//echo $ts . " => " . ZDateHelper::toICalDateTime($ts) . "<br/>\n"; exit;
$toffset = $lasttransition["offset"];
$thours = intval($toffset/60/60);
$tmins = abs($toffset)/60 - intval(abs($toffset)/60/60)*60;
if($thours < 0)
{
$offset = sprintf("%03d%02d",$thours,$tmins);
}
else
{
$offset = sprintf("+%02d%02d",$thours,$tmins);
}
$datanode = new ZCiCalDataNode("TZOFFSETFROM:".$offset);
$tobj->data[$datanode->getName()] = $datanode;
$toffset = $transition["offset"];
$thours = intval($toffset/60/60);
$tmins = abs($toffset)/60 - intval(abs($toffset)/60/60)*60;
if($thours < 0)
{
$offset = sprintf("%03d%02d",$thours,$tmins);
}
else
{
$offset = sprintf("+%02d%02d",$thours,$tmins);
}
$datanode = new ZCiCalDataNode("TZOFFSETTO:".$offset);
$tobj->data[$datanode->getName()] = $datanode;
$datanode = new ZCiCalDataNode("TZNAME:".$transition["abbr"]);
$tobj->data[$datanode->getName()] = $datanode;
$lasttransition = $transition;
}
}
return $tzobj;
}
}

View file

@ -1,28 +0,0 @@
<?php
/**
* zapcallib.php
*
* @package ZapCalLib
* @author Dan Cogliano <http://zcontent.net>
* @copyright Copyright (C) 2006 - 2017 by Dan Cogliano
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html>
* @link http://icalendar.org/php-library.html
*/
/**
* used by ZapCalLib
* @var integer
*/
define('_ZAPCAL',1);
if(!defined('_ZAPCAL_BASE'))
{
/**
* the base folder of the library
* @var string
*/
define('_ZAPCAL_BASE',__DIR__);
}
require_once(_ZAPCAL_BASE . '/includes/framework.php');