圧縮
OxPHP はデフォルトで HTTP レスポンスを Brotli エンコーディングで圧縮します。クライアントが対応している場合、テキストベースのコンテンツタイプに自動的に適用されるため、アプリケーションコードを変更することなく転送サイズが削減されます。
仕組み
OxPHP が圧縮するかどうかを判断する前に、すべてのレスポンスは以下のチェックを順番に通過します。
- Accept-Encoding のチェック。 クライアントの
Accept-Encodingヘッダーが解析され、br(Brotli)のサポートが確認されます。このヘッダーにbrが含まれていないリクエストは圧縮されません。 - コンテンツタイプのチェック。 レスポンスの MIME タイプが、圧縮可能なタイプの一覧と照合されます。
- エンコード済みのチェック。 二重圧縮を避けるため、既に
Content-Encodingヘッダーが設定されているレスポンスはスキップされます。 - サイズ範囲のチェック。 256 バイトから 3 MB の範囲のレスポンスのみが圧縮されます。これより小さいレスポンスは得られる効果が小さく、これより大きいレスポンスはバッファリングせずにストリーミングされます。
- 圧縮。 Brotli エンコーディングが適用されます。圧縮後の出力が元のサイズよりも小さくならない場合は、代わりに非圧縮のレスポンスが送信されます。
圧縮は PHP の実行後、および静的ファイルの配信後に行われます。圧縮されたボディ全体が一時的にメモリ上に保持されるため、3 MB を超えるレスポンスは除外されます。
設定
| Variable | Default | Description |
|---|---|---|
COMPRESSION_LEVEL |
4 |
Brotli の品質レベル(0〜11)。値が高いほど出力は小さくなりますが、その分 CPU 時間を消費します。0 に設定すると圧縮を完全に無効化します |
デフォルトのレベル 4 は、Web 配信における圧縮率と CPU 使用率のバランスを取ったものです。レベル 9〜11 は、オフラインまたはビルド時の圧縮に適しています。
圧縮可能なコンテンツタイプ
圧縮は以下の MIME タイプに適用されます。
テキストタイプ:
text/htmltext/csstext/plaintext/xmltext/javascript
アプリケーションタイプ:
application/javascriptapplication/jsonapplication/xmlapplication/xhtml+xmlapplication/rss+xmlapplication/atom+xmlapplication/manifest+jsonapplication/ld+jsonapplication/wasm
その他のタイプ:
image/svg+xmlfont/ttffont/otfapplication/x-font-ttfapplication/x-font-opentypeapplication/vnd.ms-fontobject
圧縮されないケース
以下のいずれかの条件を満たす場合、レスポンスは圧縮されずに送信されます。
- クライアントが
Accept-Encodingヘッダーでbrを通知していない - レスポンスに既に
Content-Encodingヘッダーが設定されている(例: 圧縮済みのコンテンツ) - レスポンスボディが 256 バイト未満、または 3 MB を超えている
- コンテンツタイプが圧縮可能な一覧に含まれていない(例:
image/png、image/jpeg、font/woff2、application/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 での 確認方法:
curl -H "Accept-Encoding: br" -I http://localhost/レスポンスヘッダーに Content-Encoding: br が含まれているか確認してください。含まれていない場合は、以下を確認してください。
COMPRESSION_LEVELが0に設定されていないこと- レスポンスボディが 256 バイト以上であること
- レスポンスの
Content-Typeが上記の圧縮可能な一覧に含まれていること
圧縮によってレスポンスが大きくなる
非常に小さいレスポンス(数百バイト未満)では、Brotli のオーバーヘッドによって元のサイズよりも大きな出力が生成されることがまれにあります。OxPHP はこれを検出し、自動的に非圧縮のレスポンスを送信します — 設定を変更する必要はありません。
圧縮による CPU 使用率の高騰
高い品質レベル(8〜11)は圧縮率が大幅に向上しますが、CPU をはるかに多く消費します。圧縮による CPU 消費が高いことに気づいた場合は、以下を試してください。
対処法: COMPRESSION_LEVEL を 4 または 5 に下げてください。これらのレベルは、最大品質のサイズ削減効果の 80〜90% を、わずかな CPU コストで実現します。
圧縮済みのアセットが再度圧縮される
ビルドパイプラインが .br ファイルを生成し、それらのファイルに Content-Encoding: br ヘッダーを設定している場合、OxPHP は自動的に再圧縮をスキップします。圧縮済みのコンテンツが再度圧縮されている場合は、圧縮処理が実行される前の元のレスポンスに Content-Encoding ヘッダーが存在することを確認してください。
Docker の例
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