您可以验证PHP接收Content-Length
到的标头的值。
该值应该在运行 POST 查询时在客户端计算。如果它不匹配,那就是你的错误。这就是您需要的所有诊断 - 如果 Content-Length 与 POST 数据不匹配,则拒绝 POST 为无效;不需要额外的参数(但计算 POST 数据长度可能很麻烦)。此外,您可能想调查为什么 PHP 在解码 POST并因此能够验证其长度时,似乎接受了错误的长度(也许检测错误所需的信息在$_SERVER
变量中的某处?)。
如果它确实匹配,并且仍然没有到达数据(即,Content-Length
较小,并且正确描述了截止 POST),则证明 POST在截止后被检查,因此要么错误在浏览器中(或者,不太可能,在 jQuery 中),或者浏览器和服务器(代理?)之间存在接收不完整查询(内容长度>实际长度)并且错误地重写它的东西,使其在服务器看来是“正确的”,而不是立即拒绝它。
对理论和解决方法的一些测试
内容提要:我把前者弄错了,但后者显然是对的。有关在我的测试系统(Linux OpenSuSE 12.3、Apache)上运行的示例,请参见下面的代码。
我相信错误的请求Content-Length
会被拒绝400 Bad Request
。我错了。看来至少我的 Apache更宽容了。
我使用这个简单的 PHP 代码来访问我感兴趣的关键变量
<?php
$f = file_get_contents("php://input");
print $_SERVER['CONTENT_LENGTH'];
print "\nLen: " . strlen($f) . "\n";
?>
然后我准备了一个错误的请求,Content-Length
使用nc
:
POST /p.php HTTP/1.0
Host: localhost
Content-Length: 666
answer=42
...你瞧,nc localhost 80 < request
不会产生 400 错误:
HTTP/1.1 200 OK
Date: Fri, 14 Jun 2013 20:56:07 GMT
Server: Apache/2.2.22 (Linux/SUSE)
X-Powered-By: PHP/5.3.17
Vary: Accept-Encoding
Content-Length: 12
Content-Type: text/html
666
Len: 10
然后我想到,如果请求以回车结束,内容长度可能会减少一到两个,以及什么回车 - LF?CRLF?. 但是,当我添加简单的 HTML 以便能够从浏览器发布它时
<form method="post" action="?"><input type="text" name="key" /><input type="submit" value="go" /></form>
我能够验证在 Firefox(最新)、IE8、Chrome(最新)中,所有在 XP Pro SP3 上运行的 Content-Length 的值strlen
与php://input
.
除非请求被切断,否则。
唯一的问题是即使对于数据php://input
也不总是可用的。POST
这让我们仍然陷入困境:
如果错误发生在网络级别,即 POST 已准备好并提供了正确的 Content-Length,但中断导致整个数据被切断,因为 Horen 的评论似乎表明:
所以只有前几个post参数到达,有时一个参数的值甚至在中间被打断
那么真正的检查Content-Length
将阻止 PHP 处理一个不完整的请求:
<?php
if ('POST' == $_SERVER['SERVER_PROTOCOL'])
{
if (!isset($_SERVER['Content-Length']))
{
header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request', True, 400);
die();
}
if (strlen(file_get_contents('php://input'))!=(int)($_SERVER['Content-Length']))
{
header($_SERVER['SERVER_PROTOCOL'] . ' 400 Bad Request', True, 400);
die();
}
}
// ... go on
?>
另一方面,如果问题出在 jQuery 中,即以某种方式中断会阻止 jQuery组装完整的 POST,但 POST 是由不完整的数据计算得出的 Content-Length 以及发送的数据包 - 那么我的解决方法不可能工作,并且必须使用“telltale”额外字段,或者......也许.post
jQuery中的函数可能会扩展为包含CRC字段?