From 2008e71e4a7d25302fca4d69596a7295cec5aa15 Mon Sep 17 00:00:00 2001 From: Christoph Haas Date: Mon, 12 Nov 2012 22:57:50 +0000 Subject: [PATCH] todo: calender choosing, timezone, improve parser --- js/dialogs/ImportContentPanel.js | 10 +- js/dialogs/ImportPanel.js | 299 ++++++++++++++++++++++ js/plugin.calendarimporter.js | 26 +- manifest.xml | 2 + php/ical/calendar - Kopie.txt | 216 ++++++++++++++++ php/ical/calendar.txt | 33 +++ php/ical/class.icalparser.php | 410 +++++++++++++++++++++++++++++++ php/upload.php | 34 +++ 8 files changed, 1011 insertions(+), 19 deletions(-) create mode 100644 js/dialogs/ImportPanel.js create mode 100644 php/ical/calendar - Kopie.txt create mode 100644 php/ical/calendar.txt create mode 100644 php/ical/class.icalparser.php create mode 100644 php/upload.php diff --git a/js/dialogs/ImportContentPanel.js b/js/dialogs/ImportContentPanel.js index 88f7608..e4acc09 100644 --- a/js/dialogs/ImportContentPanel.js +++ b/js/dialogs/ImportContentPanel.js @@ -24,12 +24,10 @@ Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.c width : 400, height : 300, //Add panel - items : [/* + items : [ { - xtype : 'owncloudrcvattachment.folderpanel', - ref : 'treePanel', - response : config.record - }*/ + xtype : 'calendarimporter.importpanel' + } ] }); @@ -38,4 +36,4 @@ Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel = Ext.extend(Zarafa.c }); -Ext.reg('calendarimportercontentpanel' ,Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel); \ No newline at end of file +Ext.reg('calendarimporter.contentpanel' ,Zarafa.plugins.calendarimporter.dialogs.ImportContentPanel); \ No newline at end of file diff --git a/js/dialogs/ImportPanel.js b/js/dialogs/ImportPanel.js new file mode 100644 index 0000000..710f6a3 --- /dev/null +++ b/js/dialogs/ImportPanel.js @@ -0,0 +1,299 @@ +Ext.namespace("Zarafa.plugins.calendarimporter.dialogs"); + +/** + * @class Zarafa.plugins.calendarimporter.dialogs.ImportPanel + * @extends Ext.form.FormPanel + */ +Zarafa.plugins.calendarimporter.dialogs.ImportPanel = Ext.extend(Ext.form.FormPanel, { + + /** + * @constructor + * @param {object} config + */ + constructor : function(config) + { + config = config || {}; + var self = this; + Ext.apply(config, { + xtype : 'calendarimporter.importpanel', + layout : { + type : 'form', + align : 'stretch' + }, + anchor : '100%', + bodyStyle : 'background-color: inherit;', + defaults : { + border : true, + bodyStyle : 'background-color: inherit; padding: 3px 0px 3px 0px; border-style: none none solid none;' + }, + items : [ + this.createSelectBox(), + this.initForm() + ], + buttons: [ + this.createSubmitButton(), + this.createCancelButton() + ] + }); + + Zarafa.plugins.calendarimporter.dialogs.ImportPanel.superclass.constructor.call(this, config); + }, + + /** + * Init embedded form, this is the form that is + * posted and contains the attachments + * @private + */ + initForm : function() + { + return { + xtype: 'form', + ref: 'addFormPanel', + layout : 'column', + fileUpload: true, + autoWidth: true, + autoHeight: true, + border: false, + bodyStyle: 'padding: 5px;', + defaults: { + anchor: '95%', + border: false, + bodyStyle: 'padding: 5px;' + }, + items: [this.createUploadField()] + }; + }, + + /** + * Init embedded form, this is the form that is + * posted and contains the attachments + * @private + */ + createGrid : function(eventdata) { + + if(eventdata == null) { + var parsedData = [ + ]; + } else { + var parsedData = new Array(eventdata.events.length); + + for(var i=0; i < eventdata.events.length; i++) { + parsedData[i] = new Array(eventdata.events[i]["SUMMARY"], parseInt(eventdata.events[i]["DTSTART"]), parseInt(eventdata.events[i]["DTEND"]), eventdata.events[i]["LOCATION"], eventdata.events[i]["DESCRIPTION"]); + } + } + + // create the data store + var store = new Ext.data.ArrayStore({ + fields: [ + {name: 'title'}, + {name: 'start'}, + {name: 'end'}, + {name: 'location'}, + {name: 'description'} + ], + data: parsedData + }); + + return { + xtype: 'grid', + ref: 'eventgrid', + id: 'eventgrid', + columnWidth: 1.0, + store: store, + width: '100%', + height: 300, + title: 'Select events to import', + frame: true, + colModel: new Ext.grid.ColumnModel({ + defaults: { + width: 300, + sortable: true + }, + columns: [ + {id: 'title', header: 'Title', width: 300, sortable: true, dataIndex: 'title'}, + {header: 'startDate', width: 150, sortable: true, dataIndex: 'start'}, + {header: 'endDate', width: 150, sortable: true, dataIndex: 'end'}, + {header: 'startDate', width: 150, sortable: true, dataIndex: 'location'}, + {header: 'endDate', width: 150, sortable: true, dataIndex: 'description'} + ] + }), + sm: new Ext.grid.RowSelectionModel({multiSelect:true}) + } + }, + + createSelectBox: function() { + ctx = container.getContextByName('calendar'); + model = ctx.getModel(); + defaultFolder = model.getDefaultFolder(); + subFolders = defaultFolder.getChildren(); + + var myStore = new Ext.data.ArrayStore({ + fields: ['calendar_id', 'calendar_displayname'], + idIndex: 0 // id for each record will be the first element + }); + + /* Calendar Record holds the name and real name of the calender */ + var CalendarRecord = Ext.data.Record.create([ + {name: 'realname', type: "string"}, + {name: 'displayname', type: "string"} + ]); + + /* Store the default folder */ + var myNewRecord = new CalendarRecord({ + realname: defaultFolder.getDefaultFolderKey(), + displayname: defaultFolder.getDisplayName() + }); + myStore.add(myNewRecord); + + for(i=0;i js/plugin.calendarimporter.js js/dialogs/ImportContentPanel.js + js/dialogs/ImportPanel.js js/plugin.calendarimporter.js js/dialogs/ImportContentPanel.js + js/dialogs/ImportPanel.js resources/css/calendarimporter.css diff --git a/php/ical/calendar - Kopie.txt b/php/ical/calendar - Kopie.txt new file mode 100644 index 0000000..0f693d4 --- /dev/null +++ b/php/ical/calendar - Kopie.txt @@ -0,0 +1,216 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:Testkalender +X-WR-TIMEZONE:Europe/Berlin +X-WR-CALDESC:Nur zum testen vom Google Kalender +BEGIN:VEVENT +DTSTART:20121105T090000Z +DTEND:20121107T173000Z +DTSTAMP:20110121T195741Z +UID:15lc1nvupht8dtfiptenljoiv4@google.com +CREATED:20110121T195616Z +DESCRIPTION:This is a short description\nwith a new line. Some "special" 's + igns' may be interesting, too. +LAST-MODIFIED:20110121T195729Z +LOCATION:Kansas +SEQUENCE:2 +STATUS:CONFIRMED +SUMMARY:My Holidays +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110112 +DTEND;VALUE=DATE:20110116 +DTSTAMP:20110121T195741Z +UID:1koigufm110c5hnq6ln57murd4@google.com +CREATED:20110119T142901Z +DESCRIPTION:Project xyz Review Meeting Minutes\n + Agenda\n1. Review of project version 1.0 requirements.\n2. + Definition + of project processes.\n3. Review of project schedule.\n + Participants: John Smith, Jane Doe, Jim Dandy\n-It was + decided that the requirements need to be signed off by + product marketing.\n-Project processes were accepted.\n + -Project schedule needs to account for scheduled holidays + and employee vacation time. Check with HR for specific + dates.\n-New schedule will be distributed by Friday.\n- + Next weeks meeting is cancelled. No meeting until 3/23. +LAST-MODIFIED:20110119T152216Z +LOCATION: +SEQUENCE:2 +STATUS:CONFIRMED +SUMMARY:test 11 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110118 +DTEND;VALUE=DATE:20110120 +DTSTAMP:20110121T195741Z +UID:4dnsuc3nknin15kv25cn7ridss@google.com +CREATED:20110119T142059Z +DESCRIPTION: +LAST-MODIFIED:20110119T142106Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 9 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110117 +DTEND;VALUE=DATE:20110122 +DTSTAMP:20110121T195741Z +UID:h6f7sdjbpt47v3dkral8lnsgcc@google.com +CREATED:20110119T142040Z +DESCRIPTION: +LAST-MODIFIED:20110119T142040Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY: +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110117 +DTEND;VALUE=DATE:20110118 +DTSTAMP:20110121T195741Z +UID:up56hlrtkpqdum73rk6tl10ook@google.com +CREATED:20110119T142034Z +DESCRIPTION: +LAST-MODIFIED:20110119T142034Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 8 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110118 +DTEND;VALUE=DATE:20110120 +DTSTAMP:20110121T195741Z +UID:8ltm205uhshsbc1huv0ooeg4nc@google.com +CREATED:20110119T142014Z +DESCRIPTION: +LAST-MODIFIED:20110119T142023Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 7 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110119 +DTEND;VALUE=DATE:20110121 +DTSTAMP:20110121T195741Z +UID:opklai3nm8enffdf5vpna4o5fo@google.com +CREATED:20110119T141918Z +DESCRIPTION: +LAST-MODIFIED:20110119T142005Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 5 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110119 +DTEND;VALUE=DATE:20110120 +DTSTAMP:20110121T195741Z +UID:kmbj764g57tcvua11hir61c4b8@google.com +CREATED:20110119T141923Z +DESCRIPTION: +LAST-MODIFIED:20110119T141923Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 6 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110119 +DTEND;VALUE=DATE:20110120 +DTSTAMP:20110121T195741Z +UID:shvr7hvqdag08vjqlmj5lj0i2s@google.com +CREATED:20110119T141913Z +DESCRIPTION: +LAST-MODIFIED:20110119T141913Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 4 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110119 +DTEND;VALUE=DATE:20110120 +DTSTAMP:20110121T195741Z +UID:77gpemlb9es0r0gtjolv3mtap0@google.com +CREATED:20110119T141909Z +DESCRIPTION: +LAST-MODIFIED:20110119T141909Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 3 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110119 +DTEND;VALUE=DATE:20110120 +DTSTAMP:20110121T195741Z +UID:rq8jng4jgq0m1lvpj8486fttu0@google.com +CREATED:20110119T141904Z +DESCRIPTION: +LAST-MODIFIED:20110119T141904Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 2 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20110119 +DTEND;VALUE=DATE:20110120 +DTSTAMP:20110121T195741Z +UID:dh3fki5du0opa7cs5n5s87ca00@google.com +CREATED:20110119T141901Z +DESCRIPTION: +LAST-MODIFIED:20110119T141901Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:test 1 +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:20400201 +DTEND;VALUE=DATE:20400202 +DTSTAMP:20400101T195741Z +UID:dh3fki5du0opa7cs5n5s87ca01@google.com +CREATED:20400101T141901Z +DESCRIPTION: +LAST-MODIFIED:20400101T141901Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Year 2038 problem test +TRANSP:TRANSPARENT +END:VEVENT +BEGIN:VEVENT +DTSTART;VALUE=DATE:19410512 +DTEND;VALUE=DATE:19410512 +DTSTAMP:19410512T195741Z +UID:dh3fki5du0opa7cs5n5s87ca02@google.com +CREATED:20400101T141901Z +DESCRIPTION: +LAST-MODIFIED:20400101T141901Z +LOCATION: +SEQUENCE:0 +STATUS:CONFIRMED +SUMMARY:Before 1970-Test: Konrad Zuse invents the Z3, the first digital Computer +TRANSP:TRANSPARENT +END:VEVENT +END:VCALENDAR diff --git a/php/ical/calendar.txt b/php/ical/calendar.txt new file mode 100644 index 0000000..64a717b --- /dev/null +++ b/php/ical/calendar.txt @@ -0,0 +1,33 @@ +BEGIN:VCALENDAR +PRODID:-//Google Inc//Google Calendar 70.9054//EN +VERSION:2.0 +CALSCALE:GREGORIAN +METHOD:PUBLISH +X-WR-CALNAME:Testkalender +X-WR-TIMEZONE:Europe/Berlin +X-WR-CALDESC:Nur zum testen vom Google Kalender +BEGIN:VEVENT +DTSTART;VALUE=DATE:20121112 +DTEND;VALUE=DATE:20121116 +DTSTAMP:20110121T195741Z +UID:1koigufm110c5hnq6ln57murd4@google.com +CREATED:20110119T142901Z +DESCRIPTION:Project xyz Review Meeting Minutes\n + Agenda\n1. Review of project version 1.0 requirements.\n2. + Definition + of project processes.\n3. Review of project schedule.\n + Participants: John Smith, Jane Doe, Jim Dandy\n-It was + decided that the requirements need to be signed off by + product marketing.\n-Project processes were accepted.\n + -Project schedule needs to account for scheduled holidays + and employee vacation time. Check with HR for specific + dates.\n-New schedule will be distributed by Friday.\n- + Next weeks meeting is cancelled. No meeting until 3/23. +LAST-MODIFIED:20110119T152216Z +LOCATION: +SEQUENCE:2 +STATUS:CONFIRMED +SUMMARY:test 11 +TRANSP:TRANSPARENT +END:VEVENT +END:VCALENDAR diff --git a/php/ical/class.icalparser.php b/php/ical/class.icalparser.php new file mode 100644 index 0000000..31f687f --- /dev/null +++ b/php/ical/class.icalparser.php @@ -0,0 +1,410 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @version SVN: 13 + * @example $ical = new ical('MyCal.ics'); + * print_r( $ical->events() ); + */ + +/** + * This is the iCal-class + * + * @param {string} filename The name of the file which should be parsed + * @constructor + */ +class ICal +{ + /* How many ToDos are in this ical? */ + public /** @type {int} */ $todo_count = 0; + + /* How many events are in this ical? */ + public /** @type {int} */ $event_count = 0; + + /* The parsed calendar */ + public /** @type {Array} */ $cal; + + /* Error message store... null default */ + public /** @type {String} */ $errors; + + /* Which keyword has been added to cal at last? */ + private /** @type {string} */ $_lastKeyWord; + + /** + * Creates the iCal-Object + * + * @param {string} $filename The path to the iCal-file + * + * @return Object The iCal-Object + */ + public function __construct($filename) + { + if (!$filename) { + $this->errors = "No filename specified"; + return false; + } + + $lines = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) { + $this->errors = "Not a valid ical file"; + return false; + } else { + // TODO: Fix multiline-description problem (see http://tools.ietf.org/html/rfc2445#section-4.8.1.5) + foreach ($lines as $line) { + $line = trim($line); + $add = $this->keyValueFromString($line); + if ($add === false) { + $this->addCalendarComponentWithKeyAndValue($type, false, $line); + continue; + } + + list($keyword, $value) = $add; + + switch ($line) { + // http://www.kanzaki.com/docs/ical/vtodo.html + case "BEGIN:VTODO": + $this->todo_count++; + $type = "VTODO"; + break; + + // http://www.kanzaki.com/docs/ical/vevent.html + case "BEGIN:VEVENT": + //echo "vevent gematcht"; + $this->event_count++; + $type = "VEVENT"; + break; + + //all other special strings + case "BEGIN:VCALENDAR": + case "BEGIN:DAYLIGHT": + // http://www.kanzaki.com/docs/ical/vtimezone.html + case "BEGIN:VTIMEZONE": + case "BEGIN:STANDARD": + $type = $value; + break; + case "END:VTODO": // end special text - goto VCALENDAR key + case "END:VEVENT": + case "END:VCALENDAR": + case "END:DAYLIGHT": + case "END:VTIMEZONE": + case "END:STANDARD": + $type = "VCALENDAR"; + break; + default: + $this->addCalendarComponentWithKeyAndValue($type, + $keyword, + $value); + break; + } + } + return $this->cal; + } + } + + /** + * Creates the iCal-Object + * + * @param {string} $filecontent The content of the iCal-file + * + * @return Object The iCal-Object + */ + public function setContent($filecontent) + { + if (!$filecontent) { + $this->errors = "No filecontent"; + return false; + } + + $lines = explode("\n", $filecontent); + if (stristr($lines[0], 'BEGIN:VCALENDAR') === false) { + $this->errors = "Not a valid ical file"; + return false; + } else { + // TODO: Fix multiline-description problem (see http://tools.ietf.org/html/rfc2445#section-4.8.1.5) + foreach ($lines as $line) { + $line = trim($line); + $add = $this->keyValueFromString($line); + if ($add === false) { + $this->addCalendarComponentWithKeyAndValue($type, false, $line); + continue; + } + + list($keyword, $value) = $add; + + switch ($line) { + // http://www.kanzaki.com/docs/ical/vtodo.html + case "BEGIN:VTODO": + $this->todo_count++; + $type = "VTODO"; + break; + + // http://www.kanzaki.com/docs/ical/vevent.html + case "BEGIN:VEVENT": + //echo "vevent gematcht"; + $this->event_count++; + $type = "VEVENT"; + break; + + //all other special strings + case "BEGIN:VCALENDAR": + case "BEGIN:DAYLIGHT": + // http://www.kanzaki.com/docs/ical/vtimezone.html + case "BEGIN:VTIMEZONE": + case "BEGIN:STANDARD": + $type = $value; + break; + case "END:VTODO": // end special text - goto VCALENDAR key + case "END:VEVENT": + case "END:VCALENDAR": + case "END:DAYLIGHT": + case "END:VTIMEZONE": + case "END:STANDARD": + $type = "VCALENDAR"; + break; + default: + $this->addCalendarComponentWithKeyAndValue($type, + $keyword, + $value); + break; + } + } + return $this->cal; + } + } + + /** + * Add to $this->ical array one value and key. + * + * @param {string} $component This could be VTODO, VEVENT, VCALENDAR, ... + * @param {string} $keyword The keyword, for example DTSTART + * @param {string} $value The value, for example 20110105T090000Z + * + * @return {None} + */ + public function addCalendarComponentWithKeyAndValue($component, + $keyword, + $value) + { + if ($keyword == false) { + $keyword = $this->last_keyword; + + switch ($component) { + case 'VEVENT': + if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { + $ts = $this->iCalDateToUnixTimestamp($value); + $value = $ts * 1000; + } + $value = str_replace("\\n", "\n", $value); + $value = $this->cal[$component][$this->event_count - 1] + [$keyword].$value; + break; + case 'VTODO' : + $value = $this->cal[$component][$this->todo_count - 1] + [$keyword].$value; + break; + } + } + + if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { + $keyword = explode(";", $keyword); + $keyword = $keyword[0]; // remove additional content like VALUE=DATE + } + + switch ($component) { + case "VTODO": + $this->cal[$component][$this->todo_count - 1][$keyword] = $value; + //$this->cal[$component][$this->todo_count]['Unix'] = $unixtime; + break; + case "VEVENT": + if (stristr($keyword, "DTSTART") or stristr($keyword, "DTEND")) { + $ts = $this->iCalDateToUnixTimestamp($value); + $value = $ts * 1000; + } + $value = str_replace("\\n", "\n", $value); + $this->cal[$component][$this->event_count - 1][$keyword] = $value; + break; + default: + $this->cal[$component][$keyword] = $value; + break; + } + $this->last_keyword = $keyword; + } + + /** + * Get a key-value pair of a string. + * + * @param {string} $text which is like "VCALENDAR:Begin" or "LOCATION:" + * + * @return {array} array("VCALENDAR", "Begin") + */ + public function keyValueFromString($text) + { + preg_match("/(^[^a-z:]+)[:]([\w\W]*)/", $text, $matches); + error_log("Matching: " . count($matches) . " " . $text); + if (count($matches) == 0) { + return false; + } + $matches = array_splice($matches, 1, 2); + return $matches; + } + + /** + * Return Unix timestamp from ical date time format + * + * @param {string} $icalDate A Date in the format YYYYMMDD[T]HHMMSS[Z] or + * YYYYMMDD[T]HHMMSS + * + * @return {int} + */ + public function iCalDateToUnixTimestamp($icalDate) + { + $icalDate = str_replace('T', '', $icalDate); + $icalDate = str_replace('Z', '', $icalDate); + + $pattern = '/([0-9]{4})'; // 1: YYYY + $pattern .= '([0-9]{2})'; // 2: MM + $pattern .= '([0-9]{2})'; // 3: DD + $pattern .= '([0-9]{0,2})'; // 4: HH + $pattern .= '([0-9]{0,2})'; // 5: MM + $pattern .= '([0-9]{0,2})/'; // 6: SS + preg_match($pattern, $icalDate, $date); + + // Unix timestamp can't represent dates before 1970 + if ($date[1] <= 1970) { + return false; + } + // Unix timestamps after 03:14:07 UTC 2038-01-19 might cause an overflow + // if 32 bit integers are used. + $timestamp = mktime((int)$date[4], + (int)$date[5], + (int)$date[6], + (int)$date[2], + (int)$date[3], + (int)$date[1]); + return $timestamp; + } + + /** + * Returns an array of arrays with all events. Every event is an associative + * array and each property is an element it. + * + * @return {array} + */ + public function events() + { + $array = $this->cal; + return $array['VEVENT']; + } + + /** + * Returns an array of calendar types. + * + * @return {array} + */ + public function calendar() + { + $array = $this->cal; + return $array['VCALENDAR']; + } + + /** + * Returns a boolean value whether thr current calendar has events or not + * + * @return {boolean} + */ + public function hasEvents() + { + return ( count($this->events()) > 0 ? true : false ); + } + + /** + * Returns false when the current calendar has no events in range, else the + * events. + * + * Note that this function makes use of a UNIX timestamp. This might be a + * problem on January the 29th, 2038. + * See http://en.wikipedia.org/wiki/Unix_time#Representing_the_number + * + * @param {boolean} $rangeStart Either true or false + * @param {boolean} $rangeEnd Either true or false + * + * @return {mixed} + */ + public function eventsFromRange($rangeStart = false, $rangeEnd = false) + { + $events = $this->sortEventsWithOrder($this->events(), SORT_ASC); + + if (!$events) { + return false; + } + + $extendedEvents = array(); + + if ($rangeStart !== false) { + $rangeStart = new DateTime(); + } + + if ($rangeEnd !== false or $rangeEnd <= 0) { + $rangeEnd = new DateTime('2038/01/18'); + } else { + $rangeEnd = new DateTime($rangeEnd); + } + + $rangeStart = $rangeStart->format('U'); + $rangeEnd = $rangeEnd->format('U'); + + + + // loop through all events by adding two new elements + foreach ($events as $anEvent) { + $timestamp = $this->iCalDateToUnixTimestamp($anEvent['DTSTART']); + if ($timestamp >= $rangeStart && $timestamp <= $rangeEnd) { + $extendedEvents[] = $anEvent; + } + } + + return $extendedEvents; + } + + /** + * Returns sorted events + * + * @param {array} $events An array with events. + * @param {array} $sortOrder Either SORT_ASC, SORT_DESC, SORT_REGULAR, + * SORT_NUMERIC, SORT_STRING + * + * @return {array} + */ + public function sortEventsWithOrder($events, $sortOrder = SORT_ASC) + { + $extendedEvents = array(); + + // loop through all events by adding two new elements + foreach ($events as $anEvent) { + if (!array_key_exists('UNIX_TIMESTAMP', $anEvent)) { + $anEvent['UNIX_TIMESTAMP'] = + $this->iCalDateToUnixTimestamp($anEvent['DTSTART']); + } + + if (!array_key_exists('REAL_DATETIME', $anEvent)) { + $anEvent['REAL_DATETIME'] = + date("d.m.Y", $anEvent['UNIX_TIMESTAMP']); + } + + $extendedEvents[] = $anEvent; + } + + foreach ($extendedEvents as $key => $value) { + $timestamp[$key] = $value['UNIX_TIMESTAMP']; + } + array_multisort($timestamp, $sortOrder, $extendedEvents); + + return $extendedEvents; + } +} +?> diff --git a/php/upload.php b/php/upload.php new file mode 100644 index 0000000..9a4f427 --- /dev/null +++ b/php/upload.php @@ -0,0 +1,34 @@ + + * @license http://www.opensource.org/licenses/mit-license.php MIT License + * @version SVN: 13 + */ + + function respondJSON($arr) { + + echo json_encode($arr); + } + + require_once("ical/class.icalparser.php"); + + $filepath = $_FILES['icsdata']['tmp_name']; + + if(is_readable ($filepath)) { + $ical = new ICal($filepath); // do not init with a file.. we set the content later + + if(isset($ical->errors)) { + respondJSON(array ('success'=>false,'errors'=>array ('parser'=>$ical->errors, 'type'=>'parser'))); + } else if(!$ical->hasEvents()) { + respondJSON(array ('success'=>false,'errors'=>array ('parser'=>"No events in ics file", 'type'=>'parser'))); + } else { + respondJSON(array ('success'=>true, 'response'=>array ('tmp_file'=>$filepath, 'calendar'=>$ical->calendar(), 'events'=>$ical->events()))); + } + } else { + respondJSON(array ('success'=>false,'errors'=>array ('reader'=>"File could not be read by server", 'type'=>'reader'))); + } +?> \ No newline at end of file