Initial commit

This commit is contained in:
Patrick Schwarz 2021-10-13 14:08:58 +02:00
commit 3a59408fc5
6 changed files with 2988 additions and 0 deletions

218
ICal/Event.php Normal file
View file

@ -0,0 +1,218 @@
<?php
namespace ICal;
class Event
{
// phpcs:disable Generic.Arrays.DisallowLongArraySyntax
const HTML_TEMPLATE = '<p>%s: %s</p>';
/**
* https://www.kanzaki.com/docs/ical/summary.html
*
* @var $summary
*/
public $summary;
/**
* https://www.kanzaki.com/docs/ical/dtstart.html
*
* @var $dtstart
*/
public $dtstart;
/**
* https://www.kanzaki.com/docs/ical/dtend.html
*
* @var $dtend
*/
public $dtend;
/**
* https://www.kanzaki.com/docs/ical/duration.html
*
* @var $duration
*/
public $duration;
/**
* https://www.kanzaki.com/docs/ical/dtstamp.html
*
* @var $dtstamp
*/
public $dtstamp;
/**
* When the event starts, represented as a timezone-adjusted string
*
* @var $dtstart_tz
*/
public $dtstart_tz;
/**
* When the event ends, represented as a timezone-adjusted string
*
* @var $dtend_tz
*/
public $dtend_tz;
/**
* https://www.kanzaki.com/docs/ical/uid.html
*
* @var $uid
*/
public $uid;
/**
* https://www.kanzaki.com/docs/ical/created.html
*
* @var $created
*/
public $created;
/**
* https://www.kanzaki.com/docs/ical/lastModified.html
*
* @var $lastmodified
*/
public $lastmodified;
/**
* https://www.kanzaki.com/docs/ical/description.html
*
* @var $description
*/
public $description;
/**
* https://www.kanzaki.com/docs/ical/location.html
*
* @var $location
*/
public $location;
/**
* https://www.kanzaki.com/docs/ical/sequence.html
*
* @var $sequence
*/
public $sequence;
/**
* https://www.kanzaki.com/docs/ical/status.html
*
* @var $status
*/
public $status;
/**
* https://www.kanzaki.com/docs/ical/transp.html
*
* @var $transp
*/
public $transp;
/**
* https://www.kanzaki.com/docs/ical/organizer.html
*
* @var $organizer
*/
public $organizer;
/**
* https://www.kanzaki.com/docs/ical/attendee.html
*
* @var $attendee
*/
public $attendee;
/**
* Creates the Event object
*
* @param array $data
* @return void
*/
public function __construct(array $data = array())
{
foreach ($data as $key => $value) {
$variable = self::snakeCase($key);
$this->{$variable} = self::prepareData($value);
}
}
/**
* Prepares the data for output
*
* @param mixed $value
* @return mixed
*/
protected function prepareData($value)
{
if (is_string($value)) {
return stripslashes(trim(str_replace('\n', "\n", $value)));
} elseif (is_array($value)) {
return array_map('self::prepareData', $value);
}
return $value;
}
/**
* Returns Event data excluding anything blank
* within an HTML template
*
* @param string $html HTML template to use
* @return string
*/
public function printData($html = self::HTML_TEMPLATE)
{
$data = array(
'SUMMARY' => $this->summary,
'DTSTART' => $this->dtstart,
'DTEND' => $this->dtend,
'DTSTART_TZ' => $this->dtstart_tz,
'DTEND_TZ' => $this->dtend_tz,
'DURATION' => $this->duration,
'DTSTAMP' => $this->dtstamp,
'UID' => $this->uid,
'CREATED' => $this->created,
'LAST-MODIFIED' => $this->lastmodified,
'DESCRIPTION' => $this->description,
'LOCATION' => $this->location,
'SEQUENCE' => $this->sequence,
'STATUS' => $this->status,
'TRANSP' => $this->transp,
'ORGANISER' => $this->organizer,
'ATTENDEE(S)' => $this->attendee,
);
// Remove any blank values
$data = array_filter($data);
$output = '';
foreach ($data as $key => $value) {
$output .= sprintf($html, $key, $value);
}
return $output;
}
/**
* Converts the given input to snake_case
*
* @param string $input
* @param string $glue
* @param string $separator
* @return string
*/
protected static function snakeCase($input, $glue = '_', $separator = '-')
{
$input = preg_split('/(?<=[a-z])(?=[A-Z])/x', $input);
$input = implode($glue, $input);
$input = str_replace($separator, $glue, $input);
return strtolower($input);
}
}

2637
ICal/ICal.php Normal file

File diff suppressed because it is too large Load diff

15
ICal/LICENSE Normal file
View file

@ -0,0 +1,15 @@
The MIT License (MIT)
Copyright (c) 2018
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

15
LICENSE Normal file
View file

@ -0,0 +1,15 @@
The MIT License (MIT)
Copyright (c) 2018
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

39
README.md Normal file
View file

@ -0,0 +1,39 @@
# Hackcal
This script is using [PHP ICS Parser](https://github.com/u01jmg3/ics-parser) to parse ics files, e.g. from Nextcloud. The output is an very simple json for embedding the calender into html websites. Its presorted by days and preformatted to use less js on client side for date interpretation.
---
## Installation
Just copy the files into your php capable webserver directory. Be sure, that the cache folder is writeable by the script and the locale set in the index.php is available on the system.
## Usage
Just call the url. You can filter by categories by adding /?filter=category to the request.
## Example integration using jQuery.
You will need to include a ``<div id="hackcal"></div>`` placeholder in your html page and embed also the jQuery js library.
```
(function($) {
var cal_uri = "https://YOURDOMAIN/hackcal/";
var uri_regex = /(https?:\/\/([-\w\.]+)+(:\d+)?(\/([\w\/\-_\.]*(\?\S+)?)?)?)/ig
$.getJSON(cal_uri, function(data) {
var items = [];
$.each(data, function(date, day) {
items.push("<tr data-date='" + date + "'><th colspan='3'>" + day.name + "</th><th>" + day.weekday + "</th></tr>");
$.each(day.events, function(uid, event) {
event.description = event.description.replace(/\n/g,"<br>").replace(uri_regex, "<a href='$1' target='_blank'>$1</a>");
items.push("<tr data-uid='" + uid + "'><td>" + event.datestr + "</td><td>" + event.summary + "</td><td>" + ((event.location)?event.location:'') + "</td><td>" + ((event.description)?event.description:'') + "</td></tr>");
});
});
$('#hackcal').html("<table><tbody>" + items.join( "" ) + "</tbody></table>");
});
})(jQuery);
```

64
index.php Normal file
View file

@ -0,0 +1,64 @@
<?php
# config
$ical = 'https://cloud.MYURL/remote.php/dav/public-calendars/CALENDARID/?export';
$cachefile = 'cache/hackcal.ics';
$cachetime = 120; // 2 min
setlocale(LC_TIME, "de_DE.utf8");
# requirements
require_once 'ICal/ICal.php';
require_once 'ICal/Event.php';
# Init Calendar
$iCal = new \ICal\ICal();
# Caching and load calendar
if(@filemtime($cachefile) + $cachetime < time()) {
$ical_str = file_get_contents($ical);
file_put_contents($cachefile, $ical_str);
$iCal->initString($ical_str);
} else {
$iCal->initFile($cachefile);
}
//$iCal->initURL($ical);
# Load calendar entries
$events = $iCal->sortEventsWithOrder($iCal->eventsFromInterval('1 month'));
$filter = filter_input(INPUT_GET, 'filter', FILTER_SANITIZE_SPECIAL_CHARS);
$result = [];
foreach ($events as $event) {
if ($filter && strpos($event->categories, $filter) === false) {
continue;
}
$start = new DateTime($event->dtstart);
$end = new DateTime($event->dtend);
$uid = $event->uid;
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt) {
$date = $dt->format("Y-m-d");
$result[$date]["name"] = strftime('%e. %B %Y', $dt->getTimestamp());
$result[$date]["weekday"] = strftime('%A', $dt->getTimestamp());
$result[$date]["events"][$uid]["dtstart"] = $event->dtstart; #TODO: Zeitzone aus lib auslesen
$result[$date]["events"][$uid]["dtend"] = $event->dtend; #TODO: Zeitzone aus lib auslesen
$result[$date]["events"][$uid]["datestr"] = (isset($event->dtstart_array[0]["VALUE"]) && $event->dtstart_array[0]["VALUE"] == 'DATE')?'Ganztägig':$start->format('H:i');
$result[$date]["events"][$uid]["summary"] = $event->summary;
$result[$date]["events"][$uid]["location"] = $event->location;
$result[$date]["events"][$uid]["description"] = $event->description;
$result[$date]["events"][$uid]["categories"] = $event->categories;
}
}
# Allow every page to load this json
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json");
echo json_encode($result, JSON_PRETTY_PRINT);