2011-12-20 75 views
1

我做了一个简单的数据库驱动的PHP网站。现在我正试图对网站实施一些简单的缓存。我试过这个从某个地方简单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(); ?> 

回答

1

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

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

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

+0

谢谢..多数民众赞成正是我在找..早些时候没有想到LOCK_NB。再次感谢。 – PRYM 2011-12-20 20:43:16

0

我不认为你的源将正常工作,因为你不删除缓存文件

+0

我为什么要删除缓存文件。该文件正在重命名为将用于显示页面的文件。 – PRYM 2011-12-20 19:39:16