Posts Tagged ‘Why should you cache your PHP website?’


Faster PHP Websites using Cache

In this part, I will show you how to ‘retrofit’ caching in to your scripts using the above script as an example. The objective is to speed things up by not having to regenerate the information every time somebody requests a file. Generating the content every request is a waste, on static information such as our CSS.
To add caching they must add things to our script. First, they must collect the information input to the script & generate a filename distinctive to that set of inputs. Secondly, they must look for a cache file & see if it is sufficiently recent. Finally, they must either use the cached copy or generate new content & cache it for next time.

Breaking the Flow

This part of the process really depends on the individual script, however I will show where I am going to break the flow of this script for the caching.

  1. <?php
  2. $fileDirectory = ”;
  3. $file = $_GET[‘q’];
  4. $nameExplode = explode(‘.’, $file);
  5. $ext = $nameExplode[1];
  6. $fileName = $fileDirectory . $file;
  7. //– WE HAVE ENOUGH DATA TO GENERATE A CACHE FILE NAME HERE —
  8. if ($ext != ‘css’ AND $ext != ‘htm’ AND $ext != ‘html’) {
  9.     //Check for evil people…
  10.     die(‘Hackers…!’);
  11. } else {
  12.     //– WE CAN INTERCEPT AND CHECH FOR THE CACHED VERSION HERE —
  13.     //Lets get down to business
  14.     $handle = fopen($fileName, ‘r’);
  15.     $fileData = fread($handle, filesize($fileName));
  16.     //Now for some regex wizardry!
  17.     $newData = preg_replace(‘/\s+/’, ‘ ‘, $fileData);
  18.     fclose($handle);
  19.     //Time to output the data.
  20.     //– NOW WE CAN STORE THE NEW DATA IF REQUIRED AND OUTPUT THE DATA —
  21.     if ($ext == ‘css’) {
  22.         header(“Content-type: text/css”);
  23.     }
  24.     echo $newData;
  25. }

?>

Putting it into Action

We will now actually write the code for caching into this script. I will first show the script completed and then go through each piece.

  1. <?php
  2. $fileDirectory = ”;
  3. $file = $_GET[‘q’];
  4. $nameExplode = explode(‘.’, $file);
  5. $ext = $nameExplode[1];
  6. $fileName = $fileDirectory . $file;
  7. $cacheName = ‘./cache/’ . $nameExplode[0] . $nameExplode[1] . ‘.tmp’;
  8. if ($ext != ‘css’ AND $ext != ‘htm’ AND $ext != ‘html’) {
  9.     //Check for evil people…
  10.     print_r($ext);
  11.     die(‘Hackers…!’);
  12. } else {
  13.     if (file_exists($cacheName) AND filemtime($cacheName) > (time() – 86400)) {
  14.         $cacheHandle = fopen($cacheName, ‘r’);
  15.         $newData = fread($cacheHandle, filesize($cacheName));
  16.         fclose($cacheHandle);
  17.         $isCached = TRUE;
  18.     } else {
  19.         //Lets get down to business
  20.         $handle = fopen($fileName, ‘r’);
  21.         $fileData = fread($handle, filesize($fileName));
  22.         //Now for some regex wizardry!
  23.         $newData = preg_replace(‘/\s+/’, ‘ ‘, $fileData);
  24.         fclose($handle);
  25.         //Lets cache!
  26.         $cacheHandle = fopen($cacheName, ‘w+’);
  27.         fwrite($cacheHandle, $newData);
  28.         fclose($cacheHandle);
  29.         $isCached = FALSE;
  30.     }
  31.     //Time to output the data.
  32.     if ($ext == ‘css’) {
  33.         header(“Content-type: text/css”);
  34.         if ($isCached) {
  35.             echo “// Retrieved from cache file. \n”;
  36.         }
  37.     } else {
  38.         if ($isCached) {
  39.             echo ‘<!– Retrieved from cache file. –>’;
  40.         }
  41.     }
  42.     echo $newData;
  43. }

?>

The Explanation

This one’s a bit trickier and a little more likely to leave you scratching you head. But don’t worry, not much has changed and we will go through each section. An extra feature we have included is the refreshing of the cache every 24 hours. This is handy so if you change anything, you can either wait 24 hours or simply empty the cache directory. If you want a different refresh interval just calculate it in seconds.

$cacheName = ‘./cache/’ . $nameExplode[0] . $nameExplode[1] . ‘.tmp’;

This bit of code just gets the file’s name and extension, glues them together and adds the cache directory and the appropriate ‘.tmp’ extension.

  1. if (file_exists($cacheName) AND filemtime($cacheName) > (time() – 86400)) {
  2.     $cacheHandle = fopen($cacheName, ‘r’);
  3.     $newData = fread($cacheHandle, filesize($cacheName));
  4.     fclose($cacheHandle);
  5.     $isCached = TRUE;
  6. } else {

 

Here we’re checking if we have a cache file saved and if the cache file was created within 24 hours. If both these conditions are met then we open the file and extract its contents to substitute for the scripts output. We also set $isCached to true so we can output some messages at the end.

  1. //Lets cache!
  2. $cacheHandle = fopen($cacheName, ‘w+’);
  3. fwrite($cacheHandle, $newData);
  4. fclose($cacheHandle);
  5. $isCache = FALSE;

Now we are caching the output of the script for us to use in later requests. We simply open a file in write mode, dump our data into it and then close it. Strictly you don’t have to close files in PHP but it’s considered a good practise so I have done it here.

  1. //Time to output the data.
  2. if ($ext == ‘css’) {
  3.     header(“Content-type: text/css”);
  4.     if ($isCached) {
  5.         echo “// Retrieved from cache file. \n”;
  6.     }
  7. } else {
  8.     if ($isCached) {
  9.         echo ‘<!– Retrieved from cache file. –>’;
  10.     }
  11. }

This is another part of the script that was modified a little so that we can offer some feedback through the browser. If the file was retrieved from the cache we can add a message to the script’s output. Notice that the message for CSS scripts has ‘\n’ at the end. This is because the characters ‘//’ comment our entire line and ‘\n’ pushes everything else onto another line. If you want to disable the messages all you have to do is comment out the line ‘$isCached = TRUE;’.

Giving it a Whirl

If we use our script again, we will notice no change until we refresh a second time when we will see a message saying that the file was retrieved from cache. Sweet success! This caching setup can also be applied to the first script with little modification, however, that is left as an exercise for the reader.

Concluding

Being able to quickly add simple but effective caching to any script that you are working on is an extremely useful skill. It just adds that extra bit to the script, reducing the load on your server and speeding up the site for users. Now that’s win-win!

Advertisements