【问题标题】:How to isolate the HTTP headers/body from a PHP Sockets request如何将 HTTP 标头/正文与 PHP 套接字请求隔离开来
【发布时间】:2012-02-04 02:02:31
【问题描述】:

我在 PHP 中使用套接字连接将数据发布到 Apache 网络服务器。我对这种技术有点陌生,我不确定如何将标头与响应正文隔离开来。

发送代码:

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

正如预期的那样。不过,我想去掉标题,然后从“你好,这是服务器.....”开始阅读正文。 我怎样才能可靠地检测到标题的结尾并将正文读入变量?

另外,我测试过的另一台服务器的回复是这样的:

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

正文周围的“4d”和“0”是什么??

谢谢!

PS 在有人说使用 CURL 之前,不幸的是我不能 :-(

【问题讨论】:

  • 不确定4d0,但您可以非常可靠地使用explode('\r\n\r\n', $result)

标签: php apache http http-headers


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    您可以通过双换行符将标题与正文分开。它应该是&lt;CRLF&gt;&lt;CRLF&gt;,所以这通常会起作用:

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

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

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

    带有4d0 的东西称为chunked encoding。 (它是用另一个换行符分隔的十六进制数字,并指示以下原始内容块的长度。

    要清除它,您必须先查看标题,然后查看是否有相应的 Transfer-Encoding: 条目。如果它变得复杂,建议使用无数现有的 HTTP 用户空间处理类之一。梨has one.

    【讨论】:

    • 太好了,您拆分标题的方法似乎效果很好。此外,看起来您对数字的看法是正确的。它们确实会根据内容的长度而变化。我希望我可以使用 CURL,我会研究 PEAR 来处理它。非常感谢!
    • 您应该能够在请求时使用 HTTP/1.0 以避免解析块。
    【解决方案3】:

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

    如果响应不包含任何文档,则 Couch DB 将 "\r\n\r\n" 放在响应正文中,试图保持结果格式正确,在这种情况下,仅将响应拆分为 "\r 是不够的\n\r\n" 因为你可能会不小心切割身体的末端。

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

    以下解析似乎对 Couch DB 更可靠:

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

    【讨论】:

    • FWIW:他的回答仍然对你有用。关键是explode 的第三个参数中的“2”。意味着在使用explode 创建的数组中最多只能有 2 个项目。因此,在list($header, $body) 中,数组的第一个“块”将分配给$headers,而其他所有内容,无论存在多少\r\n,都将分配给$body
    猜你喜欢
    • 1970-01-01
    • 2014-04-21
    • 2012-05-10
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2015-02-18
    • 2022-11-28
    • 1970-01-01
    相关资源
    最近更新 更多