How To Easily Cache Output With PHP

We will be using 4 native PHP functions to make your own cache class. This class will consist of three functions including the constructor, the other two functions will be “start” and “end”.

Two of the functions we’ll be using are file_exists which will tell us if the cache exists and filemtime to tell us when the cache file was last modified so that we know if we have to refresh it.

The other two functions ob_start and ob_get_contents are buffer functions. Think of ob_start as the red recording button in camera that is used tell the camera to start recording, in our case to start caching. ob_get_contents contains the out put after we started recording, so we will use ob_get_contents’ contents and write them to a file, this will be our cache file.

Full List Of Native PHP Functions We Will Be Using

// file exists returns a true if the file exists or a false if it doesn't
file_exists('filename.txt');

// filemtime returns the time when the file was last modified
filemtime('filename.txt');

// time() returns the current time
time();

// ob start tells the server to start recording
ob_start();

// ob get contents contains the output as a string since we started recording
// so we can assign the output to a variable and/or write the contents directly to a file.
$output=ob_get_contents();

How Do We Know When It’s Time to Refresh The Cache

We will calculate if it’s time to refresh the cache by subtracting the time the cache file was last modified from the current time and compare this value to the cache time we want.

// we also need to check if the file exists, but this is just to show you how we are going to
// calculate the time, so it's not the final product
if((time()-filemtime('cachefile.html'))<=$cacheTime)
{
  // include the cached file
}
else
{
  // no cache so start recording.
  ob_start();
}

Now that you know what we are doing, take a look at the cache class.

Cache.php

class WebHole_Cache
{
// $options is an array with the cache directory and cache time
	function __construct($options)
	{
               // cache directory/folder
		$this->cacheDir=$options['cacheDir'];
              // cache time in seconds
		$this->cacheTime=$options['cacheTime'];
	}
// file id is the cache file with extension
	public function start($fileID)
	{
		$this->fileID=$fileID;
                // check if the file exists and if the modification time is less than the cache time
		if(file_exists($this->cacheDir.$this->fileID) && ((time()-filemtime($this->cacheDir.$this->fileID))<=$this->cacheTime))
		{
		  // cache exists so include the cache file
		  include $this->cacheDir.$this->fileID;
		  return false;
		}
		else
		{
                    // cache does not exists or need to be refreshed
		    // make cache
			ob_start();
			return true;
		}
	}

	public function end()
	{
                // make cache file
		file_put_contents($this->cacheDir.$this->fileID,ob_get_contents(),LOCK_EX);
	}

}

example-cache.php

Let me show you how you would use the class. Notice that my fileID has the extension .txt, you can make it any extension you want, I used .txt because the HTML tags in it are recognized (when included as part of the script) in the browser the same way as if I used .html.

include 'cache.php';
$opts=array('cacheDir'=>'cache/', // folder for our cache
			   'cacheTime'=>50 // refresh cache every (seconds)
);

$cache=new WebHole_Cache($opts);
echo "precache ( not cached) ".time();
// everything before this is not cached.

if($cache->start('newcache.txt'))
{

        // all this is cached
	echo "<p>cached ".time();
	echo "</p>";

	$cache->end();
}
// post cache ( not cached )
echo "post cache (not cached either) ".time();

Note: One of the things I like to do, if possible, is include the database connection inside the “if” statement, this way your script won’t have to connect to the database every single time the script runs!

So to sum it up, we make the options with the cache directory and the time we want to cache the file in seconds. Then we check if the cache exists using the “start” function which returns a boolean. Finally, if the cache does not exists we make it a the end if the if statement. Anything before or after the if statement is not cached.

blog comments powered by Disqus