如何从PHP套接字请求中隔离HTTP头/正文

如何从PHP套接字请求中隔离HTTP头/正文,php,apache,http,http-headers,Php,Apache,Http,Http Headers,我正在使用PHP中的套接字连接将数据发布到Apache Web服务器。我对这项技术有点陌生,我不知道如何将标题与响应主体隔离开来 发送代码: <?php // collect data to post $postdata = array( 'hello' => 'world' ); $postdata = http_build_query($postdata); // open socket, send request $fp = fsockopen('127.0.0.1',

我正在使用PHP中的套接字连接将数据发布到Apache Web服务器。我对这项技术有点陌生,我不知道如何将标题与响应主体隔离开来

发送代码:

<?php
// collect data to post
$postdata = array(
    'hello' => 'world'
);
$postdata = http_build_query($postdata);
// open socket, send request
$fp = fsockopen('127.0.0.1', 80);
fwrite($fp, "POST /server.php HTTP/1.1\r\n");
fwrite($fp, "Host: fm1\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: ".strlen($postdata)."\r\n");
fwrite($fp, "Connection: close\r\n");
fwrite($fp, "\r\n");
fwrite($fp, $postdata);
// go through result
$result = "";
while(!feof($fp)){
    $result .= fgets($fp);
}
// close
fclose($fp);
// display result
echo $result;
?>

服务器代码:

Hello this is server. You posted:
<pre>
<?php print_r($_POST); ?>
</pre>
你好,这里是服务器。您发布了:
HTTP/1.1 200 OK
Date: Fri, 06 Jan 2012 09:55:27 GMT
Server: Apache/2.2.15 (Win32) mod_ssl/2.2.15 OpenSSL/0.9.8m PHP/5.3.2
X-Powered-By: PHP/5.3.2
Content-Length: 79
Connection: close
Content-Type: text/html

Hello this is server. You posted:
<pre>
Array
(
    [hello] => world
)
</pre>
list($header, $body) = explode("\r\n\r\n", $response, 2);
HTTP/1.0 200 OK Server: CouchDB/1.6.1 (Erlang OTP/R16B02) ETag: "DJNMQO5WQIBZHFMDU40F1O94T" Date: Mon, 06 Jul 2015 09:37:33 GMT Content-Type: text/plain; charset=utf-8 Cache-Control: must-revalidate 
{"total_rows":0,"offset":0,"rows":[
// Couch DB adds some extra line breakers on this line
]}
当发布到一台服务器时,我得到:

HTTP/1.1 200 OK
Date: Fri, 06 Jan 2012 10:02:04 GMT
Server: Apache/2
X-Powered-By: PHP/5.2.17
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html

4d
Hello this is server. You posted:
<pre>
Array
(
    [hello] => world
)
</pre>
0
HTTP/1.1200正常
日期:2012年1月6日星期五09:55:27 GMT
服务器:Apache/2.2.15(Win32)mod_ssl/2.2.15 OpenSSL/0.9.8m PHP/5.3.2
X-Powered-By:PHP/5.3.2
内容长度:79
连接:关闭
内容类型:text/html
你好,这里是服务器。您发布了:
HTTP/1.1 200 OK
Date: Fri, 06 Jan 2012 09:55:27 GMT
Server: Apache/2.2.15 (Win32) mod_ssl/2.2.15 OpenSSL/0.9.8m PHP/5.3.2
X-Powered-By: PHP/5.3.2
Content-Length: 79
Connection: close
Content-Type: text/html

Hello this is server. You posted:
<pre>
Array
(
    [hello] => world
)
</pre>
list($header, $body) = explode("\r\n\r\n", $response, 2);
HTTP/1.0 200 OK Server: CouchDB/1.6.1 (Erlang OTP/R16B02) ETag: "DJNMQO5WQIBZHFMDU40F1O94T" Date: Mon, 06 Jul 2015 09:37:33 GMT Content-Type: text/plain; charset=utf-8 Cache-Control: must-revalidate 
{"total_rows":0,"offset":0,"rows":[
// Couch DB adds some extra line breakers on this line
]}
排列 ( [你好]=>世界 )
正如所料。我想去掉标题,然后从“你好,这是服务器…”开始读正文。 如何可靠地检测标题的结尾并将正文读入变量

另外,我测试过的另一台服务器的回复如下:

list($header, $body) = preg_split("/\R\R/", $response, 2);
HTTP/1.1200正常
日期:2012年1月6日星期五格林威治标准时间10:02:04
服务器:Apache/2
X-Powered-By:PHP/5.2.17
连接:关闭
传输编码:分块
内容类型:text/html
4d
你好,这里是服务器。您发布了:
HTTP/1.1 200 OK
Date: Fri, 06 Jan 2012 09:55:27 GMT
Server: Apache/2.2.15 (Win32) mod_ssl/2.2.15 OpenSSL/0.9.8m PHP/5.3.2
X-Powered-By: PHP/5.3.2
Content-Length: 79
Connection: close
Content-Type: text/html

Hello this is server. You posted:
<pre>
Array
(
    [hello] => world
)
</pre>
list($header, $body) = explode("\r\n\r\n", $response, 2);
HTTP/1.0 200 OK Server: CouchDB/1.6.1 (Erlang OTP/R16B02) ETag: "DJNMQO5WQIBZHFMDU40F1O94T" Date: Mon, 06 Jul 2015 09:37:33 GMT Content-Type: text/plain; charset=utf-8 Cache-Control: must-revalidate 
{"total_rows":0,"offset":0,"rows":[
// Couch DB adds some extra line breakers on this line
]}
排列 ( [你好]=>世界 ) 0
正文文本周围的“4d”和“0”是什么

谢谢


PS在有人说使用CURL之前,很遗憾我不能:-(

标题应该以
“\r\n\r\n”
(两次)结尾。这些4d0可能是php响应的一部分(它们不是标题的一部分).

您可以通过在双换行符上拆分来将标题与正文分开。它应该是
,以便正常工作:

更可靠的是,您应该使用正则表达式捕捉换行变化(极不可能发生):

带有
4d
0
的东西称为(它是用另一个换行符分隔的十六进制数,表示以下原始内容块的长度)


要想弄清楚这一点,你必须首先查看标题,看看是否有相应的
传输编码:
条目。这是因为它变得复杂,建议使用无数现有的HTTP用户域处理类中的一个。PEAR。

在大多数情况下,Mario的答案应该有效,但我刚刚尝试将此方法应用于来自coach DB的响应,并且在某些情况下它不起作用

如果响应不包含任何文档,则将“\r\n\r\n”放在响应正文中,以保持结果格式良好。在这种情况下,仅将响应拆分为“\r\n\r\n”是不够的,因为您可能会意外地剪切正文的末端部分

对于Coach DB,以下解析似乎更可靠:


不确定
4d
0
,但可以使用
分解('\r\n\r\n',$result)
非常可靠。太好了,你分割标题的方法似乎工作得很好。而且,看起来你对数字的看法是正确的。它们确实会根据内容的长度而变化。我希望我可以使用CURL,我会查看PEAR来处理它。非常感谢!在处理请求时,你应该能够使用HTTP/1.0来避免解析块。FWIW:他的答案对你仍然有效。关键是
explode
的第三个参数中的“2”。这意味着使用
explode
创建的数组中最多只能有2个项目。因此在
列表($header,$body)
中,第一个“块”数组的所有部分都将分配给
$headers
,其他所有部分,无论存在多少
\r\n
都将分配给
$body