webseite-krautspace/src/getEvents.php

488 lines
12 KiB
PHP
Raw Normal View History

<?php
/**
* Datei: getEvents.php
* Autor: bernd@nr18.space
* Letze Änderung: 08.07.2020
* 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");
function printEventList(): bool
{
/**
* Die Startfuktion für die Ausgabe der Termine als Liste in index.php.
* Nach erfolgreicher initialisierung läuft die Funktion durch das Array
* der Events (ZCalNode´s vom Typ 'VEVENT') ruft für jedes Element erst
* die Funktion zur Umwandlung in ein assoziatives Array und dann die
* Ausgabefunktion auf. Gibt einen Boolean zurück.
*/
$events = initEvents();
$helper = new ZDateHelper();
date_default_timezone_set("UTC");
/**
* Startdatum für wiederkehrende Termine aktualisieren
*
* @var ZCiCalNode $event
*/
foreach ($events as $event)
{
/**
* @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
* Zeitangabe des iCal-Formates in Datum, Uhrzeit und Wochentag umgewandelt.
* Anschließend erfolgt die Ausgabe der einzelnen Teile.
*/
{
date_default_timezone_set("UTC");
$helper = new ZDateHelper();
$hyph = " - ";
$uhr = " Uhr";
$komma = ", ";
$event_start = $event->data['DTSTART']->value[0];
$event_url = lowerURL($event->data['URL']->parameter['value']);
$event_title = $event->data['SUMMARY']->value[0];
$event_location = trim($event->data['LOCATION']->value[0], '"');
$event_descr = trim($event->data['DESCRIPTION']->value[0], '"');
$unix = $helper->fromiCaltoUnixDateTime($event_start);
$event_date = date('d.m.Y', $unix);
$event_time = date('H:i', $unix);
$event_day = toGerman(date('l', $unix));
$dateline = "{$event_day}{$komma}{$event_date}{$hyph}{$event_time}{$uhr}";
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
*/
function printEventTable(): bool
{
$events = initEvents();
printTableHead();
foreach ($events as $event)
{
$event_array = getEventArray($event);
printTableItem($event_array);
}
echo "\t</tbody>\n";
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.
*/
/**
* @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.
* Gibt das Kalenderobjekt oder Null zurück.
*/
{
$iCalFile = '../public/krautspace.ics';
$iCalString = file_get_contents($iCalFile);
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
* Kalenderobjekt enthält. Im Fehlerfall wird Null zurück
* gegeben.
*/
{
$eventCount = $iCalObj->countEvents();
if (!isset ($eventCount))
{
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
* 'VEVENT' ein. Gibt ein Array mit Objekten vom Typ 'ZCiCalNode' zurück.
* Im Fehlerfall wird Null zurück gegeben.
*/
$events = [];
if (isset ($iCalObj->tree->child))
{
foreach ($iCalObj->tree->child as $node)
{
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
* daraus die gewünschten Elemente. Bildet daraus ein zweidimmensionales
* assoziatives Array. Gibt dieses Array zurück.
* Wird derzeit nur von der tabellarischen Ausgabe referenziert, welche
+ momentan nicht genutzt wird.
*/
/**
* @var ZCiCalNode $node
* @var ZCiCalDataNode $event
*/
$event = $node->data;
$event_array = [];
$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)
{
echo "\n\r<p>$errMsg</p>\n\r";
return true;
}
function toGerman(string $day): string
{
switch ($day)
{
case 'Monday':
return 'Montag';
case 'Tuesday':
return 'Dienstag';
case 'Wednesday':
return 'Mittwoch';
case 'Thursday':
return 'Donnerstag';
case 'Friday':
return 'Freitag';
case 'Saturday':
return 'Samstag';
case 'Sunday':
return 'Sonntag';
default:
return '?';
}
}
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
/**
* 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
* 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
{
$a = $event_a->data['DTSTART']->value[0];
$b = $event_b->data['DTSTART']->value[0];
return $a <=> $b;
}