Reputation: 533
I made a simple database driven php website. Now i am trying to implement some simple caching to the site. i tried this from somewhere
<?php
$reqfilename="test";
$cachetime = 60*5; // 5 minutes
$cachefile = "cache/".$reqfilename.".html";
$cf2="cache/".$reqfilename."2.html";
if (file_exists($cachefile) && ((time() - $cachetime) < filemtime($cachefile)))
{
include($cachefile);
exit;
}
ob_start();
?>
CONTENT OF THE PAGE GOES HERE
<?php
$fp = @fopen($cf2, 'w');
if($fp){
fwrite($fp, ob_get_contents());
fclose($fp);
rename($cf2,$cachefile);
}
ob_end_flush();
?>
But what if the cache file is being renamed and someone requests the page. Will there be an error displayed or just the user will experience a delay?
To reduce the time of the cache file being modified only, I am using rename instead of directly writing on the original cache file
Correct code to do this (based on answer by webbiedave below)
<?php
$reqfilename="test";
$cachetime = 60*5; // 5 minutes
$cachefile = "cache/".$reqfilename.".html";
if (file_exists($cachefile) && ((time() - $cachetime) < filemtime($cachefile)))
{
include($cachefile);
exit;
}
ob_start();
?>
CONTENT OF THE PAGE GOES HERE
<?php
$fp = @fopen($cachefile, 'w');
if (flock($fp, LOCK_EX | LOCK_NB)) {
fwrite($fp, ob_get_contents());
flock($fp, LOCK_UN);
fclose($fp);
}
ob_end_flush(); ?>
Upvotes: 1
Views: 771
Reputation: 48887
Renaming the file isn't the source of your problem. The main race condition with your script is multiple requests detecting an expired mtime and all writing to test2.html
.
A better approach is to perform an exclusive, non-blocking flock (assuming non-windows) immediately after detecting an expired mtime, buffer the output, overwrite the file and release the lock. If flock
returns false, then another process is writing to it and the current process should skip the write entirely.
If a request is made during the lock, the web server will wait until the file write is complete (and the lock released), then serve the file.
Upvotes: 1
Reputation: 41
I don't think your source will work properly because you don't delete the cache-file
Upvotes: 0