2009-09-06 106 views
20

我對如何緩存圖像完全陌生。如何讓瀏覽器緩存圖片,用PHP?

我用php輸出圖庫中的所有圖像,並希望已經顯示的圖像被瀏覽器緩存,所以php-script不必再輸出相同的圖像。我想要的是圖像顯示更快。

調用一個圖像,當我這樣做:

<img src="showImage.php?id=601"> 

showImage.php -file做:

$resultat = mysql_query(" 
    SELECT filename, id 
    FROM Media 
    WHERE id = '".$_GET['id']."' 
"); 
$data = mysql_fetch_assoc($resultat); 

... 

//Only if the user are logged in 
if(isset($_SESSION['user'])){ 
    header("Content-Type: image/jpeg"); 

    //$data['filename'] can be = dsSGKLMsgKkD3325J.jpg 
    echo(file_get_contents("images/".$data['filename']."")); 
} 
+0

我不知道你想什麼來完成,從原來的問題,聽起來就好像你生成的飛行圖像和希望在第一次加載時緩存生成的圖像,並在後續加載時從磁盤提供服務。你在談論瀏覽器緩存嗎? – 2009-09-06 15:50:06

+1

爲什麼你使用PHP腳本呢? – Gumbo 2009-09-06 15:50:42

+0

是的,我希望瀏覽器緩存圖像。 – Johan 2009-09-06 15:51:20

回答

4

如果您在輸出消息之前使用php來檢查用戶是否已登錄,那麼您不希望瀏覽器緩存圖像。

緩存的全部重點是調用服務器一次,然後再不再調用它。如果瀏覽器緩存圖像,它將不會調用服務器,腳本也不會運行。相反,即使用戶不再登錄,瀏覽器也會將您的映像從緩存中取出並顯示出來。這可能是一個非常大的安全漏洞。

+0

嗯,這是一個很好的觀點。但是,將圖像存儲一個小時就可以了。 – Johan 2009-09-06 16:43:52

+1

即使一個小時也不安全,所有這一切都是希望黑客在某個時間不會嘗試破解。但是,從我在http://www.mnot.net/cache_docs/#SCRIPT中看到的內容看起來,您可以在HTTP標頭中使用「Cache-control:public,no-cache;」強制進行身份驗證('no-cache'實際上並不意味着沒有緩存;名字有點不對)。 – Imagist 2009-09-06 16:59:48

+3

您仍然可以緩存*和*讓瀏覽器調用服務器。它被稱爲緩存驗證。你可以通過發送'Cache-control:private,must-revalidate'(private,因爲它不應該在用戶之間共享)和'Last-Modified'或者'ETag'頭文件來做到這一點。然後當瀏覽器發送'If-Modified-Since'或'If-None-Match'時,如果由於圖像已經生成而沒有任何變化,則以狀態「304」響應。 – Kornel 2013-02-15 10:36:00

48

首先,如果你使用的會話,必須禁用session_cache_limiter(通過將其設置爲nonepublic)。它發送的頭對緩存來說是相當糟糕的。

session_cache_limiter('none'); 

然後發送Cache-Control: max-age=number_of_seconds和任選的等效Expires:報頭。

header('Cache-control: max-age='.(60*60*24*365)); 
header('Expires: '.gmdate(DATE_RFC1123,time()+60*60*24*365)); 

爲了獲得最佳的高速緩存能力,發送Last-Modified頭以及如果所述瀏覽器發送一個匹配If-Modified-Since頭用狀態304和空體回覆。

header('Last-Modified: '.gmdate(DATE_RFC1123,filemtime($path_to_image))); 

爲了簡便起見,我在這裏作弊位(該示例不驗證日期),但你不介意的瀏覽器保持緩存的文件永遠是隻要有效:

if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 
    header('HTTP/1.1 304 Not Modified'); 
    die(); 
} 
+0

是的,我正在使用'sessions'。嗯,看起來你說的是我所需要的,但我不明白如何將它們合併到工作代碼中。如果我希望瀏覽器將圖像緩存一年,該如何編寫? – Johan 2009-09-06 16:01:12

+0

非常感謝,它對我來說非常適合這麼棒!謝謝thnaks! :) – ParisNakitaKejser 2014-05-12 06:55:20

+0

'If-Modified-Since''位是「d'oh」或「eureka!」時刻,無論你喜歡什麼! – Agamemnus 2015-01-17 09:06:07

3

您可以存儲生成的圖像在一個名爲「showImage」目錄中,這樣,你會嵌入他們這樣

<img src="showimage/601.jpg" /> 

然後你把.htaccess文件中,將調用showImage.php非常相同的目錄? ID =的情況下,該文件不存在,如:

<IfModule mod_rewrite.c> 
    RewriteEngine On 
    RewriteCond %{REQUEST_FILENAME} !-f 
    RewriteRule ^(.*)\.jpg$ showImage.php?id=$1 [QSA,L] 
</IfModule> 

在您的評論剛看完,你想要做的客戶端緩存:只要根據http://www.mnot.net/cache_docs/

設置緩存相關的HTTP頭

請注意,您的查詢很容易受到SQL注入,因爲你不消毒/逃避$ _GET [ '身份證']:http://php.net/mysql_real_escape_string

0

請不要地址圖片是一些id'ed資源。爲圖片使用絕對網址,最好在子網域中使用,最好使用Cookie。瀏覽器將對圖像執行緩存。在網站上更快加載圖像的巧妙方法是將其放置在某個CDN或其他網站上。這是因爲瀏覽器將並行請求線程的數量限制爲一個域。

另一種處理圖像的方法很簡單,就是查看圖像。它節省了大量的帶寬和請求。

如果速度如此重要,您也可以使用直接位圖加載。儘管這並不建議用於大圖像。如果它的圖標和小圖片/你正在加載的gif。您可以直接在頁面上使用位圖。

7

下面是一些代碼,我使用304頭支持:

/** 
    * @return false if not cached or modified, true otherwise. 
    * @param bool check_request set this to true if you want to check the client's request headers and "return" 304 if it makes sense. will only output the cache response headers otherwise. 
    **/  
    protected function sendHTTPCacheHeaders($cache_file_name, $check_request = false) 
    { 
    $mtime = @filemtime($cache_file_name); 

    if($mtime > 0) 
    { 
     $gmt_mtime = gmdate('D, d M Y H:i:s', $mtime) . ' GMT'; 
     $etag = sprintf('%08x-%08x', crc32($cache_file_name), $mtime); 

     header('ETag: "' . $etag . '"'); 
     header('Last-Modified: ' . $gmt_mtime); 
     header('Cache-Control: private'); 
     // we don't send an "Expires:" header to make clients/browsers use if-modified-since and/or if-none-match 

     if($check_request) 
     { 
     if(isset($_SERVER['HTTP_IF_NONE_MATCH']) && !empty($_SERVER['HTTP_IF_NONE_MATCH'])) 
     { 
      $tmp = explode(';', $_SERVER['HTTP_IF_NONE_MATCH']); // IE fix! 
      if(!empty($tmp[0]) && strtotime($tmp[0]) == strtotime($gmt_mtime)) 
      { 
      header('HTTP/1.1 304 Not Modified'); 
      return false; 
      } 
     } 

     if(isset($_SERVER['HTTP_IF_NONE_MATCH'])) 
     { 
      if(str_replace(array('\"', '"'), '', $_SERVER['HTTP_IF_NONE_MATCH']) == $etag) 
      { 
      header('HTTP/1.1 304 Not Modified'); 
      return false; 
      } 
     } 
     } 
    } 

    return true; 
    }