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.
<?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
?>
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.
<?php
if ($caching == true) //are we generating a cache page?
{
$fp = @fopen($hash, 'w'); //open the cache file
@fwrite($fp, ob_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";
}
?>
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.