如何确定压缩文件的内容长度?

2022-01-11 00:00:00 gzip http-headers header php

现在我正在尝试从不允许我启用 mod_gzipmod_deflate 的服务器提供 CSS 和 JS 文件.于是写了一个PHP小脚本,用GZIP压缩后返回给用户.

示例代码:

$filename = "style.css";if (!file_exists($filename) || !($info = stat($filename))) {header("HTTP/1.1 404 未找到");死();}header("日期:".gmdate("D, j M Y H:i:s e", time()));header("缓存控制: 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("接受范围:字节");header("Cache-Control: Expires ".gmdate("D, j M Y H:i:s e", $info['mtime']+2592000));header("内容类型:文本/html");ob_start("ob_gzhandler");回声文件获取内容($文件名);ob_end_flush();

我现在有两个问题.首先是,我无法确定压缩文件的最终大小以通知浏览器内容长度.通常,我会包括这一行:

header("内容长度:".$info["size"]);

但是,如果我这样做了,浏览器会在尝试等待更多数据时挂起.有没有办法计算总大小?或者我应该忽略这个头指令.

另一个问题是,每当我在 Firefox 中查看这个 PHP 文件时,它都会尝试让我下载结果.在 Chrome 中,它只是像我期望的那样显示它.有什么建议吗?

感谢 SoapBox,我将代码末尾替换为:

header("Content-Encoding: gzip");$compressed = gzencode(file_get_contents($filename), 5);header("内容长度:".strlen($compressed));死($压缩);

这对内容长度非常有用!但我仍然让 Firefox 下载文件而不是显示它.:(

再次这是修改后的代码结尾代码,由 Cletus 提供.

//开始缓冲输出ob_start();//检查 gzip 功能if (stripos($_SERVER['HTTP_ACCEPT_ENCODING'], "gzip") !== false) {ob_start("ob_gzhandler");回声文件获取内容($文件名);ob_end_flush();} 别的回声文件获取内容($文件名);//写入内容长度header('内容长度:'.ob_get_length());ob_end_flush();

我要提出一个新问题来弄清楚为什么 Firefox 一直尝试下载文件.

解决方案

这里的问题是,要知道内容长度,您需要知道客户端是否支持 gzip 编码,并且您已经使用 ob_gzhandler 委派了该决定.来自 HTTP 标头:

<块引用>

ob_start();ob_start('ob_gzhandler');...输出页面内容...ob_end_flush();//ob_gzhandler 之一header('内容长度:'.ob_get_length());ob_end_flush();//主要的

完整版:

$filename = "style.css";if (!file_exists($filename) || !($info = stat($filename))) {header("HTTP/1.1 404 未找到");死();}header("日期:".gmdate("D, j M Y H:i:s e", time()));header("缓存控制: 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("接受范围:字节");header("过期时间:".gmdate("D, j M Y H:i:s e", $info['mtime']+2592000));header("内容类型:文本/css");//注意:这是 text/html 出于某种原因?ob_start();ob_start("ob_gzhandler");回声文件获取内容($文件名);ob_end_flush();header('内容长度:'.ob_get_length());ob_end_flush();

这比自己处理 gzip 编码问题好多了.

Right now I'm trying to serve CSS and JS files from a server that won't let me enable mod_gzip or mod_deflate. So I wrote a small PHP script to compress with GZIP and return to the user.

Example Code:

$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();

I'm having two problems right now. The first is, I'm having trouble determining the resulting size of the compressed file to inform the browser of the content-length. Normally, I would include this line:

header("Content-Length: ".$info["size"]);

But, if I do, the browser hangs while trying to wait for more data. Is there a way to calculate the total size? Or should I ignore this header directive.

The other issue is, whenever I view this PHP file in Firefox, it tries to have me download the result. In Chrome, it just displays it like I would expect. Any suggestions?

Edit: Thanks to SoapBox, I replaced the end of the code with this:

header("Content-Encoding: gzip");
$compressed = gzencode(file_get_contents($filename), 5);
header("Content-Length: ".strlen($compressed));
die($compressed);

This works great for the content-length! But I'm still getting Firefox to download the file instead of display it. :(

Edit Again: Here is the modified end-of-code code, courtesy of Cletus.

// Start buffered output
ob_start();
// Check for gzip capability
if (stripos($_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();

I'm going to start a new question to figure out why Firefox keeps trying to download the file.

解决方案

The problem here is that to know the content length you need to know whether or not the client supports gzip encoding and you've delegated that decision by using ob_gzhandler. From HTTP Headers:

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

Complete version:

$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();

This is much better than taking on the gzip encoding issue yourself.

相关文章