phpCache — speed up your website

Caching seems to be the new trend. But aside from all the marketing, it’s really a lot more than that. If you don’t have the money to buy those lovely Zend products, you might find yourself turning to the world of Open Source (again). And viola! You’ll be helped.

There are two ways to cache with PHP – as far as I know -, one is using PEAR’s Cache_lite class. There’s an article already about it on Devshed, but since someone already spoiled it and I am not too much of a pear-lover myself (I like wine-berries, oranges and stuff), I’ll talk about phpCache. So here we go.

So, at first we’ll start with the principals. What does this caching thing do? And why do I want it?
Caching is used in a million things. For example, there is your browser’s cache, which saves a website to your harddrive so next time, you go to this website, it’ll come up a lot more faster on your screen. Your ISP probably also offers caching through a proxy server. In this case, highly frequented websites are downloaded to the ISPs proxy server and delivered to you a lot faster than if you would go to the site directly. Thumbnails of larger images are a way of caching too.

In this case, phpCache will save the contents of a so called “dynamic website” to the filesystem and read it until the scripts says, “Outdated!”, and regrabs the contents from the database to store them in the filesystem again, and again, and again. That’s basically how they all work. Basically – without the tech mumbo jumbo!
The reason “Why?!” is that for example if you have a high traffic site and a frontpage that pulls a lot of news from your database, you might run into a small problem. Thousands of visitors come to your site each hour (or minute) and each of those thousand requests equals an SELECT-statement which pulls the desired information from your database. The pulls equal load on the database which in return consumes memory and CPU and we would like to stay as slim as possible, won’t we?

Now that we found out, that we want to cache and since we have the latest package of phpCache handy, let’s hop on the shell and get the magic going.

Get the party started!

phpCache is a small little something, that can be found at http://0x00.org/php/phpCache/. Go there, grab the latest version and off we go.

On my servers, I like to organize my webs in the following manner:

/web/htmlcenter.com/ 
/web/htmlcenter.com/forums/ 
/web/htmlcenter.com/forums/docroot/ 
/web/htmlcenter.com/forums/logs/ 
/web/htmlcenter.com/www/ 
/web/htmlcenter.com/www/docroot/ 
/web/htmlcenter.com/www/logs/ 
...

The reason why I do it, I like to have everything that belongs to a web in one place. Whenever I need to get rid off a web, or in case of a backup, I just delete or tar the directory and get virtually everything that belongs to the web. In my case, everything except the database and mail.

Now that we downloaded the archive into /web/htmlcenter.com/forums/, we’ll extract it.

shell# tar zxvf phpCache1.4.tgz 
phpCache-1.4/ 
phpCache-1.4/ChangeLog 
phpCache-1.4/KentuckyFriedCache.pl 
phpCache-1.4/LICENSE 
phpCache-1.4/README 
phpCache-1.4/gc.php 
phpCache-1.4/phpCache.inc 
phpCache-1.4/demo/ 
phpCache-1.4/demo/all.php 
phpCache-1.4/demo/eatCPU.inc 
phpCache-1.4/demo/expire_every10s.php 
phpCache-1.4/demo/expire_mtime.php 
phpCache-1.4/demo/pager.php 
phpCache-1.4/demo/session.php 
phpCache-1.4/demo/simple.php 
phpCache-1.4/demo/thumbnails.php

(Hint: 1.4 was the latest version when I wrote this article.)

To make it look more pretty you can use the following:

shell# mv phpCache-1.4 phpCache

Which renames the directory. And makes it more easy to remember the name.
If you’d like to change the path, where phpCache saves the files to, you should use your favorite editor (vim, vi, pico, ee, joe, …) and edit phpCache.inc. If you can live with /tmp/phpCache, you keep it that way. Since I like to keep everything together, I adjusted the path to /web/htmlcenter.com/forums/phpCache/cache/ and saved the file.

If you create another directory, make sure that you set the correct permissions. In general:

chmod 777 directory_name/

Since the directory that we create for phpCache needs to be writable for everyone, I like to keep it outside the document root. Otherwise, people who go to my website could exploit the fact that a directory, that is writable for everyone is accessable to the public. Of course there is not just one way of doing it, but keeping the cache outside the document root might just be the most easiest/convenient one.

Cache it, baby!

Now, let’s assume, our script looks the following:

// pull the three latest records 
$query="SELECT title, id, teaser FROM news ORDER BY date DESC LIMIT 3"; 
// execute query 
$rawdb=@mysql_query($query); 
// check if the query was successful AND if it returned records 
if($rawdb AND @mysql_num_rows($rawdb)>0){ 
  // outputs the records 
  while($array=@mysql_fetch_array($rawdb)){ 
    extract($array); 
    echo '
include('../path/to/phpCache.inc'); 
if(!($et=cache(60)){ // We'll cache the database output for 60 seconds. :-) 
  $my_news=array(); // Create an array to store the news in 
  $query="SELECT title, id, teaser FROM news ORDER BY date DESC LIMIT 3"; 
  $rawdb=@mysql_query($query); 
  if($rawdb AND @mysql_num_rows($rawdb)>0){ 
    while($array=@mysql_fetch_array($rawdb)){ 
      extract($array); 
      // store the info in the array 
      // the info is appened 
      $my_news[]=htmlentities('     endcache(); 
  }else{ 
    if(!$rawdb){ 
      echo 'Error: '.mysql_error().' 
Query: '.$query; 
    }else{ 
      echo 'No news...'; 
    } 
  } 
} 
/* 
  debugging 
  echo 'The cache expires in '.$et.' seconds!'; 
*/ 
// output the cached array 
for($i=0;$i<;count($my_news);$i++){ 
  echo $my_news[$i]; // prints the news 
} 
// That's all folks! 
?>

So what did we do?

At first, we'll check if the cache that was created still fits our needs or if it's too old already. If the cache is just fine, we'll skip to the output. If the cache is too old, we'll pull the records once more from the database, store it into the array, cache the array and continue to the output.

Where do we go from here?

Well, at first you should eliminate the bottlenecks on your site. While phpCache comes in handy when you cache database queries and lookups, you shouldn't use it as an excuse for your poor SQL skills. Whatever type of SQL you use, always debug (check the index, query speed, ...). Depending on your type of SQL there might also be a thing called "Query Cache", consult your manual and read up on it, if you are lucky to have it.

Maintainance?

phpCache comes with a neat little script called "gc.php". It's meant to clean up the cache it created. As the author put it, "Running this once a day is recommend.". If you have questions about how to run PHP scripts with cron, check my
"Running PHP Scripts with Cron Tutorial".