PHP Script for hCalendar to iCalendar Conversion

I try to do the “right thing” in postings on DLTJ. In the context of this discussion “right” is an attempt to be progressive: including hCalendar microformat markup for postings that include mention of events. The latest example of this was yesterday’s posting of the Learning, Libraries and Technology Conference. Embedded in the first paragraph is markup that another application reading the DLTJ feed can use to understand that the posting is talking about an event. (The Technorati Events” service is one example.) The key parts of the HTML are bolded below:

<div class="vevent" id="llt2009-call-for-proposals-hcalendar"><a href="http://www.oln.org/conferences/LLT2009/pdf/LLT09precons.pdf">Pre-conference workshop descriptions</a> [PDF] and the <a href="http://www.oln.org/conferences/LLT2009/pdf/LLT09draftprogram.pdf">preliminary program</a> [PDF] as well as the <a href="https://secure.oln.org/LLT2009/LLT2009registration.php">registration form </a>for the <span class="summary"><a href="http://www.oln.org/conferences/LLT2009/" class="url">Learning, Libraries and Technology Conference</a></span> have been posted to the conference website. <span class="description">Learning, Libraries & Technology 2009 is a learning and networking opportunity from the <a href="http://www.uso.edu/">University System of Ohio</a> with content of interest to everyone involved in Ohio education, including those from colleges and universities of all sizes, independent colleges, workforce development centers and high schools.</span> Held at the <span class="location"><a href="http://www.eastontowncenter.com/">Easton Town Center</a> in Columbus, Ohio</span>, the pre-conference Workshops will be on <abbr class="dtstart" title="2009-03-01" style="border:none;text-decoration: none;">March 1, 2009</abbr> followed by the main conference on <abbr class="dtend" title="2009-03-04" style="border:none;text-decoration: none;">March 2-3, 2009</abbr>.</div>

(There is an hCalendar creator that can be used to create the proper markup.) The microformats wiki describes the above markup this way:

Microformats are small bits of HTML that represent things like people, events, tags, etc. in web pages. Microformats enable the publishing of higher fidelity information on the Web, providing the fastest and simplest way to support feeds and APIs for your website.

The hCalendar microformat is based on the iCalendar file format — a mechanism for calendaring programs to share information about events and meeting requests.

hCalendar Encoded Microformat
Add this event to your desktop calendar program.

Sample link for hCalendar to iCalendar translator

Also included in the posting is a link that says “add this event to your desktop calendar program.” This link uses an XSLT-driven process to transform the microformat data embedded in the XHTML posting into the iCalendar format. The XSLT transformation was written by Brian Suda; Brian also has a transformation service for taking an arbitrary XHTML document with hCalendar markup and creating the corresponding iCalendar file. I’ve used this transformation service in previous postings on DLTJ.

I’ve used this so much that I decided not to sponge on Brian’s translation service any more and create an equivalent translation service that runs on DLTJ. Included below is some PHP code that will drive the XSLT transformation process. If you copy and paste this PHP into a file in the same directory with Brian’s “x2v” implementation, then you can do the same thing.

The Script

Here is the script itself:

# Copyright 2008 by Peter Murray.   Licensed under the
# Educational Community License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may
# obtain a copy of the License at
#
#  http://www.osedu.org/licenses/ECL-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS"
# BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing
# permissions and limitations under the License.

## For more information about this program, see:
##   http://dltj.org/article/xhtml2vcal

# Array of tokens representing site prefixes.  To see how these
# are used, look at the $pathInfo explode() below.
$siteTokens = array(
    "dltj" => "http://dltj.org/article/%pageToken%/",
);
 
# $pathInfo[0] is blank; it represents the empty space before the leading slash
# $pathInfo[1] is the site token; see site tokens above
# $pathInfo[2] is the page token; it is appended to the end of the URI
$pathInfo = explode("/",$_SERVER['PATH_INFO']);
 
# Check to see if the token is one that we know about
if (array_key_exists($pathInfo[1], $siteTokens)) {
  # Substitute the page token into the site uri template
  $uri = preg_replace('/%pageToken%/', $pathInfo[2], $siteTokens[$pathInfo[1]]);
} else {
  header('HTTP/1.0 400 Invalid site token '.$pathInfo[1]);
  header('Content-Type: text/plain');
  echo 'Invalid site token: '.$pathInfo[1];
}
 
# See if we have 'curl'  
if ( !function_exists( 'curl_init' ) ) {
  header('HTTP/1.0 500 curl_init() function not found');
  exit;
}
 
# Prepare and execute a 'curl' request
$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, $uri);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($handle);
 
# Check to see if we got a resource back
$httpCode = curl_getinfo($handle, CURLINFO_HTTP_CODE);
if ($httpCode != '200') {
  header('HTTP/1.0 404 Remote document not found');
  header('Content-Type: text/plain');
  echo "Remote resource returned HTTP code '$httpCode' for URI $uri";
  exit;
} else {
  curl_close($handle);
}
 
# Load the XML source from that URI
$xml = new DOMDocument;
$xml->loadHTML($buffer);
 
# Load the XSLT document
$xsl = new DOMDocument;
if (! $xsl->load('x2v/hcalendar/xhtml2vcal.xsl')) {
  header('HTTP/1.0 500 XSLT style sheet not found');
  header('Content-Type: text/plain');
  echo "XSLT stylesheet not found";
  exit;  
}
 
# Configure the transformer
$proc = new XSLTProcessor;
$proc->importStyleSheet($xsl); // attach the xsl rules
$proc->setParameter('', 'Source', $uri);
 
# Tell the browser we're sending an iCalendar file
$fileName=$pathInfo[2].".ics";
header("Content-Type: text/calendar; charset=utf-8; name=$fileName");
header("Content-Disposition: attachment; filename=$fileName");
 
# Do the transformation
echo $proc->transformToXML($xml);
 
# Add a Control-M to the end of the file and flush the output
echo "15n";
flush();
(This post was updated on 11-Jun-2014.)