简体   繁体   English

内容长度标头未正确设置

[英]Content-length header not being set correctly

I have a php script (actually https://drupal.org/project/file_force ) that is forcing users who click on a link to download that link by adding the correct headers to the response. 我有一个php脚本(实际上是https://drupal.org/project/file_force ),它通过向响应中添加正确的标题来强制点击链接的用户下载该链接。

This link works fine 90% of the time. 此链接在90%的时间内都能正常工作。 Occasionally the incorrect content-length is being passed so users are getting apparently truncated files. 有时会传递不正确的内容长度,因此用户显然会截断文件。 The mistake happens consistently on particular files, but if those files are re-uploaded, the error may not appear on the new instance, which makes me think this is not an issue with the files, but instead a cache somewhere. 错误在特定文件上一致地发生,但如果重新上载这些文件,则错误可能不会出现在新实例上,这使我认为这不是文件的问题,而是某个地方的缓存。 So I ran clearstatcache() every time to no avail. 所以我每次都运行clearstatcache()无济于事。 What is odd is that php is passing the correct file size, or says it is when I pass the string it's inserting to a log file. 奇怪的是,php正在传递正确的文件大小,或者说它是在我传递它插入日志文件的字符串时。

Here's the relevant code: 这是相关的代码:

  clearstatcache();
  return array(
    'Content-Type: ' . $mimeinfo,
    'Content-Disposition: ' . $disposition . '; filename="' . basename($filepath) . '";',
    // Content-Length is also a good header to send, as it allows the browser to
    // display a progress bar correctly.
    // There's a trick for determining the file size for files over 2 GB. Nobody
    // should be using this module with files that large, but… the sprintf()
    // trickery makes sure the value is correct for files larger than 2GB. See
    // note at http://php.net/filesize
    'Content-Length: ' . sprintf('%u', filesize($filepath)),
  );

A sample output from sprintf('%u', filesize($filepath)) on a file that isn't working is 2682059 which somehow gets translated to 1740048 when the browser gets to see it. 来自sprintf('%u',filesize($ filepath))的示例输出在一个不起作用的文件上是2682059 ,当浏览器看到它时,它以某种方式被转换为1740048

I've tried removing the sprintf function to no avail. 我试过删除sprintf函数无济于事。 I've also tried not including a Content-Length declaration at all, but someone one is getting attached with the incorrect value anyway. 我也尝试过根本不包括Content-Length声明,但是无论如何,有人正在附加不正确的值。 This last piece of evidence perhaps suggests some other code is overriding the content headers I'm setting here, yet it appears to be leaving alone any other headers that I change in the above code to test that theory. 最后一条证据可能表明其他一些代码覆盖了我在这里设置的内容标题,但它似乎只留下我在上面的代码中更改的任何其他标题来测试该理论。

Any thoughts for where to look? 有什么想法去哪儿看?

I resolved the issue. 我解决了这个问题。

Turns out another module within Drupal was adding its own content-length header and getting the value from a database rather than the file directly (weird), and it was happening down stream. 事实证明,Drupal中的另一个模块正在添加自己的内容长度标头并从数据库而不是文件直接获取值(奇怪),并且它正在下游发生。 By reversing the order that the modules got their hands on the headers, the issue went away. 通过颠倒模块在标题上的顺序,问题就消失了。 I have filed a bug report against the offending module. 我已经针对违规模块提交了一份错误报告。

SOURCES: PHP official documentation - "header" function 来源: PHP官方文档 - “标题”功能

There's a function in PHP called header that you would like to use to set headers, before the actual page loads: 在实际页面加载之前,您希望在PHP中使用一个名为header的函数来设置标题:

Here's the skeleton of the function: 这是函数的骨架:

void header ( string $string [, bool $replace = true [, int $http_response_code ]] )

Explanation: 说明:

Parameters: 参数:

  • string

The header string. 标题字符串。

There are two special-case header calls. 有两种特殊情况的标题调用。 The first is a header that starts with the string "HTTP/" (case is not significant), which will be used to figure out the HTTP status code to send. 第一个是以字符串“HTTP /”开头的标题(大小写不重要),它将用于确定要发送的HTTP状态代码。 For example, if you have configured Apache to use a PHP script to handle requests for missing files (using the ErrorDocument directive), you may want to make sure that your script generates the proper status code. 例如,如果您已将Apache配置为使用PHP脚本来处理丢失文件的请求(使用ErrorDocument指令),则可能需要确保脚本生成正确的状态代码。

  • replace 更换

The optional replace parameter indicates whether the header should replace a previous similar header, or add a second header of the same type. 可选的replace参数指示标头是应该替换先前的类似标头,还是添加相同类型的第二个标头。 By default it will replace, but if you pass in FALSE as the second argument you can force multiple headers of the same type. 默认情况下它将替换,但如果您传入FALSE作为第二个参数,则可以强制使用相同类型的多个标头。

  • http_response_code http_response_code

Forces the HTTP response code to the specified value. 强制HTTP响应代码为指定值。 Note that this parameter only has an effect if the string is not empty. 请注意,如果字符串不为空,则此参数仅起作用。

=== ===

Return Values: 返回值:

No value is returned. 没有返回任何值。


Example: 例:

<?php
    header('Location: http://www.example.com/'); //redirect to www.example.com
?>

Note: The function must be called before any output is sent, ie before any HTML tags or before any echo calls. 注意: 必须在发送任何输出之前调用该函数,即在任何HTML标记之前或任何echo调用之前。

in your case: 在你的情况下:

<?php
    header('Content-Length: ' . sprintf('%u', filesize($filepath)));
?>

the replace parameter which is by default - true, will cause your program to overwrite all previously set 'Content-Length' headers.. 默认情况下的替换参数 - true,将导致程序覆盖之前设置的所有'Content-Length'标头。

Hope all the explanation was worth it... :) 希望所有的解释都值得... :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM