How to isolate the HTTP headers/body from a PHP So

2019-04-06 04:10发布

问题:

I'm using a socket connection in PHP to post data to an Apache webserver. I'm a bit new to this technique, and I am not sure how to isolate the headers from the body of the response.

Sending Code:

<?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;
?>

Server Code:

Hello this is server. You posted:
<pre>
<?php print_r($_POST); ?>
</pre>

When posting to one server, I get:

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>

As expected. I want to strip off the headers though, and just read the body from "Hello this is server....." onwards. How can i reliably detect the end of the headers and read the body into a variable?

Also, another server I've tested on replies with this:

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

What are the "4d" and "0" around the body text??

Thanks!

PS before someone says use CURL, I can't unfortunately :-(

回答1:

You can separate the header from the the body by splitting up on a double linebreak. It should be <CRLF><CRLF> so this would normally work:

list($header, $body) = explode("\r\n\r\n", $response, 2);

More reliably you should use a regex to catch linebreak variations (super unlikely to ever happen):

list($header, $body) = preg_split("/\R\R/", $response, 2);

The thing with the 4d and 0 is called the chunked encoding. (It's hex-numbers separated with another linebreak, and inidicate the length of the following raw content block).

To clear that up you have to look at the headers first, and see if there is an according Transfer-Encoding: entry. This is were it gets complicated, and advisable to use one of the myriad of existing HTTP userland processing classes. PEAR has one.



回答2:

Headers should end with "\r\n\r\n" (two times). These 4d and 0 are possibly part of your php response (they are not part of the headers).



回答3:

In most cases Mario's answer should work but I have just tried to apply this method to response from Couch DB and there are some cases when it does not work.

If response does not contain any documents then Couch DB put "\r\n\r\n" inside response body trying to keep results well-formed and in this case it is not enough to just split response by "\r\n\r\n" because you can accidentally cut end part of the body.

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
]}

Following parsing seems to be more reliable for Couch DB :

$parts = explode("\r\n\r\n", $response);

if ($parts)
{
    $headers = array_shift($parts);
    $body = json_decode(implode("\r\n\r\n", $parts));
}