Home| Portfolio| Trips| Extras| About Us| Site Map

Simple OO PHP caching

Often sites are database driven because it makes it easy to add huge volume of content that is easy to maintain. After the initial creation, often the bulk of the content remains unchanged and there is little point in generating pages from scratch using the DB for every request. This page shows how to set up a very simple cache to ease the load on the server and, hopefully, make your site run faster. It assumes you are running PHP4.x on a *nix server.

This page has an example of a simple OO cache that will:

Requirements

  1. PHP4.x
  2. A location outside of the web root to use as a cache this needs to be world writeable ( chmod 777 cache_directory, 757 should work too, but it's not really any more secure )
  3. A way of telling if your database content has changed - I use a TIMESTAMP field in content tables to provide this

NOTE:

The PHP code

class cache {
	var $good=FALSE;
	var $filename=NULL;
	var $lastModified=NULL;
	var $contentLength=NULL;
	var $request_type=NULL;
	var $etag=NULL;
	
	function cache($filename, $db_time){
		$this->request_type=$_SERVER['REQUEST_METHOD'];
		$this->filename=PT_CACHE.$filename.".html";
		if (file_exists($this->filename)) {
			$time_diff=$db_time-filemtime($this->filename);
			if ($time_diff<0) {
				$this->good=TRUE;
				$this->lastModified=gmdate('D, d M Y H:i:s', filemtime($this->filename)) . ' GMT';
				$req_date=(isset($_SERVER['HTTP_IF_MODIFIED_SINCE']))?
						$_SERVER['HTTP_IF_MODIFIED_SINCE']
						:"";
				$etag=(isset($_SERVER['HTTP_IF_NONE_MATCH']))?
					$_SERVER['HTTP_IF_NONE_MATCH']
					:"";
				$this->etag=md5($this->lastModified.$this->contentLength);
				if ($req_date == $this->lastModified or $etag == $this->etag) {
					header('HTTP/1.0 304 Not Modified');
					exit;
				} else {
					$this->contentLength=filesize($this->filename);
					header("Last-Modified: ".$this->lastModified);
					header("Content-Length: ".$this->contentLength);
					header("ETag: ".$this->etag);
					if ($this->request_type=="GET") {
						readfile($this->filename);
					}
					exit;
				}
			}
		$this->good=FALSE;
		ob_start();
	}
		
	function writeCache() {
		if ($this->filename) {
			$content=ob_get_flush();
			$cache_file=fopen($this->filename,'w');
			fwrite($cache_file, $content);
			fclose($cache_file);
			}
		}
}

What to send in - the constructor arguments

This is written in PHP 4.x and uses the contructor to set up the cache.

  1. $filename is the cache filename - ie the file to create if the cache is not usable and to be sent out if it is good. This is pretty easy to get with "Search Engine Friendly URLs"
  2. $db_time is the date of the most recent change to take account of - it should be in unix epoc format ( easily obtained from UNIX_TIMESTAMP in MySQL )

What to do & how to use the cache

  1. Save the code above into a file ( I normaly name such files good_name.class.inc ) and upload it to your server, it should, ideally, be out of the web root as well.
  2. Create your cache directory and make it writeable
  3. Add a constant to the script
    ( define("PT_CACHE", "/path/to/cache/on/server/"); ). You can do this with $_SERVER['DOCUMENT_ROOT'] and realpath() to make it more flexible.
  4. Include or require the class into your dynamic page. Once your dynamic script has the most recent altered date and filename together call the cache ( $myCache=new cache($file_name, $last_updated); )
  5. At the end of your dynamic file place $myCache->writeCache(); As you'd expect this ends the output buffering, sending the page to the client, and creates a file in the cache directory

What's missing?

Feedback on this page would be very gratefully received, my email is at the bottom of the page. I'd appreciate a copy of any enhanced version as well, thanks.

If you came looking for a great and fully featured php cache then try Cache_lite

Useful external links: