php - 发出原始 HTTP 请求时如何轻松解码 HTTP 分块编码字符串?

标签 php http

我想在不依赖于 cURL 和 allow_url_fopen = 1 的情况下发出 HTTP 请求,方法是打开套接字连接并发送原始 HTTP 请求:

/**
 * Make HTTP GET request
 *
 * @param   string   the URL
 * @param   int      will be filled with HTTP response status code
 * @param   string   will be filled with HTTP response header
 * @return  string   HTTP response body
 */
function http_get_request($url, &$http_code = '', &$res_head = '') 
{
  $scheme = $host = $user = $pass = $query = $fragment = '';
  $path = '/';
  $port = substr($url, 0, 5) == 'https' ? 443 : 80;

  extract(parse_url($url)); 

  $path .= ($query ? "?$query" : '').($fragment ? "#$fragment" : '');

  $head = "GET $path HTTP/1.1\r\n"
        . "Host: $host\r\n"
        . "Authorization: Basic ".base64_encode("$user:$pass")."\r\n"
        . "Connection: close\r\n\r\n";

  $fp = fsockopen($scheme == 'https' ? "ssl://$host" : $host, $port) or 
    die('Cannot connect!');

  fputs($fp, $head);
  while(!feof($fp)) {
    $res .= fgets($fp, 4096);
  }
  fclose($fp);

  list($res_head, $res_body) = explode("\r\n\r\n", $res, 2);
  list(, $http_code, ) = explode(' ', $res_head, 3);

  return $res_body;
}

该函数工作正常,但由于我使用的是 HTTP/1.1,响应正文通常在 Chunked-encoded 中返回字符串。例如(来自维基百科):

25
This is the data in the first chunk

1C
and this is the second one

3
con
8
sequence
0

我不想使用 http_chunked_decode()因为它依赖于 PECL,所以我想要一个高度可移植的代码。

如何轻松解码 HTTP 分块编码字符串,以便我的函数可以返回原始 HTML?我还必须确保解码字符串的长度与 Content-Length: header 匹配。

如有任何帮助,我们将不胜感激。谢谢。

最佳答案

由于该函数返回 HTTP 响应 header ,您应该检查 'Transfer-Encoding' 是否为 'chunked' 然后解码分块编码的字符串。 在伪代码中:

CALL parse_http_header
IF 'Transfer-Encoding' IS 'chunked'
  CALL decode_chunked

解析 HTTP 响应 header :

下面是将 HTTP 响应头解析为关联数组的函数。

function parse_http_header($str) 
{
  $lines = explode("\r\n", $str);
  $head  = array(array_shift($lines));
  foreach ($lines as $line) {
    list($key, $val) = explode(':', $line, 2);
    if ($key == 'Set-Cookie') {
      $head['Set-Cookie'][] = trim($val);
    } else {
      $head[$key] = trim($val);
    }
  }
  return $head;
}

该函数将返回如下数组:

Array
(
    [0] => HTTP/1.1 200 OK
    [Expires] => Tue, 31 Mar 1981 05:00:00 GMT
    [Content-Type] => text/html; charset=utf-8
    [Transfer-Encoding] => chunked
    [Set-Cookie] => Array
        (
            [0] => k=10.34; path=/; expires=Sat, 09-Jun-12 01:58:23 GMT; domain=.example.com
            [1] => guest_id=v1%3A13; domain=.example.com; path=/; expires=Mon, 02-Jun-2014 13:58:23 GMT
        )
    [Content-Length] => 43560
)

注意 Set-Cookie header 是如何解析为数组的。稍后您需要解析 cookie 以将 URL 与需要发送的 cookie 相关联。


解码分块编码的字符串

下面的函数以分块编码的字符串为参数,返回 解码后的字符串。

function decode_chunked($str) {
  for ($res = ''; !empty($str); $str = trim($str)) {
    $pos = strpos($str, "\r\n");
    $len = hexdec(substr($str, 0, $pos));
    $res.= substr($str, $pos + 2, $len);
    $str = substr($str, $pos + 2 + $len);
  }
  return $res;
}

// Given the string in the question, the function above will returns:
//
// This is the data in the first chunk
// and this is the second one
// consequence

关于php - 发出原始 HTTP 请求时如何轻松解码 HTTP 分块编码字符串?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10793017/

相关文章:

javascript - Node.js 未对 HTTP 响应 header 使用 ISO-8859-1 编码

javascript - jquery 中的 id 不起作用

php - 在一个查询中插入后获取数据库行

android - 从 android 中的 HttpURLConnection 获取响应代码

http - 如何在golang中缓存http.Response?

http - 当用户未通过身份验证时,状态代码 404 是否合适?

php - 使用 JSON 更新记录时 MySQL 语法错误

php - 如何在 slim 框架上获取环境模式

php - YouTube API V3 : Where can i find a list of each 'videoCategoryId' ?

c# - 为什么在监听强通配符(http ://+:port) http. sys/urlacl 绑定(bind)时 HttpListener "conflict with an existing registration"?