如何解码/解压分块gzip字符串?

9
在PHP中进行gzip deflate请求后,我会收到偏移块的压缩字符串,格式如下所示:
示例已大幅缩短以显示格式:
00001B4E
¾”kŒj…Øæ’ìÑ«F1ìÊ`+ƒQì¹UÜjùJƒZ\µy¡ÓUžGr‡J&=KLËÙÍ~=ÍkR
0000102F
ñÞœÞôΑüo[¾”+’Ñ8#à»0±R-4VÕ’n›êˆÍ.MCŽ…ÏÖr¿3M—èßñ°r¡\+
00000000

我无法对其进行膨胀,这可能是由于分块格式。在使用十六进制编辑器手动删除偏移量并读取gzip存档后,我可以确认数据未损坏。我想知道是否有一种正确的方法将此分块gzip挤压响应解析为可读字符串?我可能能够拆分这些偏移量并将数据拼接成一个字符串以调用gzinflate,但似乎必须有更简便的方法。
3个回答

11

正确的方法来解压分块响应大致如下:

initialise string to hold result
for each chunk {
  check that the stated chunk length equals the string length of the chunk
  append the chunk data to the result variable
}

这里有一个方便的PHP函数可以帮你实现这个功能(已修复):
function unchunk_string ($str) {

  // A string to hold the result
  $result = '';

  // Split input by CRLF
  $parts = explode("\r\n", $str);

  // These vars track the current chunk
  $chunkLen = 0;
  $thisChunk = '';

  // Loop the data
  while (($part = array_shift($parts)) !== NULL) {
    if ($chunkLen) {
      // Add the data to the string
      // Don't forget, the data might contain a literal CRLF
      $thisChunk .= $part."\r\n";
      if (strlen($thisChunk) == $chunkLen) {
        // Chunk is complete
        $result .= $thisChunk;
        $chunkLen = 0;
        $thisChunk = '';
      } else if (strlen($thisChunk) == $chunkLen + 2) {
        // Chunk is complete, remove trailing CRLF
        $result .= substr($thisChunk, 0, -2);
        $chunkLen = 0;
        $thisChunk = '';
      } else if (strlen($thisChunk) > $chunkLen) {
        // Data is malformed
        return FALSE;
      }
    } else {
      // If we are not in a chunk, get length of the new one
      if ($part === '') continue;
      if (!$chunkLen = hexdec($part)) break;
    }
  }

  // Return the decoded data of FALSE if it is incomplete
  return ($chunkLen) ? FALSE : $result;

}

非常好,正如预期的那样工作。这确实是一个方便的PHP函数,我已经寻找它有一段时间了。非常感谢! - user1309276
@user1309276 我已经更新了上述函数,修复了字符串包含文字CRLF时的错误行为。现在已经修复,并且提供了更好的检测异常字符串的功能。 - DaveRandom
1
再次感谢!对于仍然遇到问题的人,调用unchunk_string后,我只需要使用以下代码删除前10个字节:$data = gzinflate(substr($data,10)); - user1309276

3

要解码一个字符串,请使用gzinflate。Zend_Http_Client库可以帮助完成这种常见的任务,它很容易使用。如果您需要自己完成,请参考Zend_Http_Response代码


很不幸,我已经尝试过该库使用的方法,但它包含了一些我将来可能需要的代码,谢谢! - user1309276

1

用户@user1309276提供的解决方案真的帮了我!从服务器接收到一个带有transfer-encoding: chunked头的gzip压缩的json响应。没有任何解决方案有效。这个解决方案对我来说就像魔法一样!它只是去掉了前10个字节。

$data = json_decode(gzinflate(substr($response->getContent(), 10)), true);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接