Как декодировать/раздувать фрагментированную строку gzip?

После выполнения запроса gzip deflate в PHP я получаю дефлированную строку в фрагментах смещения, которая выглядит следующим образом:

Пример сильно сокращен, чтобы показать формат:

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, но, похоже, должен быть более простой способ.


person user1309276    schedule 03.04.2012    source источник


Ответы (2)


Правильный метод дефляции ответа, разбитого на фрагменты, примерно следующий:

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;

}
person DaveRandom    schedule 03.04.2012
comment
Отлично, работает так, как ожидалось. Это действительно удобная функция PHP, я давно ее искал. Большое спасибо! - person user1309276; 03.04.2012
comment
@user1309276 user1309276 Я обновил указанную выше функцию, в ней была ошибка, связанная с поведением, когда строка содержит буквальный CRLF. Теперь это исправлено, а также улучшено обнаружение искаженных строк. - person DaveRandom; 03.04.2012
comment
Спасибо еще раз! Для тех, у кого все еще есть проблемы, после вызова unchunk_string все, что мне нужно сделать, это удалить первые 10 байтов, используя: $data = gzinflate(substr($data,10)); - person user1309276; 03.04.2012

Для декодирования строки используйте gzinflate. задач, его было легко использовать, см. код Zend_Http_Response если вам нужно сделать это самостоятельно

person Sandeep Manne    schedule 03.04.2012
comment
К сожалению, я уже попробовал метод, который использует библиотека, но он содержит некоторый код, который мне может понадобиться в будущем, спасибо! - person user1309276; 03.04.2012