gzipされたファイルのContent-Lengthを決定する方法は?
-
03-07-2019 - |
質問
今、 mod_gzip
または mod_deflate
を有効にできないサーバーからCSSおよびJSファイルを提供しようとしています。そこで、GZIPで圧縮してユーザーに戻るための小さなPHPスクリプトを作成しました。
サンプルコード:
$filename = "style.css";
if (!file_exists($filename) || !($info = stat($filename))) {
header("HTTP/1.1 404 Not Found");
die();
}
header("Date: ".gmdate("D, j M Y H:i:s e", time()));
header("Cache-Control: max-age=2592000");
header("Last-Modified: ".gmdate("D, j M Y H:i:s e", $info['mtime']));
header("Etag: ".sprintf("\"%x-%x-%x\"", $info['ino'], $info['size'], $info['mtime']));
header("Accept-Ranges: bytes");
header("Cache-Control: Expires ".gmdate("D, j M Y H:i:s e", $info['mtime']+2592000));
header("Content-Type: text/html");
ob_start("ob_gzhandler");
echo file_get_contents($filename);
ob_end_flush();
今、2つの問題があります。 1つは、圧縮ファイルの結果のサイズを判断して、ブラウザにコンテンツの長さを知らせるのに問題があることです。通常、次の行を含めます。
header("Content-Length: ".$info["size"]);
しかし、私がそうするなら、さらなるデータを待っている間にブラウザがハングします。合計サイズを計算する方法はありますか?または、このヘッダーディレクティブを無視する必要があります。
もう1つの問題は、FirefoxでこのPHPファイルを表示するたびに、結果をダウンロードさせようとすることです。 Chromeでは、期待どおりに表示されます。提案はありますか?
編集: SoapBoxのおかげで、コードの末尾を次のように置き換えました:
header("Content-Encoding: gzip");
$compressed = gzencode(file_get_contents($filename), 5);
header("Content-Length: ".strlen($compressed));
die($compressed);
これは、コンテンツの長さに最適です!しかし、Firefoxにファイルを表示する代わりにダウンロードさせるようにしています。 :(
再編集: Cletusの好意により修正されたコードの終わりのコードです。
// Start buffered output
ob_start();
// Check for gzip capability
if (stripos(今、 mod_gzip
または mod_deflate
を有効にできないサーバーからCSSおよびJSファイルを提供しようとしています。そこで、GZIPで圧縮してユーザーに戻るための小さなPHPスクリプトを作成しました。
サンプルコード:
$filename = "style.css";
if (!file_exists($filename) || !($info = stat($filename))) {
header("HTTP/1.1 404 Not Found");
die();
}
header("Date: ".gmdate("D, j M Y H:i:s e", time()));
header("Cache-Control: max-age=2592000");
header("Last-Modified: ".gmdate("D, j M Y H:i:s e", $info['mtime']));
header("Etag: ".sprintf("\"%x-%x-%x\"", $info['ino'], $info['size'], $info['mtime']));
header("Accept-Ranges: bytes");
header("Cache-Control: Expires ".gmdate("D, j M Y H:i:s e", $info['mtime']+2592000));
header("Content-Type: text/html");
ob_start("ob_gzhandler");
echo file_get_contents($filename);
ob_end_flush();
今、2つの問題があります。 1つは、圧縮ファイルの結果のサイズを判断して、ブラウザにコンテンツの長さを知らせるのに問題があることです。通常、次の行を含めます。
header("Content-Length: ".$info["size"]);
しかし、私がそうするなら、さらなるデータを待っている間にブラウザがハングします。合計サイズを計算する方法はありますか?または、このヘッダーディレクティブを無視する必要があります。
もう1つの問題は、FirefoxでこのPHPファイルを表示するたびに、結果をダウンロードさせようとすることです。 Chromeでは、期待どおりに表示されます。提案はありますか?
編集: SoapBoxのおかげで、コードの末尾を次のように置き換えました:
header("Content-Encoding: gzip");
$compressed = gzencode(file_get_contents($filename), 5);
header("Content-Length: ".strlen($compressed));
die($compressed);
これは、コンテンツの長さに最適です!しかし、Firefoxにファイルを表示する代わりにダウンロードさせるようにしています。 :(
再編集: Cletusの好意により修正されたコードの終わりのコードです。
<*>
Firefoxがファイルをダウンロードしようとし続ける理由を理解するために、新しい質問を始めます。
SERVER['HTTP_ACCEPT_ENCODING'], "gzip") !== false) {
ob_start("ob_gzhandler");
echo file_get_contents($filename);
ob_end_flush();
} else
echo file_get_contents($filename);
// Write the content length
header('Content-Length: '.ob_get_length());
ob_end_flush();
Firefoxがファイルをダウンロードしようとし続ける理由を理解するために、新しい質問を始めます。
解決
ここでの問題は、クライアントがgzipエンコーディングをサポートしているかどうかを知る必要があるコンテンツの長さを知るために、ob_gzhandlerを使用してその決定を委任したことです。 HTTPヘッダーから:
ob_start(); ob_start('ob_gzhandler'); ... output the page content... ob_end_flush(); // The ob_gzhandler one header('Content-Length: '.ob_get_length()); ob_end_flush(); // The main one
完全版:
$filename = "style.css";
if (!file_exists($filename) || !($info = stat($filename))) {
header("HTTP/1.1 404 Not Found");
die();
}
header("Date: ".gmdate("D, j M Y H:i:s e", time()));
header("Cache-Control: max-age=2592000");
header("Last-Modified: ".gmdate("D, j M Y H:i:s e", $info['mtime']));
header("ETag: ".sprintf("\"%x-%x-%x\"", $info['ino'], $info['size'], $info['mtime']));
header("Accept-Ranges: bytes");
header("Expires: ".gmdate("D, j M Y H:i:s e", $info['mtime']+2592000));
header("Content-Type: text/css"); // note: this was text/html for some reason?
ob_start();
ob_start("ob_gzhandler");
echo file_get_contents($filename);
ob_end_flush();
header('Content-Length: '.ob_get_length());
ob_end_flush();
これは、gzipエンコーディングの問題を自分で処理するよりもずっと優れています。
他のヒント
最初にgzip全体を実行し、結果を測定する必要があります(メモリにコンテンツを保持するか、圧縮してディスクに書き込み、gzip圧縮されたファイルをstat's)、次にContent-Lengthヘッダーを書き込んでから、ファイルの内容を送信します。
またはチャンク転送エンコードを使用します。
Firefoxの問題を解決するには、 header(&quot; Content-Encoding:gzip&quot;);
を含めて、ブラウザがコンテンツを解凍することを認識できるようにする必要があると思います。
コンテンツの長さについては、この値をそのままにしておくか、「Transfer-Encoding:chunked」を使用する方法を見つけてください。 (このヘッダーをjsut送信することはできません。特別にデータをフォーマットする必要があります)。 ob_end_flush
が自動的にチャンクを有効にする可能性があります。
wiresharkを取得し、phpスクリプトが送信するものをキャプチャし、適切に動作するサーバーと比較して、欠落しているヘッダーなどを確認することをお勧めします。