/** * Creates an instance from a resource. * @param string $filename File name. * @param resource $fileHandler File handler. * * @throws FileCorruptedException * * @return FileHeader */ public static function createFromResource($filename, $fileHandler) { $header = new FileHeader(); $data = unpack("nmagicNumber/C1compressionMethod/C1flags/LmodificationTime/C1extraFlags/C1os", fread($fileHandler, 10)); // check magic number and compression method if (self::MAGIC_NUMBER !== $data['magicNumber'] || self::COMPRESSION_METHOD_DEFLATE !== $data['compressionMethod']) { throw new FileCorruptedException($filename); } $header->setCompressionMethod($data['compressionMethod'])->setFlags($data['flags'])->setExtraFlags($data['extraFlags'])->setModificationTimeFromUnixEpoch($data['modificationTime'])->setOperatingSystem($data['os']); // if FLG.FEXTRA set if (($header->getFlags() & self::FLAGS_EXTRA) === self::FLAGS_EXTRA) { $extraFieldData = unpack("C2subfield/vlength", fread($fileHandler, 10)); $header->setExtraSubfields($extraFieldData['subfield1'], $extraFieldData['subfield2'])->setExtraData(fread($fileHandler, $extraFieldData['length'])); } // if FLG.FNAME set if (($header->getFlags() & self::FLAGS_NAME) === self::FLAGS_NAME) { $header->setOriginalFilename(self::readString($fileHandler)); } // if FLG.FCOMMENT set if (($header->getFlags() & self::FLAGS_COMMENT) === self::FLAGS_COMMENT) { $header->setComment(self::readString($fileHandler)); } // if FLG.FHCRC set if (($header->getFlags() & self::FLAGS_HCRC) === self::FLAGS_HCRC) { $crcData = unpack('vcrc', fread($fileHandler, 2)); $header->setCrc16($crcData['crc']); } return $header; }
/** * Extracts the contents from a GZIP file. * @param string $filename GZIP file name. * @param string $target Target path. * * @throws Exception\IO\Input\FileCorruptedException * * @return bool */ protected function extractGzipFile($filename, $target) { $fileHandler = fopen($filename, 'rb'); $bitReader = new BitReader($fileHandler); // read file header try { $fileHeader = FileHeader::createFromResource($filename, $fileHandler); } catch (Exception\IO\Input\FileCorruptedException $e) { throw $e; } // read compressed blocks $result = ''; $isBlockFinal = false; while (false === $isBlockFinal) { $isBlockFinal = 1 === $bitReader->read(1); $compressionType = $bitReader->read(2); if (self::COMPRESSION_TYPE_NON_COMPRESSED === $compressionType) { // no compression $data = unpack("vlength/vlengthOneComplement", fread($fileHandler, 4)); $result .= fread($fileHandler, $data['length']); } else { // compression if (self::COMPRESSION_TYPE_FIXED_HUFFMAN === $compressionType) { list($literalsTree, $distancesTree) = $this->getFixedHuffmanTrees(); } elseif (self::COMPRESSION_TYPE_DYNAMIC_HUFFMAN === $compressionType) { list($literalsTree, $distancesTree) = $this->getDynamicHuffmanTrees($bitReader); } else { throw new Exception\IO\Input\FileCorruptedException($filename); } $result .= $this->uncompressCompressedBlock($literalsTree, $distancesTree, $bitReader, $result); } $literalsTree = null; $distancesTree = null; } // check crc32 $footer = unpack('Vcrc/Visize', fread($fileHandler, 8)); if ($footer['crc'] !== crc32($result)) { throw new Exception\IO\Input\FileCorruptedException($filename); } fclose($fileHandler); // write file $outputFilename = $fileHeader->getOriginalFilename(); if (empty($outputFilename)) { $outputFilename = pathinfo($filename, PATHINFO_FILENAME); } $location = $target . DIRECTORY_SEPARATOR . $outputFilename; file_put_contents($location, $result); return true; }