Every time a request hits your server, PHP has to do a lot of processing, all of your code has to be compiled & executed for every single visit. Even though the outcome of all this processing is often identical for both visitor 21600 and 21601. So why not save the flat HTML generated for visitor 21600, and serve that to 21601 as well? This will relieve resources of your web server and database server because less PHP often means less queries.

Cache_Lite

Now you could write such a performance system yourself but there's a neat package in PEAR called Cache_Lite that can do this for us, benefits:

  • it saves us the time of inventing the wheel
  • it's been thoroughly tested
  • it's easy to implement
  • it's got some cool features like lifetime, read/write control, etc.

Now you don't need to cache entire pages, you can also just cache parts of pages if that's easier to implement.

Install Cache_Lite

Installing is like taking candy from a baby. On Ubuntu I would use aptitude like this:

$ sudo aptitude -y update
$ sudo aptitude install php-pear

And now that we have PEAR, i would use it to install the Cache_Lite extension:

$ sudo pear install Cache_Lite

And we're ready!

Implement Cache_Lite

So let's see how we can implement Cache_Lite into our scripts. The basic idea is that we have a unique identifier for every page. You can make it up, get it from your database, or use the REQUEST_URI. Cache_Lite will see if it stored content for that identifier before, and if it's fresh enough. If so, it will retrieve the stored HTML from disk and echo it right away. If not, we:

  • turn on output buffereing so we can catch all following content
  • we include the original PHP code
  • catch the output buffer, and let Cache_Lite store it on disk for the next time.
  • and then echo it

This is a PHP example:

<?php
/* Include the class */
require_once 'Cache/Lite.php';

/* Set a key for this cache item */
$id = 'newsitem1';
/* Set a few options */
$options = array(
    'cacheDir' => '/var/www/www.mywebsite.com/cache/',
    'lifeTime' => 3600
);

/* Create a Cache_Lite object */
$Cache_Lite = new Cache_Lite($options);
/* Test if there is a valid cache-entry for this key */
if ($data = $Cache_Lite->get($id)) {
    /* Cache hit! We've got the cached content stored in $data! */
} else {
    /* Cache miss! Use ob_start to catch all the output that comes next*/
    ob_start();

    /* The original content, which is now saved in the output buffer */
    include "realcontent.php";
    /* We've got fresh content stored in $data! */
    $data = ob_get_contents();

    /* Let's store our fresh content, so next
     * time we won't have to generate it! */
    $Cache_Lite->save($data, $id);
    ob_get_clean();
}
echo $data;
?>

In this example, the real, original php code is stored in realcontent.php

Let Cache Live in RAM

If your want, you can have all the static html files served from the server's internal memory. Now this would really speedup things. Checkout my other article Create turbocharged storage using tmpfs to learn how.

More Cache_Lite

One thing I always like to do, is to automatically purge an article's cache when a comment has been placed. You could for example place this before Cache_Lite checks if it's got a cache page for a specific $id:

<?php
if (isset($_POST["add_comment"]) && $_POST["add_comment"]){
    $Cache_Lite->remove($id);
}
?>

Take some time to read the comments in the source code, it's actually pretty easy.