webseite-krautspace/src/getEvents.php

295 lines
7.8 KiB
PHP

<?php
/**
* file: getEvents.php
* date: 20.11.2022
* user: bernd@nr18.space
*/
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");
/**
* Reads the content of the given ical file and creates with this string a
* vcalendar object.
*
* @return vCalendar object | null
*/
function initCalendar(): ?object {
try {
$data = file_get_contents(ICAL_FILE);
$vcalendar = VObject\Reader::read(
$data
);
return $vcalendar;
} catch (Throwable $th) {
error_log("Failed to read calendar file.");
error_log($th->getMessage(), 0);
return null;
}
}
/**
* Grabs all VEVENTS from vCalendar object, append they to a list and
* returns the list.
*
* @param vCalendar object
* @return list | null
*/
function grabEvents(object $vcalendar): ?array {
$eventlist = [];
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 = " - ";
$uhr = " Uhr";
$komma = ", ";
$dateline = "{$day}{$komma}{$start}{$uhr}{$hyph}";
if ($event->URL != "") {
printHeadline($dateline, $event->SUMMARY, $event->URL);
} else {
printHeadline($dateline, $event->SUMMARY);
}
if ($event->DESCRIPTION != "") {
printDescription($event->DESCRIPTION);
}
if ($event->LOCATION != "") {
printLocation($event->LOCATION);
}
printBottomline();
}
/**
* 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) {
echo("\n<section class='termin'>");
if ($url == null) {
echo("\n<p class='headline'>$dateline$summary</p>");
} else {
echo("\n<p class='headline'>$dateline<a href='$url'>$summary</a></p>");
}
echo("\n<ul class='events'>");
}
/**
* Outputs the events description.
*
* @param string
*/
function printDescription(string $description) {
echo("\n<li>$description</li>");
}
/**
* Outputs the events location.
*
* @param string
*/
function printLocation(string $location) {
$location = makeLinks($location);
echo("\n<li>$location</li>");
}
/**
* Outputs the closing tags for ul and section.
*/
function printBottomline() {
echo("\n</ul>");
echo("\n</section>\n");
}
/**
* Helper function to sort the events chronologically. Compares the first
* entry from the event array (DateTime object).
*
* @param array
* @param array
* @return integer
*/
function compareEventStart(array $event_a, array $event_b): int {
// echo("Compare " . $event_a[0] . " and " . $event_b[0] . "\n");
$a = $event_a[0];
$b = $event_b[0];
return $a <=> $b;
}
/**
* Becomes the description string and makes urls contained in this string
* clickable. If anything goes wrong it returns the origin string.
*
* @param string
* @return string
*/
function makeLinks(string $description) {
try {
$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);
} catch (Throwable $th) {
return $description;
}
}
/**
* Translates the english weekday names to german.
*
* @param string
* @return string | null
*/
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 null;
}
}
///////////////////////////////////////////////////////////////////////////
/// start des programmes
///////////////////////////////////////////////////////////////////////////
/**
* The main function.
*
*/
function printEventList(): bool {
error_log("getEvents called");
date_default_timezone_set("Europe/Berlin");
$today_datetime = new DateTime();
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;
}