[php] How can I use PHP to dynamically publish an ical file to be read by Google Calendar?

Any Google search on PHP ical just brings up phpicalendar and how to parse or read IN ical files. I just want to write a PHP file that pulls events from my database and writes them out in ical format.

My problem is I can't find anywhere that will answer two questions:

  1. What is the exact ical format, including headers, file format, footers, etc.? In other words, what does the file have to have, exactly, in order to be properly read in by Google Calendar, etc.?
  2. If I build this file using a .php extension, how do I publish it as ical? Do I have to write to a new .ics file? Or will Google Calendar etc. read a .php file as ical so long as the contents are in the correct format? (Much like a style.css.php file will be read as a CSS file if the contents are actually CSS, etc.)

Any help you all can give or point me to will be greatly appreciated!!!

This question is related to php calendar icalendar

The answer is


This should be very simple if Google Calendar does not require the *.ics-extension (which will require some URL rewriting in the server).

$ical = "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:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR";

//set correct content-type-header
header('Content-type: text/calendar; charset=utf-8');
header('Content-Disposition: inline; filename=calendar.ics');
echo $ical;
exit;

That's essentially all you need to make a client think that you're serving a iCalendar file, even though there might be some issues regarding caching, text encoding and so on. But you can start experimenting with this simple code.


  1. Exact ical format: http://www.ietf.org/rfc/rfc2445.txt
  2. According to the spec, it has to end in .ics

Edit: actually I'm not sure - line 6186 gives an example in .ics naming format, but it also states you can use url parameters. I don't think it matters, so long as the MIME type is correct.

Edit: Example from wikipedia: http://en.wikipedia.org/wiki/ICalendar

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//hacksw/handcal//NONSGML v1.0//EN
BEGIN:VEVENT
DTSTART:19970714T170000Z
DTEND:19970715T035959Z
SUMMARY:Bastille Day Party
END:VEVENT
END:VCALENDAR

MIME type is configured on the server.


There is an excellent eluceo/ical package that allows you to easily create ics files.

Here is an example usage from docs:

// 1. Create new calendar
$vCalendar = new \Eluceo\iCal\Component\Calendar('www.example.com');

// 2. Create an event
$vEvent = new \Eluceo\iCal\Component\Event();
$vEvent->setDtStart(new \DateTime('2012-12-24'));
$vEvent->setDtEnd(new \DateTime('2012-12-24'));
$vEvent->setNoTime(true);
$vEvent->setSummary('Christmas');

// Adding Timezone (optional)
$vEvent->setUseTimezone(true);

// 3. Add event to calendar
$vCalendar->addComponent($vEvent);

// 4. Set headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="cal.ics"');

// 5. Output
echo $vCalendar->render();

Maybe a little late, but here's a link to the actual specification. http://tools.ietf.org/html/rfc55451


http://www.kanzaki.com/docs/ical/ has a slightly more readable version of the older spec. It helps as a starting point - many things are still the same.

Also on my site, I have

  1. Some lists of useful resources (see sidebar bottom right) on
    • ical Spec RFC 5545
    • ical Testing Resources
  2. Some notes recorded on my journey working with .ics over the last few years. In particular, you may find this repeating events 'cheatsheet' to be useful.

.ics areas that need careful handling:

  • 'all day' events
  • types of dates (timezone, UTC, or local 'floating') - nb to understand distinction
  • interoperability of recurrence rules

Make sure you format the string like this or it wont work

 $content = "BEGIN:VCALENDAR\n".
            "VERSION:2.0\n".
            "PRODID:-//hacksw/handcal//NONSGML v1.0//EN\n".
            "BEGIN:VEVENT\n".
            "UID:".uniqid()."\n".
            "DTSTAMP:".$time."\n".
            "DTSTART:".$time."\n".
            "DTEND:".$time."\n".
            "SUMMARY:".$summary."\n".
            "END:VEVENT\n".
            "END:VCALENDAR";

A note of personal experience in addition to both Stefan Gehrig's answer and Dave None's answer (and mmmshuddup's reply):

I was having validation problems using both \n and PHP_EOL when I used the ICS validator at http://severinghaus.org/projects/icv/

I learned I had to use \r\n in order to get it to validate properly, so this was my solution:

function dateToCal($timestamp) {
  return date('Ymd\Tgis\Z', $timestamp);
}

function escapeString($string) {
  return preg_replace('/([\,;])/','\\\$1', $string);
}    

    $eol = "\r\n";
    $load = "BEGIN:VCALENDAR" . $eol .
    "VERSION:2.0" . $eol .
    "PRODID:-//project/author//NONSGML v1.0//EN" . $eol .
    "CALSCALE:GREGORIAN" . $eol .
    "BEGIN:VEVENT" . $eol .
    "DTEND:" . dateToCal($end) . $eol .
    "UID:" . $id . $eol .
    "DTSTAMP:" . dateToCal(time()) . $eol .
    "DESCRIPTION:" . htmlspecialchars($title) . $eol .
    "URL;VALUE=URI:" . htmlspecialchars($url) . $eol .
    "SUMMARY:" . htmlspecialchars($description) . $eol .
    "DTSTART:" . dateToCal($start) . $eol .
    "END:VEVENT" . $eol .
    "END:VCALENDAR";

    $filename="Event-".$id;

    // Set the headers
    header('Content-type: text/calendar; charset=utf-8');
    header('Content-Disposition: attachment; filename=' . $filename);

    // Dump load
    echo $load;

That stopped my parse errors and made my ICS files validate properly.