我的脚本通过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;
这样的优点/缺点,我都必须这样做。之前它的工作原理如下,所以我完全希望它现在可以正常工作。任何见解都是真诚的感谢!
这是一个简单的脚本来举例说明我的问题。有两个文件:
<?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. :-(';
}
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问题吗?)我已经看到了启用发送分块编码但不接收分块编码的设置。
答案 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)
我遇到了同样的问题。
没有任何修饰符的正常fopen
:fopen("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刚刚在一周前发布,因此也暗示可能存在尚未找到的漏洞。
您还可以尝试测试降级是否有帮助。