2009-12-28 41 views
51

我有一個PHP 5.1.0網站(實際上它是5.2.9,但它也必須在5.1.0+上運行)。如何在PHP中使用HTTP緩存標頭

頁面是動態生成的,但其中大部分都是靜態的。靜態我的意思是內容不會改變,但內容周圍的「模板」會隨着時間而改變。

我知道他們已經有幾個緩存系統和PHP框架,但我的主機沒有安裝APC或Memcached,我沒有爲這個特定的項目使用任何框架。

我想頁面被緩存(我認爲默認PHP「禁止」緩存)。到目前爲止,我使用:

session_cache_limiter('private'); //Aim at 'public' 
session_cache_expire(180); 
header("Content-type: $documentMimeType; charset=$documentCharset"); 
header('Vary: Accept'); 
header("Content-language: $currentLanguage"); 

我看了很多教程,但我找不到簡單的東西(我知道緩存是複雜的東西,但我只需要一些基本的東西)。

什麼是「必須」有標題發送來幫助緩存?

謝謝!

+5

歡迎來到StackOverflow。偉大的第一個問題 – Sampson 2009-12-29 05:11:50

回答

40

你可能想使用private_no_expire代替private,而是設置一個長的到期內容你知道是不會改變的,並確保您處理類似埃米爾的職位if-modified-sinceif-none-match請求。凡$etag可以基於內容或用戶ID,語言和時間戳,例如校驗和

$tsstring = gmdate('D, d M Y H:i:s ', $timestamp) . 'GMT'; 
$etag = $language . $timestamp; 

$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? $_SERVER['HTTP_IF_MODIFIED_SINCE'] : false; 
$if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ? $_SERVER['HTTP_IF_NONE_MATCH'] : false; 
if ((($if_none_match && $if_none_match == $etag) || (!$if_none_match)) && 
    ($if_modified_since && $if_modified_since == $tsstring)) 
{ 
    header('HTTP/1.1 304 Not Modified'); 
    exit(); 
} 
else 
{ 
    header("Last-Modified: $tsstring"); 
    header("ETag: \"{$etag}\""); 
} 

$etag = md5($language . $timestamp); 
+2

你所描述的將是一個弱電子標籤,應該有一個「W /」前綴。 – 2012-11-09 09:29:24

+0

我還會添加「Expires」標頭,因爲有些託管服務提供商(例如服務器)無論如何都會發送它,而且他們會以過去的日期方式進行操作,而我認爲它應該是在將來。 – Sasho 2013-03-02 05:00:48

+5

如果您沒有獲得上述304s,請檢查HTTP_IF_NONE_MATCH中是否有任何雜散的引號。用'rtrim'替換'$ if_none_match == $ etag'(ltrim($ if_none_match,「'」),「'\」「)== $ etag'。 – ReactiveRaven 2013-04-11 11:24:49

7
<?php 
header("Expires: Sat, 26 Jul 2020 05:00:00 GMT"); // Date in the future 
?> 

設置緩存頁面的到期日期是在客戶端緩存它的一種有用方法。

+0

好,並且使用session_cache_limiter和session_cache_expire已經處理了這一點。 – AlexV 2009-12-29 14:11:46

6

請選擇 - 或全部使用它們! :-)

 
header('Expires: Thu, 01-Jan-70 00:00:01 GMT'); 
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); 
header('Cache-Control: no-store, no-cache, must-revalidate'); 
header('Cache-Control: post-check=0, pre-check=0', false); 
header('Pragma: no-cache'); 
+0

session_cache_limiter和session_cache_expire已經控制Expires,Cache-Control,Last-Modified和Pragma ... – AlexV 2009-12-29 14:08:34

+0

我明白了。你是對的。而且我也看到我沒有很好地閱讀你的問題。對不起 – 2009-12-29 14:42:45

11

您必須有一個Expires標題。從技術上講,還有其他解決方案,但Expires頭部確實是最好的解決方案,因爲它告訴瀏覽器不要在到期日期和時間之前重新檢查頁面,只是從緩存中提供內容。它的工作非常棒!

檢查來自瀏覽器的請求中的If-Modified-Since標頭也是有用的。如果瀏覽器的「緩存」中的內容仍然是正確的版本,則「不確定」這個標頭。如果您的頁面從那時起未被修改,只需發送一個HTTP 304代碼(未修改)。下面是發送一個304碼十分鐘的例子:

<?php 
if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 
    if(strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) < time() - 600) { 
    header('HTTP/1.1 304 Not Modified'); 
    exit; 
    } 
} 
?> 

你可以把這張支票早在你的代碼,以節省服務器資源。

+0

這不好,如果你不使用Apache。 – Geoffrey 2015-03-18 02:07:59

2

我正在做json緩存在服務器來自facebook飼料什麼都沒有工作,直到我把刷新和隱藏錯誤報告。 我知道這個惡魔的代碼,但希望快速修復儘快。

error_reporting(0); 
    $headers = apache_request_headers(); 
    //print_r($headers); 
    $timestamp = time(); 
    $tsstring = gmdate('D, d M Y H:i:s ', $timestamp) . 'GMT'; 
    $etag = md5($timestamp); 
    header("Last-Modified: $tsstring"); 
    header("ETag: \"{$etag}\""); 
    header('Expires: Thu, 01-Jan-70 00:00:01 GMT'); 

    if(isset($headers['If-Modified-Since'])) { 
      //echo 'set modified header'; 
      if(intval(time()) - intval(strtotime($headers['IF-MODIFIED-SINCE'])) < 300) { 
       header('HTTP/1.1 304 Not Modified'); 
       exit(); 
      } 
    } 
    flush(); 
//JSON OP HERE 

工作就像魅力。

+1

如果您沒有將字段名稱$ headers ['If-Modified-Since']設置爲大寫字母 - > $ headers ['IF-MODIFIED-SINCE] – 2013-10-08 15:49:10

6

這是一個爲你做http緩存的小類。它有一個名爲'Init'的靜態函數,它需要2個參數,一個頁面(或瀏覽器請求的任何其他文件)最後修改日期的時間戳以及該頁面可以保存的最大時間(以秒爲單位)由瀏覽器緩存。

class HttpCache 
{ 
    public static function Init($lastModifiedTimestamp, $maxAge) 
    { 
     if (self::IsModifiedSince($lastModifiedTimestamp)) 
     { 
      self::SetLastModifiedHeader($lastModifiedTimestamp, $maxAge); 
     } 
     else 
     { 
      self::SetNotModifiedHeader($maxAge); 
     } 
    } 

    private static function IsModifiedSince($lastModifiedTimestamp) 
    { 
     $allHeaders = getallheaders(); 

     if (array_key_exists("If-Modified-Since", $allHeaders)) 
     { 
      $gmtSinceDate = $allHeaders["If-Modified-Since"]; 
      $sinceTimestamp = strtotime($gmtSinceDate); 

      // Can the browser get it from the cache? 
      if ($sinceTimestamp != false && $lastModifiedTimestamp <= $sinceTimestamp) 
      { 
       return false; 
      } 
     } 

     return true; 
    } 

    private static function SetNotModifiedHeader($maxAge) 
    { 
     // Set headers 
     header("HTTP/1.1 304 Not Modified", true); 
     header("Cache-Control: public, max-age=$maxAge", true); 
     die(); 
    } 

    private static function SetLastModifiedHeader($lastModifiedTimestamp, $maxAge) 
    { 
     // Fetching the last modified time of the XML file 
     $date = gmdate("D, j M Y H:i:s", $lastModifiedTimestamp)." GMT"; 

     // Set headers 
     header("HTTP/1.1 200 OK", true); 
     header("Cache-Control: public, max-age=$maxAge", true); 
     header("Last-Modified: $date", true); 
    } 
} 
+0

謝謝!! Good Work !! – 2014-01-22 11:33:51