PRYM
PRYM

Reputation: 533

Error during file write in simple PHP caching

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

Answers (2)

webbiedave
webbiedave

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

Simon Strasser
Simon Strasser

Reputation: 41

I don't think your source will work properly because you don't delete the cache-file

Upvotes: 0

Related Questions