2009年8月28日 星期五

[引用] 讓瀏覽器快取 PHP 產生的圖片 或 不快取圖片

引用: 人生海海

由於 stickeraction 的關係, 貼出去的貼紙讓我的主機流量暴增, 覺得這樣下去這個月的 100G 流量一定會爆, 所以對於貼出去的貼紙做了一些處理, 讓瀏覽器快取住, 多少可以減少一些流量, 其實一開始就該做了 XD 只是沒有意識到, 完全沒有經驗 XD 而且工作上也比較沒有流量的考量, 所以這次也學到了些東西。

原本在主機上就都有設定 lighttpd, 讓圖片, js 跟 css 檔產生 etag、expire 跟 last modified … 等的 HTTP headers, 利用瀏覽器的快取機制來減少主機的流量。 不過由 PHP 產生的圖片完全沒有 cache, 今天才改了一下程式, 加上一些 header, 來減少流量的支出, 不然這個月主機流量穩爆 ~」~

$file = 'foo.jpg';
$file_etag = fileinode($file);
$file_mtime = gmstrftime("%a, %d %b %Y %T %Z", filemtime($file));

$header_etag =
array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)?$_SERVER['HTTP_IF_NONE_MATCH']:false;
$header_mtime =
array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)?$_SERVER['HTTP_IF_MODIFIED_SINCE']:false;

if ($header_etag == '"'.$file_etag.'"'
AND $header_mtime == $file_mtime) {
header('HTTP/1.1 304 Not Modified');
} else {
header("Content-Type: " . $content_type);
header("Content-Length: " . filesize($file));
header("Last-Modified: " . $file_mtime);
header('ETag: "'.$file_etag.'"');
readfile($file);
}

由於是輸出圖片, 所以 Content-Type 是一定要的, 然後還有 Content-Length, 比較重要的就是 Last-Modified 跟 ETag 這兩個 header 了, 送出這些 header 之後, 下次在瀏覽器在 request 同一張圖片時, 瀏覽器的 request header 就會送出 If-Modified-Since 跟 If-None-Match, 所以只要我們可以取得這兩個 header, 就可以判斷是否要在送出一次圖片, 如果這兩個 header 的數值都沒變, 那麼就可以告訴瀏覽器說不用在抓圖片了阿, 就丟個 304 Not Modified 的 header 回去就可以了, 就也不用再輸出圖片了。

由於我是用 lighttpd, 所以直接對 $_SERVER 變數來存取 headers , 如果是用 apache 的話可以看看 apache_request_headers 這個函式, 取得的變數名稱跟 header 一樣, 會比較直覺一點。

不過還有一些其他的 header, 像是 expire、max-age 跟 cache-control 這還要再研究一下 ~」~ 至少要可以控制哪時候過期嘛。


header("Cache-Control: private");
header("Cache-Control: no-cache", false);
header("Cache-Control: no-store, no-cache, must-revalidate", false);
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache");

這樣不論 local 還是 proxy 都不會留下你的圖片了。這個方法可以把檢查 referer 的工作交給 PHP,比使用 apache 較有彈性。

【下列文章您可能也有興趣】

沒有留言: