PHP Based Live HTML Templating
I have a number of scattered HTML files on my website that I create and maintain by hand. I want them to look like the other pages (Wordpress) on my site (common header, sidebar, css) but I don't want to embed that everywhere. It's difficult to do, and hard to maintain, and sloppy. I could create each file as a PHP script that includes the common components but then they don't work offline.
My solution is to create a custom PHP based page handler that intercepts requests for HTML documents and decorates them at runtime.
Advantages:
- Templates can easily be changed in one place and applied to all HTML pages on a side.
- HTML files themselves are very basic which makes editing them easy (by hand or in editor).
- HTML files are suitable for offline copies / backups.
Disadvantage:
Extra processing per request. Not so nice on the server. But servers are fast these days.
The nutshell is that the handler will parse the HTML and pull out the title, any CSS, and the body and then insert it into a page template and spit that out. The clients don't see any of this.
I've added a magic flag "<!--NODECORATE-->" which can be added to HTML pages (anywhere) so that the handler bypasses them completely.
Configuration: '.htaccess'
The following code needs to be added to the .htaccess file in your site root. Adjust the path to "format.php" to suit your system. You probably don't really want it in the document root.
Action DecoratePage /format.php
AddHandler DecoratePage .html
Templating Source Code: 'format.php'
<?
# CONFIGURATION ##############################################################
$basedir = '/home/jclemen1/public_html';
##############################################################################
function getRandomLine($filename)
{
global $errors;
if (file_exists($filename)) {
mt_srand ((double) microtime() * 1000000);
$lines = file($filename);
$line_number = mt_rand(0,sizeof($lines)-1);
return $lines[$line_number];
} else {
$errors['getRandomLine'][] = "File: $filename not found";
return FALSE;
}
}
# find path and make sure they aren't going something evil!
$filename = $basedir . $_SERVER["ORIG_PATH_INFO"];
if (strpos(realpath($filename ), $basepath) != 0) die("Outside of DocumentRoot");
if (!file_exists($filename )) die("File does not exist");
# read entire contents of file
$filecontents = file_get_contents($filename);
# if file is not marked for decoration, don't decorate it. return as-is
if (stristr($filecontents, '<!--NODECORATE-->'))
{
print $filecontents;
exit(0);
}
# extract title/body from data
preg_match('@<title>(.*)</title>@is', $filecontents, $matches);
$title = $matches[1];
preg_match('@<body>(.*)</body>@is', $filecontents, $matches);
$body = $matches[1];
preg_match('@<style.*?>(.*)</style>@is', $filecontents, $matches);
$morecss = $matches[1];
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head profile="http://gmpg.org/xfn/11">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>jclement.ca - <?=$title?></title>
<meta name="generator" content="Jeff's Amazing Templating Tool" />
<link rel="stylesheet" media="screen" href="/blog/wp-content/themes/jclement2/style.green2.css" type="text/css" title="Default" />
<link rel="stylesheet" media="print" href="/blog/wp-content/themes/jclement2/print.css" type="text/css" />
<link rel="alternate" type="application/rss+xml" title="RSS 2.0" href="http://jclement.ca/blog/feed/" />
<link rel="alternate" type="text/xml" title="RSS .92" href="http://jclement.ca/blog/feed/rss/" />
<link rel="alternate" type="application/atom+xml" title="Atom 0.3" href="http://jclement.ca/blog/feed/atom/" />
<style type="text/css">
<?=$morecss?>
</style>
</head>
<body>
<a name="top"></a>
<!-- Page Header -->
<div class="pageHeader">
<table border=0 width="100%" cellpadding=0 cellspacing=0>
<tr><td valign="top" colspan=1>
<a href="http://jclement.ca/blog/"><b>jclement.ca</b></a> · <?=$title?></td>
<td valign="bottom" align="right">
[
<a href="/blog/">Home</a> ·
<a href="http://flickr.com/photos/jclement">Photoblog (Flickr)</a> ·
<a href="/software/">Software</a> ·
<a href="http://twitter.com/jclement">Twitter</a> ·
<a href="/search.html">Search Site</a>
]
</td></tr></table>
</div>
<div class="pageBody">
<h1><?=$title?></h1>
<?=$body?>
</div>
<!-- Page Footer -->
<div class="pageFooter">
<table border="0" width="100%" cellpadding="0" cellspacing="0">
<tr>
<td valign="top" align="left" width="100"><a href="#top">Back to Top</a></td>
<td valign="top" align="center">© 2009, <a href="/contact.html">Jeffrey Clement</a></td>
<td valign="top" align="right" width="100"> </td>
</tr>
</table>
<p class="quote"><? print getRandomLine($basedir . '/blog/wp-content/themes/jclement2/quotes.txt'); ?></p>
</div>
</body>
</html>