Rewriteモジュール+PHPでもっと賢いWebP画像の選択配信


ブラウザのWebP対応/非対応に応じ、ApacheでWebP画像の配信を振り分ける方法について以前、書きました。

.htaccessによるWebPの選択的レスポンスとその問題点と改善案
https://qiita.com/miyanaga/items/6570c3c9ae8e15dbb57c

バッチ処理によるWebPファイルの作成はこちら
https://qiita.com/miyanaga/items/94b5bb42501e2292fb67

オリジナルの画像(Jpeg、PNG、GIF)と、それに対応するWebP画像がある場合、対応ブラウザにはWebP、非対応ブラウザにはオリジナル画像を自動で配信する方法を説明しています。

オリジナル画像差し替え問題

上記の方法は手軽なのですが、弱点があってオリジナル画像を変更して上書きすると次のバッチ処理までWebP画像の不一致が生じてしまいます。

新規の画像であれば、WebP画像がないうちはすべてのブラウザにオリジナル画像が配信されるので問題ないのですが、後でオリジナル画像だけ内容が変更されると、次のバッチ処理までWebP画像の追従を待たなければなりません。

SafariやIEだと新しい画像が表示され、ChromeやFirefoxだと古い画像が表示される時間帯ができてしまいます。

ファイルの更新日も見て比較したいがRewriteでは無理

そこでWebP画像の有無に加え、その更新日がオリジナル画像の更新日より新しいときにWebP画像を配信するようにしたくかなり試行錯誤しましたが、Rewriteモジュールだけでは無理そうでした。

PHPでファイルの更新日も判別してみる

そこで簡単なPHPスクリプトでオリジナル画像とそのWebPフォーマット画像の有無と更新時間を比較して振り分けをするサンプルを作ってみました。

ApacheのRewriteモジュールとPHPによる更新日を考慮したWebP画像の振り分けサンプル
https://github.com/ideamans/php-webp-rewrite-image

気楽に作り始めましたが、ただの静的ファイルのWeb配信でも考えなきゃいけないことが多いもんだなーと再確認…

中小規模のサイトであれば使えそう

PHPを使ってファイルの更新日を比較してWebP画像とオリジナル画像の振り分けを行えば、いつでも気軽に画像を差し替えできて楽ちんです。

一方で画像についてWebサーバーの挙動(キャッシュまわり)が一部、Apache設定ファイルで変更できなくなるのは手間です。

ベンチマーク

それより気になるのは、画像リクエストでPHPを毎回実行することによる遅延と負荷でした。

一応手元のマシンでベンチマークをとってみました。
https://github.com/ideamans/php-webp-rewrite-image#%E3%83%99%E3%83%B3%E3%83%81%E3%83%9E%E3%83%BC%E3%82%AF

一般的なWebサーバーでも平常時であれば数ミリ〜十数ミリ秒くらいの遅延ではないかと思います。

負荷にシビアではない中小規模のサイトで、画像の差し替えが頻繁に行われるような現場で、PHPを使ったこのやり方もありです。

Apache 2.5からはApache単独でできそう!

Apache 2.4から設定ファイルにおいて<If>ディレクティブで動的な条件分岐が記述できるようになったようです。

Apache コア機能
https://httpd.apache.org/docs/2.4/ja/mod/core.html#if

しかもファイルの更新日を取得するfilemod関数もあるじゃん!
https://httpd.apache.org/docs/current/expr.html

…と思ったのですが、どう頑張ってもfilemod関数がエラーに。

しれっとfilemodが書いてありますが、どうやら2.5から使えるようになる模様です。

Apache httpd 2.5.0-aplhaにはfilemodあり
https://github.com/apache/httpd/blob/2.5.0-alpha/server/util_expr_eval.c#L1509

2.4.xにはいまのところfilemodなし
https://github.com/apache/httpd/blob/2.4.41/server/util_expr_eval.c

RewriteRuleIfって組み合わせられるの?と心配しましたが、Apache 2.4系で試したところ大丈夫そうでした。

今度Apache 2.5をビルドして検証してみます。