neue ordnerstruktur, php-code hinzugefügt
die ordner public und src hinzugefügt, zapcallib.php für iCalendar files hinzugefügt, getContent.php und getEvent.php hinzugefügt
Before Width: | Height: | Size: 311 KiB After Width: | Height: | Size: 311 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 400 B After Width: | Height: | Size: 400 B |
2
public/images/icons/bars.svg
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path fill="#333" d="M1664 1344v128q0 26-19 45t-45 19h-1408q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h1408q26 0 45 19t19 45zm0-512v128q0 26-19 45t-45 19h-1408q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h1408q26 0 45 19t19 45zm0-512v128q0 26-19 45t-45 19h-1408q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h1408q26 0 45 19t19 45z"/></svg>
|
After Width: | Height: | Size: 459 B |
Before Width: | Height: | Size: 772 B After Width: | Height: | Size: 772 B |
2
public/images/icons/users.svg
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="2048" height="1792" viewBox="0 0 2048 1792" xmlns="http://www.w3.org/2000/svg"><path fill="#006400" d="M657 896q-162 5-265 128h-134q-82 0-138-40.5t-56-118.5q0-353 124-353 6 0 43.5 21t97.5 42.5 119 21.5q67 0 133-23-5 37-5 66 0 139 81 256zm1071 637q0 120-73 189.5t-194 69.5h-874q-121 0-194-69.5t-73-189.5q0-53 3.5-103.5t14-109 26.5-108.5 43-97.5 62-81 85.5-53.5 111.5-20q10 0 43 21.5t73 48 107 48 135 21.5 135-21.5 107-48 73-48 43-21.5q61 0 111.5 20t85.5 53.5 62 81 43 97.5 26.5 108.5 14 109 3.5 103.5zm-1024-1277q0 106-75 181t-181 75-181-75-75-181 75-181 181-75 181 75 75 181zm704 384q0 159-112.5 271.5t-271.5 112.5-271.5-112.5-112.5-271.5 112.5-271.5 271.5-112.5 271.5 112.5 112.5 271.5zm576 225q0 78-56 118.5t-138 40.5h-134q-103-123-265-128 81-117 81-256 0-29-5-66 66 23 133 23 59 0 119-21.5t97.5-42.5 43.5-21q124 0 124 353zm-128-609q0 106-75 181t-181 75-181-75-75-181 75-181 181-75 181 75 75 181z"/></svg>
|
After Width: | Height: | Size: 959 B |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
@ -38,7 +38,9 @@
|
||||||
<div id="headline" class="flex-box row">
|
<div id="headline" class="flex-box row">
|
||||||
<div id="header-left" class="flex-box row center">
|
<div id="header-left" class="flex-box row center">
|
||||||
<div id="status-icon" class="icon">
|
<div id="status-icon" class="icon">
|
||||||
<img class="icon-img" src="./images/user-times.svg" />
|
<img class="icon-img"
|
||||||
|
alt="Raumstatus Icon - Raum ist geschlossen"
|
||||||
|
src="./images/user-times.svg" />
|
||||||
</div>
|
</div>
|
||||||
<div id="banner-div" class="flex-box column">
|
<div id="banner-div" class="flex-box column">
|
||||||
<a id="banner" href="#"
|
<a id="banner" href="#"
|
102
src/getContent.php
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* User: vincent
|
||||||
|
* Date: 14/12/2016
|
||||||
|
* Time: 2:55 PM
|
||||||
|
*/
|
||||||
|
/* include_once("config.php"); */
|
||||||
|
|
||||||
|
$status = getStatus();
|
||||||
|
|
||||||
|
function getContent() {
|
||||||
|
$pagename = filter_input(INPUT_GET, 'title', FILTER_SANITIZE_URL);
|
||||||
|
$page = $root_url . '/content/' . $pagename . '.txt';
|
||||||
|
$file = fopen($page, 'rb');
|
||||||
|
if($file) {
|
||||||
|
echo stream_get_contents($file);
|
||||||
|
fclose($file);
|
||||||
|
} else {
|
||||||
|
echo "Page not found";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return string[][]
|
||||||
|
*/
|
||||||
|
function apiRequest()
|
||||||
|
{
|
||||||
|
$ch = curl_init('https://status.kraut.space/api');
|
||||||
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
|
||||||
|
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
|
||||||
|
$result = curl_exec($ch);
|
||||||
|
curl_close($ch);
|
||||||
|
return json_decode($result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
function getStatus(): bool
|
||||||
|
{
|
||||||
|
try { return apiRequest()['state']['open']; }
|
||||||
|
catch (Error $e) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
function getKrautButtonColor($status) {
|
||||||
|
if ($status) {
|
||||||
|
echo "<img src='./img/icons/users.svg' id='krauticon'>";
|
||||||
|
} else {
|
||||||
|
echo "<img src='./img/icons/user-times.svg' id='krauticon'>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getKrautStatus($status) {
|
||||||
|
if ($status) {
|
||||||
|
echo "Raum ist offen";
|
||||||
|
} else {
|
||||||
|
echo "Raum ist geschlossen";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getKrautSidebar($status)
|
||||||
|
{
|
||||||
|
if ($status) {
|
||||||
|
echo <<<END
|
||||||
|
<div class="sidebar-heading">
|
||||||
|
<div class="icondiv"><img src="./img/icons/users.svg" class="icon" alt="Person"></div>
|
||||||
|
<h4>Raum ist geöffnet</h4>
|
||||||
|
<p>Schaut einfach vorbei</p>
|
||||||
|
</div>
|
||||||
|
END;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
echo <<<END
|
||||||
|
<div class="sidebar-heading">
|
||||||
|
<div class="icondiv"><img src="./img/icons/user-times.svg" class="icon" alt="niemand"></div>
|
||||||
|
<h4>Niemand ist im Raum</h4>
|
||||||
|
<p>Keine Hackerseele anwesend</p>
|
||||||
|
</div>
|
||||||
|
END;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getKrautButton(bool $status)
|
||||||
|
{
|
||||||
|
if ($status) {
|
||||||
|
echo <<<END
|
||||||
|
<div id="roombutton" class="krautopen">
|
||||||
|
<img src="./img/icons/users.svg" id="roomicon" alt="Person">
|
||||||
|
<p>Raum ist geöffnet</p>
|
||||||
|
</div>
|
||||||
|
END;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
echo <<<END
|
||||||
|
<div id="roombutton" class="krautclose">
|
||||||
|
<img src="./img/icons/user-times.svg" id="roomicon" alt="niemand">
|
||||||
|
<p>Raum ist geschlossen</p>
|
||||||
|
</div>
|
||||||
|
END;
|
||||||
|
}
|
||||||
|
}
|
487
src/getEvents.php
Normal file
|
@ -0,0 +1,487 @@
|
||||||
|
<?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;
|
||||||
|
}
|
127
src/lib/README.md
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
# 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
|
||||||
|
|
568
src/lib/includes/date.php
Normal file
|
@ -0,0 +1,568 @@
|
||||||
|
<?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);
|
||||||
|
}
|
||||||
|
}
|
32
src/lib/includes/framework.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?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');
|
986
src/lib/includes/ical.php
Normal file
|
@ -0,0 +1,986 @@
|
||||||
|
<?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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
6
src/lib/includes/index.html
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
796
src/lib/includes/recurringdate.php
Normal file
|
@ -0,0 +1,796 @@
|
||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
142
src/lib/includes/timezone.php
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
<?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;
|
||||||
|
}
|
||||||
|
}
|
28
src/lib/zapcallib.php
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
<?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');
|
||||||
|
|