You are here

function HTTP_Response::_decodeGzip in Flickr API 5

Decodes the message-body encoded by gzip

The real decoding work is done by gzinflate() built-in function, this method only parses the header and checks data for compliance with RFC 1952

@access private

Parameters

string gzip-encoded data:

Return value

string decoded data

1 call to HTTP_Response::_decodeGzip()
HTTP_Response::process in phpFlickr/PEAR/HTTP/Request.php
Processes a HTTP response

File

phpFlickr/PEAR/HTTP/Request.php, line 1396

Class

HTTP_Response
Response class to complement the Request class

Code

function _decodeGzip($data) {
  if (HTTP_REQUEST_MBSTRING) {
    $oldEncoding = mb_internal_encoding();
    mb_internal_encoding('iso-8859-1');
  }
  $length = strlen($data);

  // If it doesn't look like gzip-encoded data, don't bother
  if (18 > $length || strcmp(substr($data, 0, 2), "")) {
    return $data;
  }
  $method = ord(substr($data, 2, 1));
  if (8 != $method) {
    return PEAR::raiseError('_decodeGzip(): unknown compression method', HTTP_REQUEST_ERROR_GZIP_METHOD);
  }
  $flags = ord(substr($data, 3, 1));
  if ($flags & 224) {
    return PEAR::raiseError('_decodeGzip(): reserved bits are set', HTTP_REQUEST_ERROR_GZIP_DATA);
  }

  // header is 10 bytes minimum. may be longer, though.
  $headerLength = 10;

  // extra fields, need to skip 'em
  if ($flags & 4) {
    if ($length - $headerLength - 2 < 8) {
      return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
    }
    $extraLength = unpack('v', substr($data, 10, 2));
    if ($length - $headerLength - 2 - $extraLength[1] < 8) {
      return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
    }
    $headerLength += $extraLength[1] + 2;
  }

  // file name, need to skip that
  if ($flags & 8) {
    if ($length - $headerLength - 1 < 8) {
      return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
    }
    $filenameLength = strpos(substr($data, $headerLength), chr(0));
    if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
      return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
    }
    $headerLength += $filenameLength + 1;
  }

  // comment, need to skip that also
  if ($flags & 16) {
    if ($length - $headerLength - 1 < 8) {
      return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
    }
    $commentLength = strpos(substr($data, $headerLength), chr(0));
    if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
      return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
    }
    $headerLength += $commentLength + 1;
  }

  // have a CRC for header. let's check
  if ($flags & 1) {
    if ($length - $headerLength - 2 < 8) {
      return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
    }
    $crcReal = 0xffff & crc32(substr($data, 0, $headerLength));
    $crcStored = unpack('v', substr($data, $headerLength, 2));
    if ($crcReal != $crcStored[1]) {
      return PEAR::raiseError('_decodeGzip(): header CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC);
    }
    $headerLength += 2;
  }

  // unpacked data CRC and size at the end of encoded data
  $tmp = unpack('V2', substr($data, -8));
  $dataCrc = $tmp[1];
  $dataSize = $tmp[2];

  // finally, call the gzinflate() function
  $unpacked = @gzinflate(substr($data, $headerLength, -8), $dataSize);
  if (false === $unpacked) {
    return PEAR::raiseError('_decodeGzip(): gzinflate() call failed', HTTP_REQUEST_ERROR_GZIP_READ);
  }
  elseif ($dataSize != strlen($unpacked)) {
    return PEAR::raiseError('_decodeGzip(): data size check failed', HTTP_REQUEST_ERROR_GZIP_READ);
  }
  elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
    return PEAR::raiseError('_decodeGzip(): data CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC);
  }
  if (HTTP_REQUEST_MBSTRING) {
    mb_internal_encoding($oldEncoding);
  }
  return $unpacked;
}