mylaboratory
Title image
 
Home
 
Software
 
Raytracer
 
Recipes
 
Photos
 
Mashup
 

PHP Page Cache

This bit of code generates and serves cached copies of web pages to speed up generation and reduce server load. Hopefully there aren't too many security holes in it, but if you see any, please let me know.

The first code block should be included (include_once) in a web page above the start of the output that needs caching. And similarly the second should be included at the end of the cached part.

It starts by checking for $_POST variables as it doesn't make sense to cache such pages. An MD5 hash of the file name is generated to create a unique cache file. The file name is created from the script name and request string since the passed URI may differ for the same page (eg / and /index.php are the same file).

If the cache file doesn't exist then output buffering (the thing that sends output to an internal buffer rather than the browser) is switched on and the page is executed. If the cache does exist then the modification time is compared to the source modification time. If the cache is older it is regenerated, otherwise it is read to the ouput and the script exits.

$dtime is used to fix the offset in time between the modified stamp created on the script file when I upload it, and the generated cache file (the server's clock is wrong by about an hour and twenty minutes). ignore_user_abort allows the script to continue, even if the user closes their browser window so that the cache is faithfully generated. Finally, $diskroot.$cachedir is the path on disk to the cache file directory.

Alt
<?php
//PHP page cache by Simon Chorley, 2007/08/07
//Feel free to modify and redistribute.

    //do hit counting session starting etc here

    
if (!$_POST)    //don't cache files with POST variables
    
{
        
//Generate has name from script name so that we are using the actual served script file
        
$uri $_SERVER['SCRIPT_NAME'].((strlen($_SERVER['QUERY_STRING']) != 0) ? "?".$_SERVER['QUERY_STRING'] : "");
        
$hash $diskroot.$cachedir.md5($uri).".cache";    //generate cache file name
        
if (file_exists($hash))    //check that this file exists
        
{
            
$dtime 4440;    //time difference between server and my computer
            
$ct filemtime($hash)-$dtime;    //cache modification time
            
$st filemtime($_SERVER['SCRIPT_FILENAME']);    //script modification time
            
if ($ct $st)    //is it stale?
            
{    //then regenerate
                
ignore_user_abort(true);    //don't want to stop if the user closes their browser window
                
$caching true;    //tell then closing script that we are generating a cache page
                
ob_start();    //start output buffering to record the page
            
}
            else
            {
                
readfile($hash);    //we have a good cache page so print the file
                
echo "<!-- Cache: ".$ct.", Source: ".$st." -->\n<!-- Used cached file. -->\n";
                exit;    
//exit processing
            
}
        }
        else    
//no cache page. start one
        
{
            
ignore_user_abort(true);
            
$caching true;
            
ob_start();
        }
    }
    
//If we are here then the page is processed as normal
?>
Alt
 01  <?php
 02  
//PHP page cache by Simon Chorley, 2007/08/07
 03  //Feel free to modify and redistribute.
 04  
 05      //do hit counting session starting etc here
 06  
 07      
if (!$_POST)    //don't cache files with POST variables
 08      
{
 09          
//Generate has name from script name so that we are using the actual served script file
 10          
$uri = $_SERVER['SCRIPT_NAME'].((strlen($_SERVER['QUERY_STRING']) != 0) ? "?".$_SERVER['QUERY_STRING'] : "");
 11          
$hash = $diskroot.$cachedir.md5($uri).".cache";    //generate cache file name
 12          
if (file_exists($hash))    //check that this file exists
 13          
{
 14              
$dtime = 4440;    //time difference between server and my computer
 15              
$ct = filemtime($hash)-$dtime;    //cache modification time
 16              
$st = filemtime($_SERVER['SCRIPT_FILENAME']);    //script modification time
 17              
if ($ct < $st)    //is it stale?
 18              
{    //then regenerate
 19                  
ignore_user_abort(true);    //don't want to stop if the user closes their browser window
 20                  
$caching = true;    //tell then closing script that we are generating a cache page
 21                  
ob_start();    //start output buffering to record the page
 22              
}
 23              else
 24              {
 25                  
readfile($hash);    //we have a good cache page so print the file
 26                  
echo "<!-- Cache: ".$ct.", Source: ".$st." -->\n<!-- Used cached file. -->\n";
 27                  exit;    
//exit processing
 28              
}
 29          }
 30          else    
//no cache page. start one
 31          
{
 32              
ignore_user_abort(true);
 33              
$caching = true;
 34              
ob_start();
 35          }
 36      }
 37      
//If we are here then the page is processed as normal
 38  
?>

The final part of the code takes the buffered output and saves it to the cache file and writes it to the screen. The @ infront of the file commands suppress error messages if the script is unable to write the file.

Alt
<?php
    
if ($caching == true)    //are we generating a cache page?
    
{
        
$fp = @fopen($hash'w');    //open the cache file
        
@fwrite($fpob_get_contents());    //write the output buffer to it
        
@fclose($fp);        //close cache
        
ob_end_flush();    //flush the cache to the browser too
        
ignore_user_abort(false);    //swtich off
        
echo "<!-- Cache: ".$ct.", Source: ".$st." -->\n";
        echo 
"<!-- Generated page cache. -->\n";
    }
?>
Alt
 01  <?php
 02      
if ($caching == true)    //are we generating a cache page?
 03      
{
 04          
$fp = @fopen($hash, 'w');    //open the cache file
 05          
@fwrite($fp, ob_get_contents());    //write the output buffer to it
 06          
@fclose($fp);        //close cache
 07          
ob_end_flush();    //flush the cache to the browser too
 08          
ignore_user_abort(false);    //swtich off
 09          
echo "<!-- Cache: ".$ct.", Source: ".$st." -->\n";
 10          echo
"<!-- Generated page cache. -->\n";
 11      }
 12  
?>
 13  

Download the source files:

If you have any comments or suggestions please e-mail me at code@ my domain.

Bottom image