圧縮

OxPHP はデフォルトで HTTP レスポンスを Brotli エンコーディングで圧縮します。クライアントが対応している場合、テキストベースのコンテンツタイプに自動的に適用されるため、アプリケーションコードを変更することなく転送サイズが削減されます。

仕組み

OxPHP が圧縮するかどうかを判断する前に、すべてのレスポンスは以下のチェックを順番に通過します。

  1. Accept-Encoding のチェック。 クライアントの Accept-Encoding ヘッダーが解析され、br(Brotli)のサポートが確認されます。このヘッダーに br が含まれていないリクエストは圧縮されません。
  2. コンテンツタイプのチェック。 レスポンスの MIME タイプが、圧縮可能なタイプの一覧と照合されます。
  3. エンコード済みのチェック。 二重圧縮を避けるため、既に Content-Encoding ヘッダーが設定されているレスポンスはスキップされます。
  4. サイズ範囲のチェック。 256 バイトから 3 MB の範囲のレスポンスのみが圧縮されます。これより小さいレスポンスは得られる効果が小さく、これより大きいレスポンスはバッファリングせずにストリーミングされます。
  5. 圧縮。 Brotli エンコーディングが適用されます。圧縮後の出力が元のサイズよりも小さくならない場合は、代わりに非圧縮のレスポンスが送信されます。
Note

圧縮は PHP の実行後、および静的ファイルの配信後に行われます。圧縮されたボディ全体が一時的にメモリ上に保持されるため、3 MB を超えるレスポンスは除外されます。

設定

Variable Default Description
COMPRESSION_LEVEL 4 Brotli の品質レベル(0〜11)。値が高いほど出力は小さくなりますが、その分 CPU 時間を消費します。0 に設定すると圧縮を完全に無効化します

デフォルトのレベル 4 は、Web 配信における圧縮率と CPU 使用率のバランスを取ったものです。レベル 9〜11 は、オフラインまたはビルド時の圧縮に適しています。

圧縮可能なコンテンツタイプ

圧縮は以下の MIME タイプに適用されます。

テキストタイプ:

  • text/html
  • text/css
  • text/plain
  • text/xml
  • text/javascript

アプリケーションタイプ:

  • application/javascript
  • application/json
  • application/xml
  • application/xhtml+xml
  • application/rss+xml
  • application/atom+xml
  • application/manifest+json
  • application/ld+json
  • application/wasm

その他のタイプ:

  • image/svg+xml
  • font/ttf
  • font/otf
  • application/x-font-ttf
  • application/x-font-opentype
  • application/vnd.ms-fontobject

圧縮されないケース

以下のいずれかの条件を満たす場合、レスポンスは圧縮されずに送信されます。

  • クライアントが Accept-Encoding ヘッダーで br を通知していない
  • レスポンスに既に Content-Encoding ヘッダーが設定されている(例: 圧縮済みのコンテンツ)
  • レスポンスボディが 256 バイト未満、または 3 MB を超えている
  • コンテンツタイプが圧縮可能な一覧に含まれていない(例: image/pngimage/jpegfont/woff2application/zip — これらのフォーマットは既に内部で圧縮を使用しています)
  • レスポンスがストリーミングされる — ヘッダー送信時にその長さが不明である場合(oxphp_stream_flush() を使用する PHP スクリプトや Server-Sent Events)。ストリームを圧縮するにはメモリ上で全体をバッファリングする必要があり、time-to-first-byte を損なうため、ストリーミングされるレスポンスは常に非圧縮のまま通過します

レスポンスヘッダー

圧縮が適用されると、OxPHP は以下のヘッダーを設定します。

Header Value
Content-Encoding br
Content-Length 圧縮後のボディサイズに更新されます
Vary Accept-Encoding が追加され、HTTP キャッシュが Brotli 対応クライアントと非対応クライアントとで別々のバージョンを保存するようにします

トラブルシューティング

レスポンスが圧縮されない

クライアントが Accept-Encoding: br を送信していることを確認してください。最近のブラウザのほとんどは送信しますが、一部の HTTP テストツールはデフォルトでこれを含めません。

curl での 確認方法:

bash
curl -H "Accept-Encoding: br" -I http://localhost/

レスポンスヘッダーに Content-Encoding: br が含まれているか確認してください。含まれていない場合は、以下を確認してください。

  1. COMPRESSION_LEVEL0 に設定されていないこと
  2. レスポンスボディが 256 バイト以上であること
  3. レスポンスの Content-Type が上記の圧縮可能な一覧に含まれていること
圧縮によってレスポンスが大きくなる

非常に小さいレスポンス(数百バイト未満)では、Brotli のオーバーヘッドによって元のサイズよりも大きな出力が生成されることがまれにあります。OxPHP はこれを検出し、自動的に非圧縮のレスポンスを送信します — 設定を変更する必要はありません。

圧縮による CPU 使用率の高騰

高い品質レベル(8〜11)は圧縮率が大幅に向上しますが、CPU をはるかに多く消費します。圧縮による CPU 消費が高いことに気づいた場合は、以下を試してください。

対処法: COMPRESSION_LEVEL4 または 5 に下げてください。これらのレベルは、最大品質のサイズ削減効果の 80〜90% を、わずかな CPU コストで実現します。

圧縮済みのアセットが再度圧縮される

ビルドパイプラインが .br ファイルを生成し、それらのファイルに Content-Encoding: br ヘッダーを設定している場合、OxPHP は自動的に再圧縮をスキップします。圧縮済みのコンテンツが再度圧縮されている場合は、圧縮処理が実行される前の元のレスポンスに Content-Encoding ヘッダーが存在することを確認してください。

Docker の例

compose.yaml
services: app: image: ghcr.io/oxphp/oxphp:0.10.0 ports: - "8080:80" volumes: - ./src:/var/www/html environment: - DOCUMENT_ROOT=/var/www/html/public - ENTRY_FILE=index.php - COMPRESSION_LEVEL=6

関連項目