Compare commits

...

29 commits

Author SHA1 Message Date
Thomas Lotze 9e56a06bc9 calendar update script: put calendar URL in variable 2023-10-20 00:19:40 +02:00
Ludwig Behm b09a5b9aa8
README: added install instructions 2023-10-19 23:47:55 +02:00
Ludwig Behm 8e9e6d37fc
add nextcloud public calendar export 2023-10-19 23:29:05 +02:00
Ludwig Behm 01fcc976ba
add nginx.conf 2023-10-19 23:24:29 +02:00
Thomas Lotze 888dd7bab7 Anfahrt: StraBa- und Buslinien korrigiert 2023-10-16 06:58:40 +02:00
bernd cdf90ee14f beschreibung freifunk angepasst 2023-09-26 21:27:40 +02:00
bernd 435e3d759d jitsi link hinzu 2023-09-26 21:22:06 +02:00
bernd 82c8219a94 link zu twitter entfernt 2023-09-26 21:10:02 +02:00
bernd b005287947 typo korrigiert 2023-09-26 20:53:47 +02:00
bernd 20cb8bd7f7 link zum bbb hinzu 2023-09-26 20:50:40 +02:00
bernd a718964080 Fehler im Terminfile korrigiert 2023-09-22 23:42:10 +02:00
bernd 3f21025450 neuer Termin ins Kalenderfile 2023-09-22 21:47:10 +02:00
bernd 56d5ef7f04 neuer termin ins kalenderfile 2023-09-22 20:31:40 +02:00
Thomas Lotze f790745848 Kalender: Wiederholungsregel für Plenum repariert 2023-09-21 16:23:42 +02:00
Thomas Lotze 636faa2984 Istanbul -> "König 2 Döner" 2023-09-06 18:42:13 +02:00
Thomas Lotze 9995f16c6e Freifunk-Treff zu Terminen hinzu 2023-09-06 15:13:05 +02:00
Thomas Lotze 9e8bb28d7e Plenum zum Kalender hinzu 2023-09-06 10:10:50 +02:00
bernd d33426976c logmeldungen auskommentiert 2023-09-05 21:38:55 +02:00
Thomas Lotze 208e740f6e Jitsi -> Videokonferenz (ist grade ein BBB) 2023-09-05 17:57:02 +02:00
Thomas Lotze bcba6e51c0 Wegbeschreibung noch mal unabhängig vom Wegweiser im Haus formuliert 2023-09-04 16:32:57 +02:00
Thomas Lotze 8e093baf55 Jitsi-Link zu den Kommunikationsmöglichkeiten hinzugefügt 2023-09-03 22:57:48 +02:00
Thomas Lotze 5b9d3b80c3 Beschreibung der Treffpunkte verbessert, Ort für Termine angepaßt 2023-09-03 21:38:29 +02:00
Thomas Lotze 2414e055b7 Zugangsbeschreibung zum Raum verbessert 2023-09-03 21:18:25 +02:00
Thomas Lotze 148621a706 Titel und Beschreibung der Brettspielrunde angepaßt 2023-09-03 21:12:09 +02:00
bernd efd93a1088 typo im readme korrigiert 2023-08-25 17:34:37 +02:00
+++ 96f9038932 Merge branch 'main' of https://git.kraut.space/Krautspace/webseite-krautspace
veraenderungen auf dem server uebernommen
2022-11-26 15:45:34 +01:00
+++ efcdf21fdd verzeichnis mit der zcap lib entfernt 2022-11-26 15:36:36 +01:00
+++ 576f1b7c23 readme hinzugefuegt 2022-11-26 15:27:23 +01:00
+++ 78b461609f kalenderdatei ueberarbeitet, getEvents auf VObject von sabre.io umgestellt 2022-11-26 15:08:50 +01:00
17 changed files with 496 additions and 3150 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
events.json

28
README.md Normal file
View file

@ -0,0 +1,28 @@
# Webseite
Das Repository enthält die Webseite das Vereins "Hackspace Jena". Der größte
Teil der Webseite ist statisches HTML, ergänzt um einige dynamische
Elemente zur Anzeige des Raumstatuses und der aktuellen Termine.
## Installation
Zum Betrieb der Webseite ist ein Webserver und PHP notwendig. Die
Auswertung der Termine erfolgt mittels der VObject Bibliothek von
[https://sabre.io](https://sabre.io), welche auch in Nextcloud enthalten
ist. Debian stellt die Bibliothe in dem Paket php-sabre-vobject bereit. Nach
der Installation und Konfiguration des Websevers inklusive PHP wird das Repo
in das Dokumentroot des Webservers kopiert.
### Installationsschritte
```bash
# install calendar event exporter
sudo install -o0 -g0 -m444 etc/systemd/calendar-events-exporter.* /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now calendar-events-exporter.timer
# install nginx config
sudo install -o0 -g0 -m444 etc/nginx/kraut.space.conf /etc/nginx/sites-available/
sudo ln -s ../sites-available/kraut.space.conf /etc/nginx/sites-enabled/
sudo systemctl reload nginx
```

View file

@ -0,0 +1,7 @@
#!/usr/bin/env bash
CAL_URL="https://cloud.kraut.space/remote.php/dav/public-calendars/2EkPGt3PF6WwYsA3?export&expand=1&start=$(date -d '' +%s)&end=$(date -d 'next month' +%s)"
curl -sH "Accept: application/calendar+json" "${CAL_URL}" \
| jq -r '.[2] | map({_type: .[0]} + (.[1] | map({key: .[0], value: .[3]}) | from_entries))' \
> ./events.json

123
etc/nginx/kraut.space.conf Normal file
View file

@ -0,0 +1,123 @@
server {
listen 0.0.0.0:80;
listen [::]:80;
server_name kraut.space www.kraut.space;
access_log /var/log/nginx/kraut.space_access.log ano;
error_log /var/log/nginx/kraut.space_error.log;
include /etc/nginx/letsencrypt.conf;
error_page 404 =301 https://wiki.kraut.space$request_uri;
location / {
return 301 https://$host$request_uri?;
}
location /chaostreff {
return 301 https://kabi.blue/join/krautspace;
}
location /lug {
return 301 https://kabi.blue/join/krautspace;
}
location /plenum {
return 301 https://kabi.blue/join/krautspace;
}
location /btw {
return 301 https://auth.kabi.tk/index.php/apps/bbb/b/d8Er44TQYC9BJYmp;
}
location /nocovid {
return 301 https://wiki.kraut.space/blog:content:vortrag_von_viola_priesemann;
}
location /brettspielerei {
return 301 https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:brettspielerei;
}
location /gamingamfreitag {
return 301 https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:gaming;
}
location /kinderbasteln {
return 301 https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:kinderbasteln;
}
location /iran {
return 301 https://wiki.kraut.space/blog:content:about_the_current_situation_in_iran_-_report_and_insight_by_locals_and_q_a_live_from_tehran;
}
}
server {
listen 0.0.0.0:443 ssl http2;
listen [::]:443 ssl http2;
ssl_certificate /var/lib/dehydrated/certs/kraut.space/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/kraut.space/privkey.pem;
server_name kraut.space www.kraut.space;
access_log /var/log/nginx/kraut.space_access.log ano;
error_log /var/log/nginx/kraut.space_error.log;
add_header Strict-Transport-Security max-age=15768000; # six months
include /etc/nginx/letsencrypt.conf;
if ($host = www.kraut.space) {
return 301 https://wiki.kraut.space$request_uri;
}
root /var/www/kraut.space/public/;
# falls es mal (global) an sein sollte
autoindex off;
index index.php;
client_max_body_size 15M;
client_body_buffer_size 128k;
location = /robots.txt { log_not_found off; }
location = /favicon.ico { log_not_found off; }
location ~ /\. { deny all; }
location ~ ~$ { deny all; }
error_page 404 =301 http://wiki.kraut.space$request_uri;
location /chaostreff {
return 301 https://kabi.blue/join/krautspace;
}
location /lug {
return 301 https://kabi.blue/join/krautspace;
}
location /plenum {
return 301 https://kabi.blue/join/krautspace;
}
location /btw {
return 301 https://auth.kabi.tk/index.php/apps/bbb/b/d8Er44TQYC9BJYmp;
}
location /nocovid {
return 301 https://wiki.kraut.space/blog:content:vortrag_von_viola_priesemann;
}
location /brettspielerei {
return 301 https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:brettspielerei;
}
location /gamingamfreitag {
return 301 https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:gaming;
}
location /kinderbasteln {
return 301 https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:kinderbasteln;
}
location /iran {
return 301 https://wiki.kraut.space/blog:content:about_the_current_situation_in_iran_-_report_and_insight_by_locals_and_q_a_live_from_tehran;
}
# führe PHP-Script aus
location ~ \.php$ {
include fastcgi_params;
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_intercept_errors on;
fastcgi_pass unix:/etc/alternatives/php-fpm.sock;
# entferne Header "X-Powered-By: PHP/5.4.40-1~dotdeb+wheezy.1"
fastcgi_hide_header "X-Powered-By";
fastcgi_read_timeout 120;
}
include snippets/xmpp.conf;
include snippets/chat2.conf;
include snippets/chat1.conf;
}

View file

@ -0,0 +1,12 @@
[Unit]
Description=Dumps calendar events from nextcloud into usable json
After=network.target
[Service]
Type=simple
ExecStart=/usr/bin/bash /var/www/kraut.space/bin/calendar-events-exporter.sh
User=www-data
Group=www-data
WorkingDirectory=/var/www/kraut.space

View file

@ -0,0 +1,9 @@
[Unit]
Description=timer for automatic refresh of calendar export
[Timer]
# execute at the second minute of every hour, and repeat every 5 minutes
OnCalendar=*:2/5
[Install]
WantedBy=timers.target

View file

@ -1,4 +1,4 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="de">
<head>
@ -154,18 +154,17 @@
<section>
<p>
Mit Begin der Corona-Pandemie waren auch wir gezwungen unsere
Aktivit&auml;ten in einen virtuellen Raum zu verlegen. Dazu
betreiben wir zwei wöchentliche virtuelle Treffpunkte. Daneben
nutzen wir zur Kommunikation hauptsächlich einen Raum in der
Matrix. Du kannst dort gern Kontakt zu uns aufnehmen.
Unser haupts&auml;chlicher Treffpunkt ist der Krautspace in der
Krautgasse 26 im Zentrum von Jena. Nachdem wir wegen der
Corona-Pandemie vor&uuml;bergehend auf virtuelle R&auml;ume
ausweichen mussten, treffen sich mittlerweile alle unsere Runden
wieder vor Ort.
</p>
<p>
Anfang Juni 2022 haben wir die bisherige Mailingliste durch ein
<a class="extern" href="https://senf.kraut.space">Forum</a>
abgel&ouml;st. Alle Runden treffen sich wieder live in der
Krautgasse. Bei Chaostreff und LUG bieten wir weiterhin die
M&ouml;glichkeit per Jitsi teilzunehmen.
Bei Chaostreff und LUG bieten wir weiterhin die M&ouml;glichkeit,
per Videokonferenz teilzunehmen. Daneben nutzen wir zur Kommunikation
haupts&auml;chlich einen Raum in der Matrix. Du kannst dort gern
Kontakt zu uns aufnehmen.
</p>
<div class="flex-box column with-aside">
@ -213,15 +212,6 @@
<li>Webchat: <a href="https://kraut.space/chat">kraut.space/chat</a></li>
</ul>
</div>
<div class="sb-item">
<h4 class="aside">Twitter</h4>
<ul class="aside">
<li>
<a rel="me"
href="https://twitter.com/hackspacejena">twitter.com/hackspacejena</a>
</li>
</ul>
</div>
<div class="sb-item">
<h4 class="aside">Mastodon</h4>
<ul class="aside">
@ -231,17 +221,26 @@
</li>
</ul>
</div>
<div class="sb-item">
<h4 class="aside">Videokonferenz</h4>
<ul class="aside">
<li>
<a rel="me"
href="https://kraut.space/lug">https://kraut.space/lug</a>
</li>
</ul>
</div>
</aside>
</div>
<section>
</div> <!-- end class panel-wrapper content-overlay -->
<div id="verein" class="panel-wrapper content-overlay">
<h2>Verein</h2>
<section>
<p>
Der Verein Hackspace Jena e.&#x202f;V. fungiert als Tr&auml;gerverein für den
@ -272,7 +271,7 @@
gegen&uuml;ber den Vorstand des Vereines Im Idealfall &uuml;ber
das ausgef&uuml;llte <a class="extern"
href="https://wiki.kraut.space/_media/verein:mitgliedsantrag.pdf">Mitgliedsformular</a>,
gesendet an die Postadresse.
gesendet an die Postadresse.
</p>
<h3>Kontaktmöglichkeiten</h3>
@ -303,7 +302,7 @@
</section>
</div> <!-- end class panel-wrapper content-overlay -->
<div id="raum" class="panel-wrapper content-overlay">
<h2>Raum</h2>
@ -313,14 +312,17 @@
Unser physischer Raum liegt mitten im Zentrum Jenas und ist sehr
gut zu erreichen. Die n&auml;chsten Haltestellen des
&ouml;ffentlichen Nahverkehrs befinden sich ca. 50 Meter entfernt.
Das sind die Stra&szlig;enbahnen der Linie 16, sowie die Busse der
Linie 5.
Das sind die Stra&szlig;enbahnen der Linie 5, sowie die Busse der
Linie 16. Von der Krautgasse aus muss man den Durchgang am Café Rossi
passieren und dann den Eingang links neben dem „König 2 Döner“
nehmen. Im Haus geht es eine Treppe hoch und dann nach rechts über
den Balkon; ganz hinten ist es dann die rechte Tür.
</p>
<div id="map-box" class="flex-box column with-aside">
<div id="map">
<a class="extern"
href="http://www.openstreetmap.org/node/1875593753">
<img src="./images/lageplan.svg"
<img src="./images/lageplan.svg"
alt="Lageplan des Krautspace"
title="Karte auf Open Street Map öffnen">
</a>
@ -386,7 +388,7 @@
<li><span class="no-wrap">Bank: Ethikbank Eisenberg</li>
</ul>
</div> <!-- end class sub-panel -->
</div> <!-- end class flex-box center-content max-width footer-box -->
</footer>

View file

@ -11,46 +11,61 @@ TZOFFSETTO:+0100
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
SUMMARY:"Plenum"
UID:0000000001@kraut.space
CLASS:PUBLIC
DESCRIPTION:Plenum unseres Vereins
DTEND;TZID=CET:20230907T235900
DTSTAMP;TZID=CET:20230907T125900
DTSTART;TZID=CET:20230907T200000
GEO:50.9292035\,11.5825763
LOCATION:Vor Ort im Krautspace und online unter https://kraut.space/lug
URL:https://wiki.kraut.space/hswiki:verein:plenum:start
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:WKST=MO;FREQ=MONTHLY;BYDAY=1TH
END:VEVENT
BEGIN:VEVENT
SUMMARY:"Chaostreff"
UID:0000000002@kraut.space
CLASS:PUBLIC
DESCRIPTION:"Offene Runde"
DESCRIPTION:Offene Runde
DTEND;TZID=CET:20200623T235900
DTSTAMP;TZID=CET:20200623T125900
DTSTART;TZID=CET:20200623T200000
GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena"
URL;VALUE="HTTPS://kraut.space/chaostreff"
LOCATION:Vor Ort im Krautspace und online unter https://kraut.space/chaostreff
URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:chaostreff:start
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY
END:VEVENT
BEGIN:VEVENT
SUMMARY:"Brettspielrunde"
SUMMARY:"Brettspielerei"
UID:0000000003@kraut.space
CLASS:PUBLIC
DESCRIPTION:"Brettspielerei"
DTEND;TZID=CET:20220518T235900
DTSTAMP;TZID=CET:20220518T125900
DTSTART;TZID=CET:20220518T200000
DESCRIPTION:Moderne Gesellschaftsspiele zu wechselnden Themen
DTSTAMP;TZID=CET:20221116T125900
DTSTART;TZID=CET:20221116T200000
DTEND;TZID=CET:20221116T235900
GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena"
URL;VALUE="HTTPS://kraut.space/brettspielerei"
LOCATION:Vor Ort im Krautspace
URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:brettspielerei
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,36,38,40,42,44,46,48,50,52
RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=WE;BYWEEKNO=2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,36,38,40,42,44,46,48,50,52
END:VEVENT
BEGIN:VEVENT
SUMMARY:"Linux User Group"
UID:0000000004@kraut.space
CLASS:PUBLIC
DESCRIPTION:"Alles rund um Linux"
DESCRIPTION:Alles rund um Linux
DTEND;TZID=CET:20200625T235900
DTSTAMP;TZID=CET:20200623T125900
DTSTART;TZID=CET:20200625T200000
GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena"
URL;VALUE="HTTPS://kraut.space/lug"
LOCATION:Vor Ort im Krautspace und online unter https://kraut.space/lug
URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:lug:start
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY
@ -59,13 +74,13 @@ BEGIN:VEVENT
SUMMARY:"Gaming am Freitag"
UID:0000000005@kraut.space
CLASS:PUBLIC
DESCRIPTION:"Der Stammtisch für Videospielkultur"
DESCRIPTION:Der Stammtisch für Videospielkultur
DTEND;TZID=CET:20220527T235900
DTSTAMP;TZID=CET:20220527T125900
DTSTART;TZID=CET:20220527T190000
GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena"
URL;VALUE="HTTPS://kraut.space/gamingamfreitag"
LOCATION:Vor Ort im Krautspace
URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:gaming
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:office@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53
@ -74,15 +89,41 @@ BEGIN:VEVENT
SUMMARY:"Kinderbasteln"
UID:0000000006@kraut.space
CLASS:PUBLIC
DESCRIPTION:"Natur und Technik für Vor- und Grundschulkinder"
DESCRIPTION:Natur und Technik für Vor- und Grundschulkinder
DTEND;TZID=CET:20220611T120000
DTSTAMP;TZID=CET:20220611T100000
DTSTART;TZID=CET:20220611T100000
GEO:50.9292035\,11.5825763
LOCATION:"Krautgasse 26\, 07743 Jena"
URL;VALUE="HTTPS://kraut.space/kinderbasteln"
LOCATION:Vor Ort im Krautspace
URL:https://wiki.kraut.space/hswiki:veranstaltungen:regelmaessige:kinderbasteln
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:basteln@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=MO;BYDAY=FR;BYWEEKNO=1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39,41,43,45,47,49,51,53
RRULE:WKST=MO;FREQ=WEEKLY;BYDAY=2SA,4SA
END:VEVENT
BEGIN:VEVENT
SUMMARY:"Freifunk-Treff"
UID:0000000007@kraut.space
CLASS:PUBLIC
DESCRIPTION:Für alle, die sich für Freifunk interessieren
DTEND;TZID=CET:20221211T200000
DTSTAMP;TZID=CET:20221211T100000
DTSTART;TZID=CET:20221211T190000
GEO:50.9292035\,11.5825763
LOCATION:Online im Jitsi unter der URL https://meet.weimarnetz.de/freifunk-jena und vor Ort im Krautspace.
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:basteln@kraut.space
REFRESH-INTERVAL;VALUE=DURATION:P1W
RRULE:WKST=MO;FREQ=WEEKLY;BYDAY=TU
END:VEVENT
BEGIN:VEVENT
SUMMARY:"Ausstellung: und gäbs die Logik nicht, dann gäbs mich auch nicht"
UID:0000000008@kraut.space
CLASS:PUBLIC
DESCRIPTION:Wir laden euch zu einem Gespräch und Präsentation mit dem Künstler Mondstern ein. Mondstern widmet sich mit seinen Werken der Welt der freien Software.
DTSTART;TZID=CET:20230928T200000
DTEND;TZID=CET:20230928T220000
DTSTAMP;TZID=CET:20230922T203000
GEO:50.9292035\,11.5825763
LOCATION:BigBlueButton unter der URL https://kabi.blue/join/krautspace/
ORGANIZER;CN="VORSTAND HACKSPACE JENA E.V.":MAILTO:basteln@kraut.space
END:VEVENT
END:VCALENDAR

View file

@ -1,344 +1,192 @@
<?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.
* file: getEvents.php
* date: 20.11.2022
* user: bernd@nr18.space
*/
require_once("../src/lib/zapcallib.php");
ini_set('log_errors', 1);
ini_set('error_log', '../log/events.log');
error_reporting(E_ALL & ~E_NOTICE & ~E_WARNING & ~E_DEPRECATED);
use Sabre\VObject;
include '/usr/share/php/Sabre/VObject/autoload.php';
define ("ICAL_FILE", "krautspace.ics");
function printEventList(): bool
{
/**
* Die Startfuktion für die Ausgabe der Termine als Liste in index.php.
* 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.
* Reads the content of the given ical file and creates with this string a
* vcalendar object.
*
* @return vCalendar object | null
*/
$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;
}
function initCalendar(): ?object {
try {
$data = file_get_contents(ICAL_FILE);
$vcalendar = VObject\Reader::read(
$data
);
return $vcalendar;
} catch (Throwable $th) {
error_log("Failed to read calendar file.");
error_log($th->getMessage(), 0);
return null;
}
/**
* 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.
* Grabs all VEVENTS from vCalendar object, append they to a list and
* returns the list.
*
* @param vCalendar object
* @return list | null
*/
{
date_default_timezone_set("UTC");
$helper = new ZDateHelper();
function grabEvents(object $vcalendar): ?array {
$eventlist = [];
try {
foreach ($vcalendar->VEVENT as $event) {
$eventlist[] = $event;
}
} catch (Throwable $th) {
error_log("Failed to grab evens.");
error_log($th->getMessage(), 0);
return null;
}
return $eventlist;
}
/**
* Becomes an instance from recurrency rule iterator and an datetime object.
* Until the iterators date is in future, we call for the next date.
*
* @param iterator object
* @param datetime
* @return datetime | null
*/
function getNextDate(object $rriterator, DateTime $now): ?DateTime {
foreach ($rriterator as $item) {
if ($item > $now) {
return $item;
}
}
return null;
}
/**
* Main function to display the events.
*
* @param array
* @param object
*/
function printEvent(array $eventarray, object $date_helper) {
$start_datetime = $eventarray[0];
$event = $eventarray[1];
$day = toGerman($start_datetime->format("l"));
$start = $start_datetime->format("d.m.Y H:i");
$hyph = " - ";
$uhr = " Uhr";
$komma = ", ";
$dateline = "{$day}{$komma}{$start}{$uhr}{$hyph}";
$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;
if ($event->URL != "") {
printHeadline($dateline, $event->SUMMARY, $event->URL);
} else {
printHeadline($dateline, $event->SUMMARY);
}
if ($event->DESCRIPTION != "") {
printDescription($event->DESCRIPTION);
}
if ($event->LOCATION != "") {
printLocation($event->LOCATION);
}
printBottomline();
}
/**
* Die Startfuktion für die Ausgabe der Termine als Tabelle in termine.php
* Outputs the opening tags for section and ul, the date and time, and
* summary. ifi a url is given, the summary is a link to the corresponding
* wiki page.
*
* @param string
* @param string
*/
function printEventTable(): bool
{
$events = initEvents();
printTableHead();
foreach ($events as $event)
{
$event_array = getEventArray($event);
printTableItem($event_array);
function printHeadline(string $dateline, string $summary, string $url=null) {
echo("\n<section class='termin'>");
if ($url == null) {
echo("\n<p class='headline'>$dateline$summary</p>");
} else {
echo("\n<p class='headline'>$dateline<a href='$url'>$summary</a></p>");
}
echo "\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;
echo("\n<ul class='events'>");
}
/**
* Funktionen, die von beiden Ausgaben benutzt werden.
* Outputs the events description.
*
* @param string
*/
/**
* @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 printDescription(string $description) {
echo("\n<li>$description</li>");
}
function initCalendar(): ?ZCiCal
/**
* Erstellt das Kalenderobjekt vom Typ ZCiCal.
* Gibt das Kalenderobjekt oder Null zurück.
* Outputs the events location.
*
* @param string
*/
{
$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 printLocation(string $location) {
$location = makeLinks($location);
echo("\n<li>$location</li>");
}
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.
* Outputs the closing tags for ul and section.
*/
{
$eventCount = $iCalObj->countEvents();
if (!isset ($eventCount))
{
printError("Fehler beim Parsen des Kalenders");
return null;
}
// echo "<p>$eventCount anstehende Events</p>";
return $eventCount;
function printBottomline() {
echo("\n</ul>");
echo("\n</section>\n");
}
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.
* Helper function to sort the events chronologically. Compares the first
* entry from the event array (DateTime object).
*
* @param array
* @param array
* @return integer
*/
$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 compareEventStart(array $event_a, array $event_b): int {
// echo("Compare " . $event_a[0] . " and " . $event_b[0] . "\n");
$a = $event_a[0];
$b = $event_b[0];
return $a <=> $b;
}
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.
* Becomes the description string and makes urls contained in this string
* clickable. If anything goes wrong it returns the origin string.
*
* @param string
* @return string
*/
/**
* @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'];
}
function makeLinks(string $description) {
try {
$reg_pattern = "/(((http|https)\:\/\/)|(www\.))[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,5}(\:[a-zA-Z0-9]+)?(\/\S*)?/";
return $new = preg_replace($reg_pattern, '<a href="$0" target="_blank" rel="noopener noreferrer">$0</a>', $description);
} catch (Throwable $th) {
return $description;
}
return $event_array;
}
function printError($errMsg)
{
echo "\n\r<p>$errMsg</p>\n\r";
return true;
}
function toGerman(string $day): string
/**
* Translates the english weekday names to german.
*
* @param string
* @return string | null
*/
function toGerman(string $day): ?string
{
switch ($day)
{
@ -357,131 +205,91 @@ function toGerman(string $day): string
case 'Sunday':
return 'Sonntag';
default:
return '?';
return null;
}
}
function lowerURL(string $url): string
{
$old = array('HTTPS', 'HTTP', 'FTP', 'WWW', 'SSH');
$new = array('https', 'http', 'ftp', 'www', 'ssh');
$new_url = str_replace($old, $new, $url);
return $new_url;
}
function calculateNextStart(int $unix_start, string $rrule): int
/**
* 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;
}
///////////////////////////////////////////////////////////////////////////
/// start des programmes
///////////////////////////////////////////////////////////////////////////
/**
* 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.
* The main function.
*
* @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;
function printEventList(): bool {
// error_log("getEvents called");
date_default_timezone_set("Europe/Berlin");
$today_datetime = new DateTime();
date_time_set($today_datetime, 0, 0, 0, 0);
$date_helper = new VObject\DateTimeParser();
$eventlist = [];
$next_events = [];
// einlesen der kalenderdatei
$vcalendar = initCalendar();
if ($vcalendar == null) {
error_log("getEvents unsuccessful terminated");
return false;
}
// die events aus dem kalender herausziehen
$eventlist = grabEvents($vcalendar);
if ($eventlist == null) {
error_log("grabEvent returns null");
return false;
}
elseif (count($eventlist) == 0) {
echo("\n<p>Keine Termine gefunden</p>\n");
return false;
}
// durch die liste der events laufen. wir holen uns den starttermin und
// wandeln ihn in ein datetime objekt um. liegt das in der vergangenheit
// und der termin hat eine rrule, holen wir uns einen iterator über die
// rrule (dazu brauchen wir die uid) und versuche den nächsten gültigen
// termin zu bekommen. gibt es einen gültigen termin, wird das event mit
// dem neuen starttermin an die liste der relevanten termine angehängt.
// ist der starttermin von anfang an in der zukunft, dann wird er
// natürlich auch angehängt.
foreach ($eventlist as $event) {
$next_event = [];
$e_uid = $event->UID;
$e_start = $event->DTSTART;
$e_summary = $event->SUMMARY;
$e_description = $event->DESCRIPTION;
$e_location = $event->LOCATION;
$e_url = $event->URL;
$start_datetime = $date_helper->parseDateTime($e_start);
if ($start_datetime < $today_datetime) {
if (isset($event->RRULE)) {
$rriter = new VObject\RecurrenceIterator($vcalendar, $e_uid);
$start_datetime = getNextDate($rriter, $today_datetime);
if ($start_datetime == null) {
continue;
} else {
array_push($next_events, array($start_datetime, $event));
}
}
} else {
array_push($next_events, array($start_datetime, $event));
}
}
// liste der anstehenden events nach dem begin sortieren
usort($next_events, "compareEventStart");
// die sortierte liste ausgeben
foreach ($next_events as $event) {
printEvent($event, $date_helper);
}
// error_log("getEvents successful terminated");
return true;
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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