升级到PHP 5.3后未填充$ HTTP_RAW_POST_DATA

时间:2012-01-17 17:47:56

标签: php post

我的脚本通过POST从桌面应用程序接收gzip压缩数据,它从$HTTP_RAW_POST_DATA检索并处理。在PHP 5.2.16(ISAPI)中,$HTTP_RAW_POST_DATA正确填充了预期的二进制数据。升级到PHP 5.3.9(FastCGI)后,未定义$HTTP_RAW_POST_DATA。我怎样才能获得数据?

我在32位Windows XP SP3下运行IIS 5.1。


'的docs regarding $HTTP_RAW_POST_DATA状态不适用于enctype =“multipart / form-data”',但我没有使用该内容类型。 (回想一下,在PHP 5.2下,相同的代码工作正常,因此内容类型也是一个问题。)

当我启用always_populate_raw_post_data ini 指令时,没有任何更改。 phpinfo()报告设置为“开启”,但变量仍未设置。

文档还建议获取此数据的首选方法是从php://input流中读取它。我尝试了如下:

$HTTP_RAW_POST_DATA = file_get_contents('php://input');

但脚本只是挂在那一行上,大概是因为它在等待数据(即没有发送文件结束)。即使我将maxlength限制为一个小到一个字节的值,如下所示,它仍然会挂起。

$HTTP_RAW_POST_DATA = file_get_contents('php://input', false, null, -1, 1);

当我将 maxlen 设置为0时,它唯一没有挂在该行上,这意味着它不会尝试读取任何内容但也没有帮助。 : - )

如果强制使用$HTTP_RAW_POST_DATA时不会填充php://input,我无法从php://input获取任何内容,我该如何获取数据?

$_SERVER显然是空的,这表明ISAPI和FastCGI之间存在差异吗?我没有看到任何暗示原始POST表现不同或在FastCGI下丢失的内容。


以下是[CONTENT_LENGTH] => 4294967295 [CONTENT_TYPE] => application/client-gzip [HTTP_HOST] => 127.0.0.1 [HTTP_CONTENT_TYPE] => application/client-gzip [HTTP_TRANSFER_ENCODING] => chunked [HTTP_ACCEPT_ENCODING] => gzip [HTTP_EXPECT] => 100-continue [REQUEST_METHOD] => POST [SERVER_NAME] => 127.0.0.1 [SERVER_PORT] => 80 [SERVER_PROTOCOL] => HTTP/1.1 的一些相关部分。在使用PHP 5.2和PHP 5.3运行脚本之间,所有这些值都是相同的。

CONTENT_LENGTH

(注意:我知道4GB内容长度看起来很奇怪,但由于它使用的是chunked encoding,因此会忽略CONTENT_LENGTH。)

由于没有使用$HTTP_RAW_POST_DATA标头,我有什么方法可以验证某些地方确实正在接收数据并且IIS没有丢失数据?

由于数据是从桌面客户端的二进制库发送的,因此无法更改POST的格式。无论使用<?php $headers = array( "Content-Type: application/client-gzip", // "Transfer-Encoding: chunked", ); $text = 'This text is superior to your text even though it is useless.'; $data = gzdeflate($text); echo "text: $text<br />gzip: $data<br />"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://localhost/server/postreceive.php"); curl_setopt($ch, CURLOPT_USERPWD, "user:pass"); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $result = curl_exec($ch); echo $result; 这样的优点/缺点,我都必须这样做。之前它的工作原理如下,所以我完全希望它现在可以正常工作。任何见解都是真诚的感谢!


更新

这是一个简单的脚本来举例说明我的问题。有两个文件:

postsend.php

<?php
if (!empty($HTTP_RAW_POST_DATA)) {
    printf(
        'HTTP_RAW_POST_DATA set!<br />gzip:%s<br />text: %s',
        $HTTP_RAW_POST_DATA,
        gzinflate($HTTP_RAW_POST_DATA)
    );
} else {
    echo 'No raw data. :-(';
}

postreceive.php

text: This text is superior to your text even though it is useless.
gzip: ÉÈ,V(I­(QÒÅ¥©E™ùE %ù •ù¥E‰Ô²Ô<…’ŒüÒô …L°ºÒâÔœÔâb=
HTTP_RAW_POST_DATA set!
gzip: ÉÈ,V(I­(QÒÅ¥©E™ùE %ù •ù¥E‰Ô²Ô<…’ŒüÒô …L°ºÒâÔœÔâb=
text: This text is superior to your text even though it is useless.

在PHP 5.3(FastCGI)下,这在我运行postsend.php时有效,输出为:

Transfer-Encoding

但是,如果我使用{{1}}标题取消注释该行,那么当我运行postsend.php时,所有内容都会挂起。因此,接收分块编码似乎打破了它。

是否有一些我缺少的IIS或FastCGI配置允许在接收分块编码时使用它? (如果是这样,现在这更适合作为ServerFault问题吗?)我已经看到了启用发送分块编码但不接收分块编码的设置。

4 个答案:

答案 0 :(得分:1)

$_SERVER['HTTP_EXPECT']的存在向我建议,此请求可能没有数据,您需要在客户端回复数据之前回复HTTP/1.1 100 Continue。见the http spec on the use of Expect and 100 Continue。但是,我不知道为什么file_get_contents('php://input')不会立即返回一个空字符串。

另外,我不确定IIS + FastCGI是否支持没有缓冲的分块传输编码。有一个transferMode IIS设置可能对调查很有用。

最后,如果您确实这样做了,请注意您可能需要“解除”(解码transfer-encoding: chunked正文)请求输入,即使您之前不必执行此操作。您可以像这样使用它:

$fp = fopen('php://input', 'rb');
stream_filter_append($fp, 'dechunk', STREAM_FILTER_READ);
$HTTP_RAW_POST_DATA = stream_get_contents($fp);

如果您需要在PHP上执行此操作&lt; 5.3,我写了http_unchunk_filter stream filter做了同样的事情。

答案 1 :(得分:1)

我遇到了同样的问题。

没有任何修饰符的正常fopenfopen("php://input")给了我一个“假”。 fopen("php://input","rb")工作了。

答案 2 :(得分:1)

最终在bug report #60826中确定,此问题是由Web堆栈中的PHP引起的 这是FastCGI在各种Web服务器中实现的缺点。

答案 3 :(得分:0)

this bug entry表明它破坏了5.1版本的php以及5.2版本。如果他们在5.3版本中也将它打破了,我也不会感到惊讶,所以我建议在那里打开一个bug。 5.3.9刚刚在一周前发布,因此也暗示可能存在尚未找到的漏洞。

您还可以尝试测试降级是否有帮助。