php 在内容前插入十六进制字符数

Lar*_*bar 4 html php apache utf-8

我正在将网站移动到新服务器。(旧服务器有 php 5.3.2,新服务器有 php 5.5.9)Centos,httpd Apache/2.2.26。

我已经复制了文件,它工作正常,除了唯一奇怪的事情:在页面内容之前插入了一些奇怪的十六进制数字:

在此输入图像描述

另外,在页面底部,0将插入到</html>标签之后。

我注意到两件事:

1)在我的例子中,只有两个标头从 php 脚本发送:

header("HTTP/1.1 200 OK");
header("Status: 200");
Run Code Online (Sandbox Code Playgroud)

如果我评论第一个标题就可以了 - 没有奇怪的数字。

2)看起来这个数字是页面上的字符数(我已经检查过)。如果页面少于 8000 个字符,则不会显示该数字,但如果页面有 8001 个字符,则1F41显示该数字

PS 我被建议从文件中删除所有 BOM。文件没问题——已经没有 BOM 了。所以这与 BOM 无关。

UPD: 我做了一个非常简单的测试(index.php):

<?php header("HTTP/1.1 200 OK"); ?>
Lorem Ipsum ... 8000 characters
Run Code Online (Sandbox Code Playgroud)

一切都好。

<?php header("HTTP/1.1 200 OK"); ?>
Lorem Ipsum ... 8001 characters
Run Code Online (Sandbox Code Playgroud)

Bug 发生1f41在 Lorem Ipsum 之前。

LSe*_*rni 5

这不是 PHP 也不是 BOM。您的内容传输编码有问题。

服务器正在发送客户端显然不知道如何处理的编码(这通常在不可用时完成),或者Chunked组合使客户端相信它可以绕过分块Content-Length

因此,“下一个块的长度”实际上是由客户端解释的,您将其视为内容之前的十六进制位:

05
These
05
 Are 
03
the
1F
 first characters of the senten
03
ce.
Run Code Online (Sandbox Code Playgroud)

代替

Content-Length: 48
These are the first characters of the sentence.
Run Code Online (Sandbox Code Playgroud)

我用肉眼计算的长度,他们可能是错的

可能的原因是您有某种干扰内容编码的缓冲。如果所有内容都保留在缓冲区中,那么一切都很好,内容长度可用,被发送,鲍勃是你的叔叔。但是,如果您发送的缓冲区超过 8000 字节,缓冲区就会被刷新,并且会发生一些意外情况。尝试查看 zlib 和输出缓冲的文档,您可能会在php.iniApache 的操作和 PHP 的操作之间遇到一些冲突。

有趣的链接显示了 8000 到底是(曾经是?)在 apache 的某些部分中使用的缓冲区大小:

https://bugs.php.net/bug.php?id=45945

https://serverfault.com/questions/366996/how-can-the-apache-2-2-deflate-module-length-limit-be-increased

最后一个链接建议我建议您尝试检查 zlib、mod_gzip、ob_gzhandler 和/或 mod_deflate 是否已启用,并且可能存在冲突,或者尝试将其中一个替换为另一个。

更新(根据评论)

添加适当的传输编码标头可以解决该问题。

那么究竟发生了什么?我们知道输出是正确分块编码的(即分块本身是正确的),并且客户端在被告知后能够解释它。因此,缺少的只是内容被分块的知识,这看起来很荒谬,而且有点错误对于任何分块的内容,都必须知道它会被分块(哦!),因此它有责任添加适当的内容标头,但它没有(或者确实有,但其他东西剥夺了它),直到OP纠正了这种情况,自己手动添加了标头。

问题现在已经解决了,但我认为工作流程中的某个地方肯定仍然存在一个错误,无论是在模块中、应用程序中,还是在标头的处理方式中。