Caching HTML Output with PHP

This tutorial describes how to cache HTML output with PHP script.
Provided by Leumas Naypoka / www.apphp.com

Contents


Introduction

There are many cases when people would like to create a cache for output of php pages on their website. This technique allows you to reduce a response time and increase productivity of your site. And, one of important things, it's a simple enough and may be used both for small sites and big web portals. It may be also very useful for a code, that performs a lot of "hard-time" operations, like: multiple database requests, long-time running of code parts etc. In other words, it can be very helpful for site optimization.

The main idea behind this technique is that you catch the HTML output, generated by your PHP code (no matter what exactly you use: some PHP Framework or just a plain codding), place this code in some file on your server and define the "life time" for this cache file. Now every time someone browsing this page, your code checks if there is a cache available for a requested page and simply flush to the screen a content of the stored cache file, stopping running the last part of the code. Of course, you have to check the "life time" of this cache file and if it was elapsed, you have to repeat the first steps again.

So.. on the first step you have to create the directory where cache files will be stored, for example: cache/ Also you have to prevent direct access and browsing of this directory. The simplest way to do this is to place in this directory .htaccess file with the following directive. For your cache files you may define any extension you want: .html, .txt or something else; we prefer to use .chh as the cache file extension.

Sample 1. Content of .htaccess file
<FILES ~ "\.chh$">  
    Order allow,deny  
    Deny from all  
</FILES>

Now we create the first (top) part of the caching mechanism.

Sample 2. The first (top) part of the cache mechanism (cache_top.php).
<?php

// get file name
$phpself = isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF']) : '';
$phpself trim($phpself'.php');
// block access if unexpected characters found in the file name
if(preg_match("/:|;|'|\(|\)/"$phpself)) $phpself '';

// define cache file name
$cachefile = ($phpself != '') ? 'cache/'.$phpself.'.chh' '';

if(!empty(
$cachefile) && file_exists($cachefile)){
    
// set lifetime in minutes
    
$cachetime 10 60
  
    
// Serve from the cache if it is younger than $cachetime
    
if((filesize($cachefile) > 0) &&
      ((
time() - $cachetime) < filemtime($cachefile))){
        
// the page has been cached from an earlier request
        // output the contents of the cache file
        
include_once($cachefile); 
        echo 
'<!-- Taken from cache at: '.date('H:i'filemtime($cachefile)).' -->';
        
// exit the script, so that the rest isn't executed
        
exit;
    }        
}
// start the output buffer
ob_start();   
?>

Here the second (bottom) part of this mechanism.

Sample 3. The second (bottom) part of the cache mechanism (cache_bottom.php).
<?php

// open the cache file for writing
if(!empty($cachefile)){
    
$fp = @fopen($cachefile'w'); 
    
// save the contents of output buffer to the file
    
@fwrite($fpob_get_contents());
    
// close the file
    
@fclose($fp);         
}
// Send the output to the browser
ob_end_flush();    
?>

Now we have to include both parts into your PHP file in the following way:

Sample 4. Both parts of the cache mechanism included.
<?php include("cache_top.php"); ?>

<html>
<head>
    <title>Your Page</title>
</head>
<body>
    <h1>Header</h1>
    <p>here the content of your page</p>
</body>
</html>

<?php include("cache_bottom.php"); ?>

How to cache a file with parameters?

The examples we've seen work fine if you want to cache a simple file. But what about a case, where your file has some additional parameters, like this: index.php?page=test&para1=1&param2=2? In such a case we have to store parameters in some way. We can include them in the file name. Let's see how we do this in the following example:

Sample 5. Saving parameters in file name.
<?php

// get file name
$phpself = isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF']) : '';
$phpself trim($phpself'.php');
// block access if unexpected characters found in the file name 
if(preg_match("/:|;|'|\(|\)/"$phpself)) $phpself '';

// retrieve parameters
$page = isset($_GET['page']) ? $_GET['page'] : '';
$param1 = isset($_GET['param1']) ? $_GET['param1'] : '';
$param2 = isset($_GET['param2']) ? $_GET['param2'] : '';

// define cache file name
$cachefile = ($phpself != '') ? 'cache/'.$phpself.'-'.$page.'-'.$param1.'-'.$param2.'.chh' '';

// Output
// cache/index-test-1-2.chh
?>

Encoding file names

Placing parameters in the cache file name is a good way to store them, but what to do if the value of parameter has characters, that are not acceptable in URLs? In this case you can encode cache file name, using some encoding algorithmes, for example md5. Rememeber, that this is only an example of code and you have to care about full validation of parameters you receive.

Sample 6. Encoding file names with parameters.
<?php

// get file name
$phpself = isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF']) : '';
$phpself trim($phpself'.php');
// block access if unexpected characters found in the file name
if(preg_match("/:|;|'|\(|\)/"$phpself)) $phpself '';

// retrieve parameters
$page = isset($_GET['page']) ? $_GET['page'] : '';
$param1 = isset($_GET['param1']) ? $_GET['param1'] : '';
$param2 = isset($_GET['param2']) ? $_GET['param2'] : '';

// define cache file name
$cachefile = ($phpself != '') ? 'cache/'.md5($phpself.'-'.$page.'-'.$param1.'-'.$param2).'.chh' '';

// Output
// cache/25c9b35d591981b5324782dcd640eae5.chh
?>

Now, when you check whether the cache file exists, you do this in the same way:

Sample 7. Full example (cache_top.php).
<?php

// get file name
$phpself = isset($_SERVER['PHP_SELF']) ? basename($_SERVER['PHP_SELF']) : '';
$phpself trim($phpself'.php');
// block access if unexpected characters found in the file name
if(preg_match("/:|;|'|\(|\)/"$phpself)) $phpself '';

// retrieve parameters
$page = isset($_GET['page']) ? $_GET['page'] : '';
$param1 = isset($_GET['param1']) ? $_GET['param1'] : '';
$param2 = isset($_GET['param2']) ? $_GET['param2'] : '';

// define cache file name
$cachefile = ($phpself != '') ? 'cache/'.md5($phpself.'-'.$page.'-'.$param1.'-'.$param2).'.chh' '';

if(!empty(
$cachefile) && file_exists($cachefile)){
    
// set lifetime in minutes
    
$cachetime 10 60
  
    
// Serve from the cache if it is younger than $cachetime
    
if((filesize($cachefile) > 0) &&
      ((
time() - $cachetime) < filemtime($cachefile))){
        
// the page has been cached from an earlier request
        // output the contents of the cache file
        
include_once($cachefile); 
        echo 
'<!-- Taken from cache at: '.date('H:i'filemtime($cachefile)).' -->';
        
// exit the script, so that the rest isn't executed
        
exit;
    }        
}
// start the output buffer
ob_start();   
?>

Conclusion

In this tutorial we've seen one of the possibilities that allows creating a caching mechanism for your website. Now, when you read this article and try to implement this knowledge to your own needs, you may be interested to check a response time of your site, if there are some improvements or not.

There are many resources on the Internet they may check the speed of your site, like:
http://developers.google.com or www.webpagetest.org

You may also download all examples in one archive file:
DOWNLOAD ALL
example files ▼



Comments


Please post only comments related to the original tutorial. Be polite and helpful, do not spam or offend others.
Create Your Free Account
Please remember that this information is essential to use our services correctly.
After creating the account you will be able to download all of our FREE products.
Fields marked with * are mandatory






Please send me information about updates, new products, specials and discounts from ApPHP!
We recommend that your password should be at least 6 characters long and should be different from your username/email. Please use only letters of the English alphabet to enter your name.

Your e-mail address must be valid. We use e-mail for communication purposes (order notifications, etc). Therefore, it is essential to provide a valid e-mail address to be able to use our services correctly.

All your private data is confidential. We will never sell, exchange or market it in any way. Please refer to Privacy Policy.

By clicking "Create Account", you are indicating that you have read and agree to the ApPHP Terms & Conditions.