在简单的PHP缓存中写入文件时出错

时间:2011-12-20 19:21:40

标签: php caching

我做了一个简单的数据库驱动的php网站。现在我正在尝试对网站实施一些简单的缓存。我从某个地方试过这个

<?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(); 
?>

但是,如果正在重命名缓存文件并且有人请求该页面,该怎么办?是否会显示错误或只是用户会遇到延迟?

为了减少缓存文件的修改时间,我使用重命名而不是直接写入原始缓存文件

正确代码(基于下面的webbiedave回答)

<?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(); ?>

2 个答案:

答案 0 :(得分:1)

重命名文件不是问题的根源。您的脚本的主要竞争条件是多个请求检测到过期的mtime并且所有写入test2.html

更好的方法是在检测到过期的mtime后立即执行独占的非阻塞flock(假设为非窗口),缓冲输出,覆盖文件并释放锁定。如果flock返回false,则另一个进程正在写入它,当前进程应该完全跳过写入。

如果在锁定期间发出请求,Web服务器将等待文件写入完成(并释放锁定),然后提供文件。

答案 1 :(得分:0)

我认为您的源代码无法正常运行,因为您没有删除缓存文件