PHP
Rails
nginx
Apache

PHPでCSSや画像の静的ファイルをキャッシュさせない正しい方法(Rails風味)

More than 1 year has passed since last update.

CSSや画像ファイルを、ユーザーにキャッシュされないで最新のものを見て貰う方法ですが、PHPで良く見かけるのが以下2つのパターン。

(1) WEBサーバの設定でキャッシュを無効にし、毎回ファイルをダウンロードさせる

  <Directory /var/www/project_name/htdocs/css>
    Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
    Header set Pragma "no-cache"
    Header set Expires "Wed, 11 Jan 1984 05:00:00 GMT"
  </Directory>

(2) ファイル生成日時パラメータを渡す

<link rel="stylesheet" href="/css/style.css?20170906130934"/>

(1) は、ページ遷移する度に共通CSSなども強制ダウンロードさせる訳ですから、さすがにエンジニアとして負けた感がありますが、

(2) は更新のタイミングでファイル生成日時パラメータも更新されるので、一見いい感じで動いてくれそうに見えますが、実際はそうではありません。パラメータ付ファイルを同一ファイルと見なさないか否かは、ブラウザ側の仕様によって様々です。

Ruby on Railsの場合

Ruby on Railsでは、これを回避するためにAsset Pipelineのフィンガープリント機能で更新時のみ再アクセスを強制する仕組みを提供しています。以下の通り「style-$hash.css」とファイル名そのものをハッシュ化している訳です。賢い。

<link rel="stylesheet" href="/assets/style-f88b32d7f32262.css" />

PHPだと例えばCakePHPの場合、、、

https://book.cakephp.org/3.0/ja/development/configuration.html

Asset.timestamp
適切なヘルパーを使用した際、アセットファイルの URL (CSS, JavaScript, Image) の終端に そのファイルの最終更新時間のタイムスタンプを加えます。

<link rel="stylesheet" href="/css/style.css?1478939889"/>

mtimeパラメータ方式を謳ってますね。

PHPでRails風味なフィンガープリンティングを実現するには

しかし、Railsのようなアプリケーションサーバ型ではないPHPアプリでは、ファイル名そのものをRailsのように更新のタイミングで変更することは困難です。WEBサーバの設定と組み合わせて実現します

Apache

httpd.conf
AliasMatch ^/css/(.*)(-version-[0-9]*).css$ /var/www/project_name/htdocs/css/$1.css
AliasMatch ^/js/(.*)(-version-[0-9]*).js$ /var/www/project_name/htdocs/js/$1.js
AliasMatch ^/img/(.*)(-version-[0-9]*).jpeg$ /var/www/project_name/htdocs/img/$1.jpeg
AliasMatch ^/img/(.*)(-version-[0-9]*).jpg$ /var/www/project_name/htdocs/img/$1.jpg
AliasMatch ^/img/(.*)(-version-[0-9]*).png$ /var/www/project_name/htdocs/img/$1.png
AliasMatch ^/img/(.*)(-version-[0-9]*).gif$ /var/www/project_name/htdocs/img/$1.gif

PHP

PHP側は以下のようなヘルパーやビューを実装します。

helper.php
function assets($file)
{
    $version = filemtime(DOCROOT.preg_replace('/^\//', '', $file));
    $retval = preg_replace('/(\.css|\.js|\.gif|\.jpg|\.jpeg|\.png)$/', '-version-'.$version.'$1', $file);

    return $retval;
}
view.php
// 自動(ヘルパー)
<link rel="stylesheet" href="<?=assets('/css/style.css')?>" />

// 手動でコーディングする場合は更新日時を書けば良いでしょう
<img src="/img/foo-version-20170906210425.jpg" />

無事、ファイル名にmtimeバージョンが付加されるようになりました。

それでは、良いプログラミング・ライフを!