How to Build an iCal Calendar with PHP and MySQL

When I wanted to produce an iCalendar feed from my PHP application, I was somewhat surprised at the difficulty I had in finding any basic tutorials on the subject.

Sure, there is the official documentation which I would highly recommended studying if you are serious about building a detailed calendar, but a basic template will probably suffice for most.

The good news is that iCal calendars can be output on a basic LAMP server without any special configuration. It is essentially just plain text.

My iCal is a bunch of appointments retrieved from a database for my clinic management software, and the raw output looks like this:

PRODID:-//Thomas Multimedia//Clinic Time//EN
SUMMARY:Emily Henderson
LOCATION:Bundall Clinic Room 1

The PHP to generate the calendar looks like this (using the CodeIgniter framework):


// the iCal date format. Note the Z on the end indicates a UTC timestamp.
define('DATE_ICAL', 'Ymd\THis\Z');

// max line length is 75 chars. New line is \\n

PRODID:-//Thomas Multimedia//Clinic Time//EN\n";

// loop over events
foreach ($query_appointments->result() as $appointment):
 $output .=
SUMMARY:$appointment->firstname $appointment->surname
STATUS:" . strtoupper($appointment->status) . "
DTSTART:" . date(DATE_ICAL, strtotime($appointment->starts)) . "
DTEND:" . date(DATE_ICAL, strtotime($appointment->ends)) . "
LAST-MODIFIED:" . date(DATE_ICAL, strtotime($appointment->last_update)) . "
LOCATION:$appointment->location_name $appointment->name

// close calendar
$output .= "END:VCALENDAR";

echo $output;


Here is some info on some of the fields:

PRODID:-//Thomas Multimedia//Clinic Mate//EN\n”;
The PRODID are your app / company details in the format Business Name//Product Name//Language.

The start tag for an event. You can have as many vevents as you require.

This is the event title.

A unique ID for the event. This is important and required, and allows you to push changes to event details after they have been created. If you are retrieving database rows, the primary key is an ideal candidate for the UID value.

STATUS (optional. default value is CONFIRMED)
The event status is optional and can be one of CONFIRMED, TENTATIVE, CANCELLED. A cancelled event shows with a line through text decoration on iOS.

The event start and end timestamp. This should be formatted as demonstrated using the defined iCal format.If your dates are not already in the UTC timezone, you should convert them to UTC before outputting as this is the expected timezone when the timestamp ends with “Z”. There are options to specify a timezone which are beyond the scope of this tutorial.

LAST-MODIFIED (optional)
If your event has been modified you might like to set the last modified date in the same format as DTSTART above.

LOCATION (optional)
The title of the event location. There is also a GEO field where you can specify LAT/LONG coordinates, as well as a proposed VVENUE field to contain additional location data, however at least on the iPhone / iPad these tags are unused by the OS. Further reading here. I would expect better map integration in the near future for these fields.

It is worth noting that if you enter an address or phone number into the DESCRIPTION field (which I haven’t documented) in plain text, iOS will auto-link the text and will jump to the Maps app or Phone app with the details pre-filled.

The close tag for an event. Remember, you can have as many vevents as you require.

Once your web application is generating calendar data, its time to test!

I did my testing on my iPad. To add a calendar URL, go to: Settings > Mail, Contacts, Calendars, Add Account… Select Other > Add Subscribed Calendar, and then enter your URL in the Server field. Your calendar does not have to have the .ics extension. Then in the Calendar app, you can open the Calendars option and select only your new calendar for testing purposes. The refresh button is your friend! The Apple Calendar updates on its own schedule, which I think is somewhere around every 10-15 minutes.

The major thing to watch out for is formatting errors. iOS devices flatly refused all calendar data if there were any issues with new lines or anything else in contrast to the iCal specifications.

Questions? Comments? Ask below.

29 Replies to “How to Build an iCal Calendar with PHP and MySQL”

  1. Hey Steve,

    Great tutorial and explanation. I was wondering if the same link works on other calendars like Google, Outlook and Yahoo. I was able to make a calendar feed like you described above and it works on all the apple devices but the same feed url does not work on other calendars.


    – Rajeev

  2. Good PHP code but you need to add correct content-type-header :

    header(‘Content-type: text/calendar; charset=utf-8’);
    header(‘Content-Disposition: inline; filename=calendar.ics’);

  3. Hi,

    This looks great!

    ….so I just run a query to pull out fields from my DB and label them with the same names as you’ve used here and it should loop through my DB right?

  4. Hi Steve

    I’ve just stumbled across this, and it’s excellent – thank you. Just a quick question if I can, I’ve looked at the Docs but can’t see it clearly in there so just hoping you might know the answer….

    Your events have a start & end time, which is great. In iCal on Mac you can set an “all day” event, do you know what the mark-up would be for me to do that?

    Thanks again

  5. All-day events simply set DTSTART:20130919 and DTEND:20130920 and add

    This would be an all day event on 2013-09-19.

  6. Thanks for sharing that – it works brilliantly.

    Do you know how (or a resource to tell me how) to add an alert/alarm for an event?

  7. This is really great, thanks. I am almost there I think…

    My php file works fine, and generates the ical feed – I can then add it manually to my iphone using Calendars, Add Account… Select Other > Add Subscribed Calendar, and all works fine. It even updates regularly.

    But I want to allow users to subscribe by making the link webcal://

    when i try and click this link, it says “could not connect to *.php* on

    Any ideas?


  8. Hi,
    This looks great! I just have one question about security: do you think there is way to secure the access to the content of the PHP file, maybe with a username and password that could be stored on the iPad or iPhone?
    Thanks a lot,

  9. Matthieu,

    I’m not sure whether iOS or Android supports something like HTTP Basic Authentication, which you could setup fairly easily on your server – maybe someone else can answer that.

    Otherwise I would recommend using a secure token appended to the url which is attached to the user account.

  10. What if I want to send the file attached to email instead echo to the browser? I have an email sending library capable to attach files. But when I place $output as the attachment file I don’t receive it, the email is sent but without any file attached.

    Some thoughts?

  11. Good code. Not that hard to do it actually, it’s pretty simple once you figure it out. Do you think Android supports HTTP bacis authentication? I’m trying to find the answer on the internet, but no luck. Even looked on, these guys usually have everything when it comes to Android

  12. Well, feed events in php in this way is very easy and useful if u are goong to use it with iphone/outlook but if you want to make it work also with android calendar good luck! I was happy to have found the possibility to restrict access asking username and password too but works only with iphone. If you want something more compatible study caldav like im doin rite now. Google “basic authentication php” for protect the feeder with username and pass 😉

  13. Hie,
    You started me off nicely. I encountered two issues.
    1. When i fetch a calender from a client, it has several events with same uid. Do you know why?
    2. The calender i get from the client has RRULE which simply gives events that repeats like :
    [rrule] => FREQ=WEEKLY;UNTIL=20150520T100000Z;INTERVAL=1;BYDAY=WE;WKST=MO
    How can i deal with this if i am saving anything to the my db

    please help 🙁

  14. Hi,
    how we can use ical in laravel.

    can you give me just simple example for download ical in laravel ?

  15. Hi,

    How can I connect with the DB?
    What code do I put before code

    // the iCal date format. Note the Z on the end indicates a UTC timestamp.
    define(‘DATE_ICAL’, ‘Ymd\THis\Z’);


  16. Hi, thanks for the code. But, I’m not able to view shift assigned between 10:30 to 6:30

    Here is my Code:-

    function __export_schedule($appointment){
    define(‘DATE_ICAL’, ‘Ymd\THis’);
    // max line length is 75 chars. New line is \\n
    $output =”BEGIN:VCALENDAR\rMETHOD:PUBLISH\rVERSION:2.0\rPRODID:-//Thomas Multimedia//Clinic Time//EN\n”;
    $filename = urlencode( ‘My-Events-‘ . date(‘YmdHis’));
    foreach($appointment as $appointmentVal)
    $start=$appointmentVal->schedule_date.” “.$appointmentVal->shift_start_time;
    $ends=$appointmentVal->schedule_date.” “.$appointmentVal->shift_end_time;
    $summary=$appointmentVal->user_funllname.” @ “.$appointmentVal->shift_alias;
    $output .=
    DTSTART:” . date(DATE_ICAL, strtotime($start)) . ”
    DTEND:” . date(DATE_ICAL, strtotime($ends)) . ”
    LAST-MODIFIED:” . date(DATE_ICAL, strtotime($appointmentVal->schedule_updated)) . ”
    LOCATION:’test location’
    //echo “

    "; echo $start;
    //echo "
    "; echo $ends;
    $output .= "END:VCALENDAR";
        //echo "
    "; echo $filename;
    //echo "
    "; echo $output; exit();
    header("Content-Type: text/Calendar;charset=utf-8");
    header('Content-Disposition: inline; filename='.$filename . '.ics' );
    echo $output;
  17. Hi, thanks for the code. But in the mac calendar it shows

    Some Events in this calendar file were unreadable. Events that were readable have been added to your calendar.

    Please help me.

  18. Hi, I´m having an issue and I don´t know why, but for example The date is 20160729 and the time is 080000
    this means it must make an appointment for 2016-07-09 at 8:00 am
    but for some weird reason in outlook it takes 5 hours, so the appointment at outlook is made at 3:00 am…I need help to fix this timezone/something Issue!
    function sendIcalEvent($from_name, $from_address, $to_name, $to_address, $year, $month, $day, $hour, $minute, $seconds, $EndHour, $EndMinute, $subject, $description, $location)
    //Create Email Headers
    $headers = "From: someone@someone\r\n";
    $headers .= 'Content-Type:text/Calendar; Content-Disposition: inline; charset=utf-8;\r\n';

    $message = "BEGIN:VCALENDAR\r\n
    PRODID:-//HPE-Scheduler// v1.0//EN\r\n

    $mailsent = mail($to_address, $subject, $message, $headers);

  19. Hey Steve, Good job man. Thanks for the article. I have read so many articles about Outlook calendar integration with PHP, but found your article helpful & clear than others.

  20. I was wondering if anyone could point me to a list of valid properties of a VCalendar.
    Such as:
    $vcalendar = new VObject\Component\VCalendar([
    ‘VEVENT’ => [
    ‘SUMMARY’ => ‘Conference: ‘ . $conference->getName(),
    ‘DTSTART’ => $conference->getStartDate(),
    ‘DTEND’ => $conference->getFinishDate(),

  21. Great tutorial
    Works great even added writing to a file on the server

    Events show in outlook, but not in google? Any idea why??


  22. hello i m code is able to block calende but not at give date.whats wrong with this script.pls help someone

    PRODID:-//productlabs Solutions//EN
    TRUE;CN=Rohit B R;
    TRUE;CN=Srinivasulu Mallampooty;
    TRUE;CN=Godavarma Chazhoor;
    DESCRIPTION:Meeting Details : “.$txtMeetingName.”\nView your event at
    LOCATION:Bengaluru\, Karnataka 560001\, India

  23. Nice tutorial.. I have been struggling to look for such tutorial for whole day, and finally got to this page. Thank you very much. I have kept following two lines to complete whole functionality of my calendar event.

    header(‘Content-type: text/calendar; charset=utf-8’);
    header(‘Content-Disposition: inline; filename=calendar.ics’);

Leave a Reply

Your email address will not be published. Required fields are marked *