PHPで画像を動的に出力する際にキャッシュさせない

この記事は次のブログに引っ越しました。

PHPのGDを使って合成した画像を出力するスクリプトを作って、テスト用に<img>タグをたくさんならべて、変化をチェックしてみた。しかし、URLが変わらないためか、いくつかの画像が表示しきれなかったり、他と同じだったり・・・単発でスクリプトを叩くと、ちゃんと表示されるので、どうやらブラウザのキャッシュが効いているようである。色々調べてみたが、完全にキャッシュをクリアというかキャッシュを使わせないことは難しいらしい。答え PHPでheader情報を出力する際に"Etag"と改行コードを入れる。php 保存されている画像をキャッシュされにくく出力するスクリプト $sFileName = "image.png"; $sFilePath = "./img/" . $sFileName ; if(File_Exists($sFilePath){ //画像データの読み込み if(!($fp = fopen($sFilePath,'rb'))) die(); $iFileSize = FileSize($sFilePath); $img = fread($fp,$iFileSize); fclose($fp); $sEtag = md5_file($sFilePath); //ファイルをMD5したものをEtagのIDとする $aImgInfo = getImageSize($sSavePath); //ファイルの情報を取得 $sMIME = $aImgInfo['mime']; //ファイルの種類(MIME)を取得 header("Cache-Control: no-cache, must-revalidate\n\n"); // HTTP/1.1 header("Expires: Mon, 26 Jul 1997 05:00:00 GMT\n\n"); // 過去の日付 header("Content-type: {$sMIME}\n\n"); // ファイルのMIME出力 header("Content-Disposition: inline; filename={$sFileName}\n\n"); // 保存時ファイル名 header("Etag: \"{$sEtag}\"\n\n"); // Etagの出力 print ($img); //画像データを出力} さすがに F5キーとか、Ctrl+F5キーとかで、激しく更新すると×マークの画像がでることがあるが、それでも以前より表示は安定した(キャッシュされずに最新の画像が表示された)。 注意としては サーバ負荷を減らすためにも、一度作成した画像はサーバ側でも保存(キャッシュ)しておいて、過去に一度リクエスト済みの画像は改めて(作成)処理せずに、保存した画像(キャッシュ画像)を使うのがベターなのである。その際に Etagを見て、Etagと同じ画像ならデータを出力せずに、"304 Not Modified"のヘッダー情報を返せばよりサーバの負荷やレスポンスが軽くなるハズ。経緯 色々試していたわけだが、にっちもさっちもだったので、Firefoxの"Live HTTP headers"プラグインを使って、他のサイトにある画像だけを表示してヘッダー情報を調べたら Etagが送信されていた。 動的HTMLページを作成する際に、昔ハマった記憶がよみがえる。 色々試したけど、最初NGだった結果 header情報で Cache-Control を送信してもキャッシュされることがある header情報で Expires を送信してもキャッシュされることがある imgタグのsrc属性内にランダムな数値を付加してもキャッシュされることがある
(例:src='./image.png?aadf0eadf0ee') header情報に改行コードを入れてみヘッダーの最後に改行コードを2つ("\n\n"を)入れてみたのですが、どうもこれがないとヘッダーが区別されないのか、入れたら少しよくなった。例 header("Cache-Control: no-cache, must-revalidate"); ↓ header("Cache-Control: no-cache, must-revalidate\n\n"); Etagを入れてみた Etagについて詳しくは調べてもらうとして、一言でいうとEtagはデータのID番号というか版番号(バージョン番号)みたいなもの。つまり、Etagが同じなら同じデータであるということですな。 ヘッダーのやり取りのサンプルで php.netのロゴ画像を表示する際のヘッダー情報はこんな感じ。■ブラウザからの画像のリクエスト 以下は「http://jp.php.net/images/php.gifの画像が欲すぃの。手元の画像のEtagは"189c018-9db-f8269940"よ。」の意味。http://jp.php.net/images/php.gif GET /images/php.gif HTTP/1.1 Host: jp.php.net User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.8.1.15) Gecko/20080623 Firefox/2.0.0.15 Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5 Accept-Language: ja,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300 Connection: keep-alive Cookie: LAST_LANG=ja; COUNTRY=JPN%2C122.17.95.69 If-Modified-Since: Mon, 06 Mar 2006 21:11:25 GMT If-None-Match: "189c018-9db-f8269940" Cache-Control: max-age=0 ■サーバからのレスポンス 以下は「Etagが同じなので、変更なし。データは送らないのでキャッシュを使ってね」の意味。 HTTP/1.x 304 Not Modified Date: Wed, 16 Jul 2008 14:28:06 GMT Server: Apache Connection: Keep-Alive Keep-Alive: timeout=15, max=100 Etag: "189c018-9db-f8269940" いずれもFirefoxLive HTTP headers プラグインで見れます。