2011-12-20 76 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