-
-
Save furkanmustafa/d9f62450bf7db9b825e3 to your computer and use it in GitHub Desktop.
<?php /* | |
This program is free software: you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program. If not, see <http://www.gnu.org/licenses/>. | |
Furkan Mustafa, 2015.04.06 | |
- Updated 2015.04.09: Limit lines to 70 chars (spec is 75) | |
- Updated 2015.04.26: duplicate letter fixed by @PGallagher69 (Peter Gallagher) | |
- Updated 2015.04.26: Outtlook Invite fixed by @PGallagher69 (Peter Gallagher) | |
- Updated 2015.05.02: Line-limit bug fixed by @waddyvic (Victor Huang) | |
Adapted from: https://gist.github.com/jakebellacera/635416 | |
Also see: https://www.ietf.org/rfc/rfc5545.txt | |
Development Sponsored by 77hz KK, Tokyo, http://77hz.jp | |
Usage: | |
$cal = new SimpleICS(); | |
// $cal->productString = '-//77hz/iFLYER API//'; | |
$cal->addEvent(function($e) { | |
$e->startDate = new DateTime("2015-04-06T10:00:00+09:00"); | |
$e->endDate = new DateTime("2015-04-06T18:30:00+09:00"); | |
$e->uri = 'http://url.to/my/event'; | |
$e->location = 'Tokyo, Event Location'; | |
$e->description = 'ICS Entertainment'; | |
$e->summary = 'Lorem ipsum dolor ics amet, lorem ipsum dolor ics amet, lorem ipsum dolor ics amet, lorem ipsum dolor ics amet'; | |
}); | |
header('Content-Type: '.SimpleICS::MIME_TYPE); | |
if (isset($_GET['download'])) { | |
header('Content-Disposition: attachment; filename=event.ics'); | |
} | |
echo $cal->serialize(); | |
*/ | |
class SimpleICS { | |
use SimpleICS_Util; | |
const MIME_TYPE = 'text/calendar; charset=utf-8'; | |
var $events = []; | |
var $productString = '-//hacksw/handcal//NONSGML v1.0//EN'; | |
static $Template = null; | |
function addEvent($eventOrClosure) { | |
if (is_object($eventOrClosure) && ($eventOrClosure instanceof Closure)) { | |
$event = new SimpleICS_Event(); | |
$eventOrClosure($event); | |
} | |
$this->events[] = $event; | |
return $event; | |
} | |
function serialize() { | |
return $this->filter_linelimit($this->render(self::$Template, $this)); | |
} | |
} | |
class SimpleICS_Event { | |
use SimpleICS_Util; | |
var $uniqueId; | |
var $startDate; | |
var $endDate; | |
var $dateStamp; | |
var $location; | |
var $description; | |
var $uri; | |
var $summary; | |
static $Template; | |
function __construct() { | |
$this->uniqueId = uniqid(); | |
} | |
function serialize() { | |
return $this->render(self::$Template, $this); | |
} | |
} | |
trait SimpleICS_Util { | |
function filter_linelimit($input, $lineLimit = 70) { | |
// go through each line and make them shorter. | |
$output = ''; | |
$line = ''; | |
$pos = 0; | |
while ($pos < strlen($input)) { | |
// find the newline | |
$newLinepos = strpos($input, "\n", $pos + 1); | |
if (!$newLinepos) | |
$newLinepos = strlen($input); | |
$line = substr($input, $pos, $newLinepos - $pos); | |
if (strlen($line) <= $lineLimit) { | |
$output .= $line; | |
} else { | |
// First line cut-off limit is $lineLimit | |
$output .= substr($line, 0, $lineLimit); | |
$line = substr($line, $lineLimit); | |
// Subsequent line cut-off limit is $lineLimit - 1 due to the leading white space | |
$output .= "\n " . substr($line, 0, $lineLimit - 1); | |
while (strlen($line) > $lineLimit - 1){ | |
$line = substr($line, $lineLimit - 1); | |
$output .= "\n " . substr($line, 0, $lineLimit - 1); | |
} | |
} | |
$pos = $newLinepos; | |
} | |
return $output; | |
} | |
function filter_calDate($input) { | |
if (!is_a($input, 'DateTime')) | |
$input = new DateTime($input); | |
else | |
$input = clone $input; | |
$input->setTimezone(new DateTimeZone('UTC')); | |
return $input->format('Ymd\THis\Z'); | |
} | |
function filter_serialize($input) { | |
if (is_object($input)) { | |
return $input->serialize(); | |
} | |
if (is_array($input)) { | |
$output = ''; | |
array_walk($input, function($item) use (&$output) { | |
$output .= $this->filter_serialize($item); | |
}); | |
return trim($output, "\r\n"); | |
} | |
return $input; | |
} | |
function filter_quote($input) { | |
return quoted_printable_encode($input); | |
} | |
function filter_escape($input) { | |
$input = preg_replace('/([\,;])/','\\\$1', $input); | |
$input = str_replace("\n", "\\n", $input); | |
$input = str_replace("\r", "\\r", $input); | |
return $input; | |
} | |
function render($tpl, $scope) { | |
while (preg_match("/\{\{([^\|\}]+)((?:\|([^\|\}]+))+)?\}\}/", $tpl, $m)) { | |
$replace = $m[0]; | |
$varname = $m[1]; | |
$filters = isset($m[2]) ? explode('|', trim($m[2], '|')) : []; | |
$value = $this->fetch_var($scope, $varname); | |
$self = &$this; | |
array_walk($filters, function(&$item) use (&$value, $self) { | |
$item = trim($item, "\t\r\n "); | |
if (!is_callable([ $self, 'filter_' . $item ])) | |
throw new Exception('No such filter: ' . $item); | |
$value = call_user_func_array([ $self, 'filter_' . $item ], [ $value ]); | |
}); | |
$tpl = str_replace($m[0], $value, $tpl); | |
} | |
return $tpl; | |
} | |
function fetch_var($scope, $var) { | |
if (strpos($var, '.')!==false) { | |
$split = explode('.', $var); | |
$var = array_shift($split); | |
$rest = implode('.', $split); | |
$val = $this->fetch_var($scope, $var); | |
return $this->fetch_var($val, $rest); | |
} | |
if (is_object($scope)) { | |
$getterMethod = 'get' . ucfirst($var); | |
if (method_exists($scope, $getterMethod)) { | |
return $scope->{$getterMethod}(); | |
} | |
return $scope->{$var}; | |
} | |
if (is_array($scope)) | |
return $scope[$var]; | |
throw new Exception('A strange scope'); | |
} | |
} | |
SimpleICS::$Template = <<<EOT | |
BEGIN:VCALENDAR | |
VERSION:2.0 | |
PRODID:{{productString}} | |
METHOD:PUBLISH | |
CALSCALE:GREGORIAN | |
{{events|serialize}} | |
END:VCALENDAR | |
EOT; | |
SimpleICS_Event::$Template = <<<EOT | |
BEGIN:VEVENT | |
UID:{{uniqueId}} | |
DTSTART:{{startDate|calDate}} | |
DTSTAMP:{{dateStamp|calDate}} | |
DTEND:{{endDate|calDate}} | |
LOCATION:{{location|escape}} | |
DESCRIPTION:{{description|escape}} | |
URL;VALUE=URI:{{uri|escape}} | |
SUMMARY:{{summary|escape}} | |
END:VEVENT | |
EOT; |
For those having time zone issues - remove the \Z on line ~124 :
return $input->format('Ymd\THis');
\Z will return GMT.
@waddyvic Thanks, merged your changes!
@aaroncrawford Thanks, I'll try to look for some nice way to make it configurable.
Awesome job. Thanks!
Hi,
I'm trying to use this code to create an event calendar for my website.
An ics file is generated, but none of the info passed is in there (only the default values are).
Simply echoing out the passed info before the addEvent call does output all the correct info.
What am I doing wrong?
Thanks for any help!
Code below:
$cal = new SimpleICS();
// $cal->productString = '-//77hz/iFLYER API//';
// Pull events from database
foreach($pages->find("template=event") as $event){
// Convert event start time that was pulled from database to format expected.
$temp = date("Y-m-d",$event->event_start)."T".date("H:i:sP",$event->event_start);
$cal->addEvent(function($e) {
$e->startDate = new DateTime($temp);
$e->endDate = new DateTime($temp);
$e->location = $event->location;
$e->description = $event->description;
$e->summary = $event->summary;
});
header('Content-Type: '.SimpleICS::MIME_TYPE);
if (isset($_GET['download'])) {
header('Content-Disposition: attachment; filename=event.ics');
}
echo $cal->serialize();
}
@kriscreative sorry for late reply, this thing (gist) doesn't have notifications for some reason.
You need to use use
keyword for that to work.
$cal->addEvent(function($e) use ($temp, $event) {
Nice
👍
I would really like to use this code on my website. I'm quite new so I am hoping someone can be kind.
I use a database which only prints to pdf various fields from my database and inside that pdf are appointment details. I want to format the Pdf with a link which includes appointment details which will populate the simpleICS.php function via post method which will then download an ics file for the appointmentee can use.
I presume that the code below goes inside my functions.php and the simpleics.php placed in directory but how do you call that function from the actual page I am send the data to in a url string.
$cal = new SimpleICS();
// $cal->productString = '-//77hz/iFLYER API//';
$cal->addEvent(function($e) {
$e->startDate = new DateTime("2015-04-06T10:00:00+09:00");
$e->endDate = new DateTime("2015-04-06T18:30:00+09:00");
$e->uri = 'http://url.to/my/event';
$e->location = 'Tokyo, Event Location';
$e->description = 'ICS Entertainment';
$e->summary = 'Lorem ipsum dolor ics amet, lorem ipsum dolor ics amet, lorem ipsum dolor ics amet, lorem ipsum dolor ics amet';
});
header('Content-Type: '.SimpleICS::MIME_TYPE);
if (isset($_GET['download'])) {
header('Content-Disposition: attachment; filename=event.ics');
}
echo $cal->serialize();
Is there any way to include an attachment in the ICS file
Hi furkanmustafa,
I was using your SimpleICS class and found a bug. I've forked your code and fixed it. Please feel free to pull the changes back to your code.