Dynamic .ics from php not updating in Google Calendar - php
I have been trying to create a .ics page in php which is to be added to Google Calendar via "Add by URL" in order for me to retrieve events from a database and present them in the calendar.
I have searched around a while on SO and found another post which was very helpful in getting started, but I have now hit a snag which doesn't seem to affect those with similar code. Post can be found here.
So, my problem is that I cannot seem to get the Google Calendar to update my page, as if it has cached the page within the calendar. So when I add another VEVENT to the page it does not update the calendar.
When creating the file it generates the correct format for an *.ics file. Format shown below.
If I go directly to the page I do get prompted to download the file, which works to import into GC, and if I add the same code to a different page, for instance changing the pages name from cal.php to cal2.php, will make GC read all of the events whilst when I simply add the same URL as before it does not pick up on any changes made to the file.
Anyone have any idea to why this isn't updating?
Others who have had similar problems have solved this by adding a UID to their VEVENT, which did not solve this anything for me...
Format generated
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:17d88c861131ec62f18835cdd4eb7d0c#yourhost.test
DTSTAMP:20110901T092002Z
DTSTART:20110925T170000Z
DTEND:20110928T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
BEGIN:VEVENT
UID:00813115d1a2d21447eb11ded3ba9020#yourhost.test
DTSTAMP:20110901T092002Z
DTSTART:20110929T170000Z
DTEND:20110930T035959Z
SUMMARY:Camping Trip
END:VEVENT
BEGIN:VEVENT
UID:1f18d85fe516d684536129ed066e7d4f#yourhost.test
DTSTAMP:20110901T092002Z
DTSTART:20110914T170000Z
DTEND:20110915T035959Z
SUMMARY:Testing new Event
END:VEVENT
END:VCALENDAR
Code used
<?php
header("Content-Type: text/Calendar");
header("Content-Disposition: inline; filename=\"calendar.ics\"");
echo "BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
UID:" . md5(uniqid(mt_rand(), true)) . "#yourhost.test
DTSTAMP:" . gmdate('Ymd').'T'. gmdate('His') . "Z
DTSTART:20110925T170000Z
DTEND:20110928T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
BEGIN:VEVENT
UID:" . md5(uniqid(mt_rand(), true)) . "#yourhost.test
DTSTAMP:" . gmdate('Ymd').'T'. gmdate('His') . "Z
DTSTART:20110929T170000Z
DTEND:20110930T035959Z
SUMMARY:Camping Trip
END:VEVENT
BEGIN:VEVENT
UID:" . md5(uniqid(mt_rand(), true)) . "#yourhost.test
DTSTAMP:" . gmdate('Ymd').'T'. gmdate('His') . "Z
DTSTART:20110914T170000Z
DTEND:20110915T035959Z
SUMMARY:Testing new Event
END:VEVENT
END:VCALENDAR";
?>
csanyigabor is correct. Also you must ensure that the UID's are the same so that the application will match the events.
This question and answer here deals with cancelations, but the principle is the same
How to cancel an calendar event using ics files?
I think you should use the SEQUENCE attribute in VEVENT and it should increases after every change.
#csanyigabor is right and so is #anmari, but a few other tips I picked up. When you are building your ICS file, like anmari said, make sure your UID's are consistent every time your feed is sync'd. I had made it create a hash based on some text provided by the user (bad, bad idea. Shame on myself 5 years ago when I built it).
If you go here -> https://www.rfc-editor.org/rfc/rfc5545 (and a few updated points here -> https://www.rfc-editor.org/rfc/rfc7986 ) it gives some great outlines on stuff that's helpful. Specifically 3.8.7.4. Sequence Number and it outlines what should be criteria for a new sequence.
Description: When a calendar component is created, its sequence
number is 0. It is monotonically incremented by the "Organizer's"
CUA each time the "Organizer" makes a significant revision to the
calendar component.
Also helpful is what it says about UID in 3.8.4.7. Unique Identifier
Description: The "UID" itself MUST be a globally unique identifier.
The generator of the identifier MUST guarantee that the identifier
is unique. There are several algorithms that can be used to
accomplish this. A good method to assure uniqueness is to put the
domain name or a domain literal IP address of the host on which
the identifier was created on the right-hand side of an "#", and
on the left-hand side, put a combination of the current calendar
date and time of day (i.e., formatted in as a DATE-TIME value)
along with some other currently unique (perhaps sequential)
identifier available on the system (for example, a process id
number). Using a DATE-TIME value on the left-hand side and a
domain name or domain literal on the right-hand side makes it
possible to guarantee uniqueness since no two hosts should be
using the same domain name or IP address at the same time. Though
other algorithms will work, it is RECOMMENDED that the right-hand
side contain some domain identifier (either of the host itself or
otherwise) such that the generator of the message identifier can
guarantee the uniqueness of the left-hand side within the scope of
that domain.
Example: The following is an example of this property:
UID:19960401T080045Z-4000F192713-0052#host1.com
Related
.ics export from Google calendar has wrong time
Using PHP,mysql, i am trying to export/import calendar data from/to Google calendar. The importing (to Google) works fine. I can export data from my mysql table and create an ics file then import it into Google Calendar, using a specific timezone. The problem is when i am exporting the data... Google changes the timezone for every event. I'll give an example. When i am importing the data to Google Calender, a typical event looks like this: BEGIN:VEVENT UID:20 DTSTAMP:20160328T222128 DTSTART:20160328T033000 DTEND:20160328T043000 LOCATION: DESCRIPTION:My description here SUMMARY:Event number 3 END:VEVENT The StartTime is 033000 and EndTime is 043000. Everything is fine, i see an event starting at 3:30am and ending at 4:30am. When i am exporting my calendar from Google this event looks like this: BEGIN:VEVENT DTSTART:20160328T003000Z DTEND:20160328T013000Z DTSTAMP:20160328T194501Z UID:20 CREATED:20160328T224357Z DESCRIPTION:My description here LAST-MODIFIED:20160328T194410Z LOCATION: SEQUENCE:0 STATUS:CONFIRMED SUMMARY:Event number 3 TRANSP:OPAQUE END:VEVENT StartTime 003000 EndTime 013000 Both .ics files have X-WR-TIMEZONE:Europe/Athens Why on earth is Google sending me back Zulu time, instead of what i am seeing in the calendar ? I dont want to handle timezones. This means if a person from the Usa uploads an .ics file to the custom calendar i am making, it will insert wrong times in the database. Is it possible, Google Calendar to export exactly the hours a person sees in his calendar? If i cant avoid this, what is the easiest way to convert this Z time into the proper time ? (the time that person sees in Google Calendar) Thanks!
I assume that, since you are able to insert the date/times into a database, you are able to parse the format of DTSTART. If not, I recommend taking a look at sabre/vobject for a full-on iCalendar parser. So after parsing DTSTART, make sure you parse this into a php DateTime object. This object makes it really easy to convert to different timezones: $dt = new \DateTime($input); $dt->setTimeZone(new DateTimeZone('Europe/Athens')); After that, your $dt contains your start time, converted to your timezone. Here's an example with vobject: $cal = Sabre\VObject\Reader::read($iCalendarData); // DTSTART property $dtstart = $cal->VEVENT->DTSTART; // Turn into DateTime object $dateTime = $dtstart->getDateTime(); // Convert to your timezone $newDateTime = $dateTime->setTimeZone('Europe/Athens'); Disclaimer: I'm the main author for vobject.
iCalendar exclude date range
I am working on school timetables system and currently developing a PHP script that would allow exporting the data in iCalendar (.ics) format. The target use-case of exporting the data would be importing it into Google Calendar. Since there are holidays inbetween the semesters in our school (specified by start and end date), what would be the best way to exclude the holidays from the iCalendar recurrence rule (RRULE)?. Keep in mind that there can be many different schedules in one export. I did try using EXDATE;VALUE=DATE:YYYYMMDD,YYYYMMDD,YYYYMMDD... with all holiday days, but Google Calendar didn't exclude the dates, probably because schedules also have time attached and therefore they don't match. I'll also provide the data in iCalendar format with one of the events, with holiday days excluded one by one (the one that didn't work) BEGIN:VCALENDAR PRODID:-//Gregor Eesmaa/NONSGML Poska timetables//ET VERSION:2.0 METHOD:PUBLISH BEGIN:VEVENT UID:schedule-1442#jpg.tartu.ee SUMMARY:French DESCRIPTION: LOCATION:Room 210 DTSTART:20151215T123000Z DTEND:20151215T134500Z RRULE:FREQ=WEEKLY;UNTIL=20160211;INTERVAL=1;BYDAY=TU EXDATE;VALUE=DATE:20151223,20151224,20151225,20151226,20151227,20151228,20151229,20151230,20151231,20160101,20160102,20160103,20160104,20160105,20160106,20160107,20160108,20160109,20160110,20160319,20160320,20160321,20160322,20160323,20160324,20160325,20160326,20160327,20160415,20160416,20160417,20160418,20160607,20160608,20160609,20160610,20160611,20160612,20160613,20160614,20160615,20160616,20160617,20160618,20160619,20160620,20160621,20160622,20160623,20160624,20160625,20160626,20160627,20160628,20160629,20160630,20160701,20160702,20160703,20160704,20160705,20160706,20160707,20160708,20160709,20160710,20160711,20160712,20160713,20160714,20160715,20160716,20160717,20160718,20160719,20160720,20160721,20160722,20160723,20160724,20160725,20160726,20160727,20160728,20160729,20160730,20160731,20160801,20160802,20160803,20160804,20160805,20160806,20160807,20160808,20160809,20160810,20160811,20160812,20160813,20160814,20160815,20160816,20160817,20160818,20160819,20160820,20160821,20160822,20160823,20160824,20160825,20160826,20160827,20160828,20160829,20160830,20160831 LAST-MODIFIED:20160102T123758Z DTSTAMP:20160107T232137Z END:VEVENT END:VCALENDAR
If DTSTART is a date-time value then EXDATEs must also be date-times. I propose you append T123000Z to each of your EXDATEs to make them actually point to valid instance starts. They will then get correctly excluded.
Based on this other SO issue, it seems you're not setting any excluded date in EXDATE. EXDATE can be set to DATE, based on the RFC 5545 specificaiton. Based on the answer on the other issue, your EXDATE should have been EXDATE:20151223,20151224,20151225,20151226,20151227,20151228,20151229,20151230,20151231,20160101,20160102,20160103,20160104,20160105,20160106,20160107,20160108,20160109,20160110,20160319,20160320,20160321,20160322,20160323,20160324,20160325,20160326,20160327,20160415,20160416,20160417,20160418,20160607,20160608,20160609,20160610,20160611,20160612,20160613,20160614,20160615,20160616,20160617,20160618,20160619,20160620,20160621,20160622,20160623,20160624,20160625,20160626,20160627,20160628,20160629,20160630,20160701,20160702,20160703,20160704,20160705,20160706,20160707,20160708,20160709,20160710,20160711,20160712,20160713,20160714,20160715,20160716,20160717,20160718,20160719,20160720,20160721,20160722,20160723,20160724,20160725,20160726,20160727,20160728,20160729,20160730,20160731,20160801,20160802,20160803,20160804,20160805,20160806,20160807,20160808,20160809,20160810,20160811,20160812,20160813,20160814,20160815,20160816,20160817,20160818,20160819,20160820,20160821,20160822,20160823,20160824,20160825,20160826,20160827,20160828,20160829,20160830,20160831 Hope this helps!
I posted this question looking for a solution that would exclude whole ranges. After careful consideration, I decided to do this properly, by excluding only the date-times where the event would actually take place. This decreased the file size of the export three fold. I also added timezone information as recommended for using RRULE. Now the French lesson event would look like this: BEGIN:VEVENT UID:schedule-1442#jpg.tartu.ee SUMMARY:French DESCRIPTION: LOCATION:Room 210 DTSTART;TZID=Europe/Tallinn:20151215T143000 DTEND;TZID=Europe/Tallinn:20151215T154500 RRULE:FREQ=WEEKLY;UNTIL=20160211;INTERVAL=1;BYDAY=TU EXDATE;TZID=Europe/Tallinn:20151229T143000,20160105T143000 CREATED:20160102T123758Z LAST-MODIFIED:20160102T123758Z DTSTAMP:20160108T115122Z END:VEVENT
Google Calendar Feed
I am trying to add a Google calendar to a website I'm making that the client will be able to update themselves. I found this: http://mikeclaffey.com/google-calendar-into-html/ which has been quite helpful, but I am a bit stuck. The website I am building is using PHP template and the page contents is contained within the $content variable. Here is the link I'm working on: http://victoriasawyer.com/AmosTheTransparent. The calendar feed is the top one of the two lists of Tour Dates. I would like the top one to look similar to the bottom one. The same would be ideal but not necessary. The biggest issue I'm having is with the start date and time. In the title of the event I would like just the date to show (preferably like 10/03/14) not the time. I have figured out how to display just the time separately without issue. Is there some way to change the date format? The other issue I'm having is the order that the events are appearing. I would like the events to show with the soonest one first in the list and the furthest one last in the list. I added the additional parameters as instructed in the tutorial (orderby=starttime and sortorder=ascending) but they do not display correctly. The url I am using is: https://www.google.com/calendar/feeds/qmfadhgtq2kmabsi3dlb456v98%40group.calendar.google.com/public/full?orderby=starttime&sortorder=ascending&futureevents=true&alt=json. Is there something I can adjust or add to fix the order? Any help will be much appreciated (even if you can recommend an alternative. It just needs to be customizable, and so far this seems to be the best option I have found).
You can use PHP's DateTime class like this: $date = new DateTime('Sun Nov 16 2014 00:30:00 GMT+0000'); echo $date->format('Y-m-d'); You can then use the predefined formats in PHP which are listed here to format it into whatever style you like. echo $date->format('d/m'); echo $date->format('d/m/Y');
Importing iCal calendar into MySQL database
I've searched through a lot of sites, but all of them do in reverse already what I've achieved , but not what I need. I need a way to import data FROM ICAL into a MySQL database, actually just one table and a few columns in a WordPress database. But I'm ignoring WordPress (as it messed up my export) and using direct database connection. Can any of you help me achieve this? Is importing ICAL so obviously simple that I'm thinking way too difficult? My ICAL docs setup: BEGIN:VCALENDAR VERSION:2.0C ALSCALE:GREGORIAN METHOD:PUBLISH X-WR-TIMEZONE:Europe/Amsterdam BEGIN:VEVENT DTSTART:20120113T133300 DTEND:20120223T165900 DTSTAMP:20120118T093232 SEQUENCE:0 STATUS:CONFIRMED SUMMARY:29007/on/on TRANSP:OPAQUE END:VEVENT END:VCALENDAR From "BEGIN:" to "END:" also gets repeated when a user exports multiple events. In status I've currently (will change to something else) a post ID, whether or not the event is "on"(true) meaning to be displayed (in order to preserve data of past events), and the 2nd "on" tells the front end whether an event is an all-day event (from 00:00 until 23:59). So again the question, how could I import this, using just a few lines of code, not a plugin or some other external code, into my table in a WP database? Thanks in advance! P.s. -> I just made this profile, not here to leech knowledge, before I created the profile just now I've also answered questions anonymously and corrected some answers in which I spotted mistakes.
The next is not a universal tool, but may suit your needs iCal Export/Import Tool for dhtmlxScheduler
Sitemap for dynamic PHP website ... the "lastmod" field is needed?
I've a really small website, so I usually update the sitemap by hand! In each "url" element there are the fields: loc, lastmod, changefreq and priority. The "lastmod" field is setup to the date in witch I update the content of the related PHP page or the content that is loaded dynamically in the related PHP page! I've tried to use http://www.xml-sitemaps.com/ to verify if all it was right, and I've noticed that in the generated sitemap there isn't the "lastmod" field! In the Google wiki, about how to write a sitemap, there's written that is a good practice to setup the "lastmod" field even for dynamic pages; so, my question is ... Is the "lastmod" field needed or not? Thanks in advace!
$lastmod = date('Y-m-dTH:i:s+00:00'); for more info, http://www.w3.org/TR/NOTE-datetime
You can use php date function to create last mod How Last mode value is created <sitemap> <loc><?php echo url('/') ?>/sitemap/uk/lse/list</loc> <lastmod><?php echo date('c', time()); ?></lastmod> </sitemap>
The standard says that it's optionnal : http://www.sitemaps.org/protocol.php#locdef : <lastmod> optional The date of last modification of the file. This date should be in W3C Datetime format. This format allows you to omit the time portion, if desired, and use YYYY-MM-DD. Still, it might be usefull to let search engines / spiders know when your content was updated for the last time. The How do I compute lastmod date? entry of the FAQ also gives an interesting reason, that explains why you should include the lastmod date if you can (quoting) : Using even an approximate date or timestamp can help crawlers avoid crawling URLs that have not changed. This will reduce the bandwidth and CPU requirements for your web servers.
It's not mandatory but it's good to have it in order to let Google (and other engines) know when content updates happen on your site.