The last time I talked about XSL I mentioned how powerful it is for caching. In this post I’m going to talk about how I use it and how you can easily implement it. In this post I’m going to talk a bit more about how I handle caching with XSL and PHP.
When I started the last iteration of Christian Lyrics I spent a lot of time looking for the best way to cache my data and templates. I wanted each page load to do as little as possible. Unfortunately most of the templating engines I saw had medicore cache control at best, and it was starting to look like I need to work on a new one. Then I found XSL. I had already fallen in love with SimpleXML and DOM, and with XSL I was able to utlize both for views. I’m not going into detail how my view class works, instead I’m just going to cover the caching techniques I use. So let’s get started!
Most new sites have some form of login, and usually there is a block on each page with your user info. Take, for example, Christian Lyrics. It has a “My Account” box in the left menu that shows a log in form for Guests and some information about your account if you log in. I wanted everything on the home page, except for the user box, to be cached for a specified amount of time. With normal templating systems this required caching the “compiled” templates with whatever data inside of it and where the user menu goes is a line of PHP that calls the user template, which isn’t cached. I got that working, but it was clunky and used a lot of space.
With XSL, all we have to do is cache the XML data. It saves hundreds of megs in space for Christian Lyrics and adds a ton of post-processing capabilities, such as adding in the correct user box.
Now I’m going to use a fictional example with some XML and then a little PHP to show how you can use it. It’s the same idea described above, just the XML changed. First is what a cached XML file could look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?xml version="1.0"?> <page> <meta> <title>My Website</title> <description/> <keywords/> <last-updated>Mon, 15 Aug 05 15:52:01 +0000</last-update> </meta> <artists> <artist/> <artist/> <artist/> </artists> </page> |
So now whenever any visitor loads that page you don’t have to re-process anything, just load the XML and skip your actions. After the XML is loaded you can do any visitor-specific updates to it on the fly.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?xml version="1.0"?> <page> <meta> <title>My Website</title> <description/> <keywords/> <last-updated>Mon, 15 Aug 05 15:52:01 +0000</last-update> </meta> <artists> <artist/> <artist/> <artist/> </artists> <user> <id>1</id> <name>James Logsdon</name> </user> </page> |
And then deliver it to the visitor either as raw XML (with a processing directive for the XSL, I hope) or process the XSL server-side and deliver HTML (or whatever you want to transform it into, really).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | <?php // Path to where XML files should be saved define('PATH_CACHE', './cache/'); /** * Checks for a cached action XML, if not found runs the action and caches it * * Usage: * // Will cach search action for 1 hour based on the arguments array * run_action("search", array( * "query" => "this is a search", * "type" => "basic" * ), 60*60); * * @author James Logsdon <dwarf@girsbrain.org> * @param string $action Name of the action * @param array $arguments Arguments that are page specific, to cache seperate results for the same action * @param int $ttl Time to live (in seconds) of the cache file. Default is 10 minutes (600). Setting it to 0 disables caching. * @return boolean|SimpleXML */ function run_action($action, $arguments = array(), $ttl = 600) { $filename = $action.'_'.md5(http_build_query($arguments)).'.xml'; $cache = PATH_CACHE.$filename; $xml = null; // If the cache file doesn't exist or it's too old run the action if ($ttl > 0 && is_file($cache) && filemtime($cache) > (time() - $ttl)) { $xml = @simplexml_load_file($cache); } else { //... set xml to SimpleXML in here. // Save xml to cache for later (only if cache is enabled) if ($ttl > 0) { file_put_contents($cache, $xml->asXML()); } } // Failure importing XML if ($xml === false || $xml === null) { return false; } return $xml; } ?> |
In the next few weeks I’ll be doing another post on XSL and PHP, I’m just not sure on what part of it yet.
Comments 4
There is no problem with caching data as XML files… But caching IMHO should be done at later stage. I mean saving nearly full (X)HTML output in cache files. Only one thing bothers me with this solution. How to skip and re-process parts of code which should be dynamic e.g. forms (validation) or other user interaction parts of website.
Should be quiet complicated cause there are no released examples of live code on caching of XSLt in PHP.
If you got any ideas, I am ready to listen.
Posted 23 May 2008 at 5:08 pm ¶The problem with caching nearly full (X)HTML output is it basically nulls out the advantages of using XSL. Since I send XML to the client and let their browser handle the rendering it’s even more useless.
That’s a good point on re-processing for forms, though. I haven’t encountered a scenario where I needed to do that, but I’ll work it out right now since I have the time. I’ll edit my post with it.
Edit: Thinking about it some, I don’t really see it as an issue.
Take, for example, a search page: the search query would be passed in as an argument to run_action so each query would get it’s own cache file.
If you’re talking about, for example, a poll module on your site and you want to cache output until the user votes and then show them the results and cache that, then I would do it like this: create a “plugin” (or whatever your framework needs) so that the poll module is run independently of the action, but handle caching in the same way. So you run_action(”index”) and then run_action(”poll”) and insert the poll XML into the action XML.
Posted 23 May 2008 at 5:13 pm ¶“Since I send XML to the client and let their browser handle the rendering it’s even more useless.” - that’s not the good way of dealing with XSL transformations. Consider search engines, mobile devices and other stuff like text browsers e.g. Lynx. It lacks accessibility.
However, still thinking about caching static pages. It makes sense to me. Maybe I will find some examples in Java.
Thanks for you opinion.
Posted 24 May 2008 at 12:07 pm ¶“that’s not the good way of dealing with XSL transformations. Consider search engines, mobile devices and other stuff like text browsers e.g. Lynx. It lacks accessibility.”
I’ve only got it going on internal sites right now. If I ever put it on a public site, which I will be in the next 6 months, there will be some checks involved. That’s another post down the road, though.
Posted 24 May 2008 at 7:17 pm ¶Post a Comment