Content-Length header が送信されない | PHP Walker

Content-Length header が送信されない

PHPからzipファイルなどを読み込んで出力する際に Content-Length header を送信しておくと、ブラウザ側でダウンロードの進捗が表示されてユーザーにとって親切だと思う。

しかし、以下のPHPファイルを

<?php
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="a.zip"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize('a.zip'));
readfile('a.zip');
?>

実行するも LiveHTTPHeaders で確認するとヘッダーが

HTTP/1.x 200 OK
Date: Thu, 28 Jan 2010 08:09:10 GMT
Server: Apache
Content-Disposition: attachment; filename="a.zip"
Content-Transfer-Encoding: binary
Vary: Accept-Encoding
Content-Encoding: gzip
Keep-Alive: timeout=4, max=48
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/octet-stream

となり、Content-Length header が出力されていない。もちろんブラウザでの進捗も表示されない。

調べた結果、Apache の mod_deflate (mod_gzip) が導入されているのが原因であった。
そこで、先述のPHPを以下のように変更することで対応できる。

<?php
apache_setenv('no-gzip', '1'); // ← apache環境変数に deflate(gzip) 無効をセット

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="a.zip"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize('a.zip'));
readfile('a.zip');
?>

ヘッダーも

HTTP/1.x 200 OK
Date: Thu, 28 Jan 2010 08:09:10 GMT
Server: Apache
Content-Disposition: attachment; filename="a.zip"
Content-Transfer-Encoding: binary
Content-Length: 4774298
Keep-Alive: timeout=4, max=48
Connection: Keep-Alive
Content-Type: application/octet-stream

に変わり、ブラウザの進捗も表示された。