diff --git a/composer.json b/composer.json index 94cc8ce..6f0c4dc 100644 --- a/composer.json +++ b/composer.json @@ -25,11 +25,6 @@ "ext-zlib": "*", "psr/http-message": "^1.0" }, - "config": { - "platform": { - "php": "5.5" - } - }, "require-dev": { "phpunit/phpunit": "^4.8|^5.7", "zendframework/zend-diactoros": "^1.4" diff --git a/src/PhpZip/Crypto/WinZipAesEngine.php b/src/PhpZip/Crypto/WinZipAesEngine.php index 4e1056e..d050fca 100644 --- a/src/PhpZip/Crypto/WinZipAesEngine.php +++ b/src/PhpZip/Crypto/WinZipAesEngine.php @@ -49,9 +49,9 @@ class WinZipAesEngine implements ZipEncryptionEngine * * @param string $content Input stream buffer * - * @throws ZipCryptoException * @throws ZipException * @throws ZipAuthenticationException + * @throws ZipCryptoException * * @return string */ diff --git a/src/PhpZip/Extra/Fields/WinZipAesEntryExtraField.php b/src/PhpZip/Extra/Fields/WinZipAesEntryExtraField.php index 948452a..582514a 100644 --- a/src/PhpZip/Extra/Fields/WinZipAesEntryExtraField.php +++ b/src/PhpZip/Extra/Fields/WinZipAesEntryExtraField.php @@ -4,7 +4,7 @@ namespace PhpZip\Extra\Fields; use PhpZip\Exception\ZipException; use PhpZip\Extra\ExtraField; -use PhpZip\ZipFileInterface; +use PhpZip\ZipFile; /** * WinZip AES Extra Field. @@ -49,9 +49,9 @@ class WinZipAesEntryExtraField implements ExtraField ]; protected static $encryptionMethods = [ - self::KEY_STRENGTH_128BIT => ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128, - self::KEY_STRENGTH_192BIT => ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192, - self::KEY_STRENGTH_256BIT => ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256, + self::KEY_STRENGTH_128BIT => ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128, + self::KEY_STRENGTH_192BIT => ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192, + self::KEY_STRENGTH_256BIT => ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256, ]; /** diff --git a/src/PhpZip/Mapper/OffsetPositionMapper.php b/src/PhpZip/Mapper/OffsetPositionMapper.php deleted file mode 100644 index 747b8a1..0000000 --- a/src/PhpZip/Mapper/OffsetPositionMapper.php +++ /dev/null @@ -1,43 +0,0 @@ -offset = (int) $offset; - } - - /** - * @param int $position - * - * @return int - */ - public function map($position) - { - return parent::map($position) + $this->offset; - } - - /** - * @param int $position - * - * @return int - */ - public function unmap($position) - { - return parent::unmap($position) - $this->offset; - } -} diff --git a/src/PhpZip/Mapper/PositionMapper.php b/src/PhpZip/Mapper/PositionMapper.php deleted file mode 100644 index 42a9b29..0000000 --- a/src/PhpZip/Mapper/PositionMapper.php +++ /dev/null @@ -1,32 +0,0 @@ -entryCount = $entryCount; - $this->comment = $comment; + $this->cdOffset = $cdOffset; + $this->cdSize = $cdSize; $this->zip64 = $zip64; + $this->comment = $comment; } /** - * @return string|null + * @param string|null $comment */ - public function getComment() + public function setComment($comment) { - return $this->comment; + $this->comment = $comment; } /** @@ -113,6 +123,30 @@ class EndOfCentralDirectory return $this->entryCount; } + /** + * @return int + */ + public function getCdOffset() + { + return $this->cdOffset; + } + + /** + * @return int + */ + public function getCdSize() + { + return $this->cdSize; + } + + /** + * @return string|null + */ + public function getComment() + { + return $this->comment; + } + /** * @return bool */ diff --git a/src/PhpZip/Model/Entry/OutputOffsetEntry.php b/src/PhpZip/Model/Entry/OutputOffsetEntry.php index fea5383..b968212 100644 --- a/src/PhpZip/Model/Entry/OutputOffsetEntry.php +++ b/src/PhpZip/Model/Entry/OutputOffsetEntry.php @@ -9,6 +9,8 @@ use PhpZip\Model\ZipEntry; * * @author Ne-Lexa alexey@nelexa.ru * @license MIT + * + * @internal */ class OutputOffsetEntry { diff --git a/src/PhpZip/Model/Entry/ZipAbstractEntry.php b/src/PhpZip/Model/Entry/ZipAbstractEntry.php index c5435c6..f8dcc1a 100644 --- a/src/PhpZip/Model/Entry/ZipAbstractEntry.php +++ b/src/PhpZip/Model/Entry/ZipAbstractEntry.php @@ -10,7 +10,7 @@ use PhpZip\Extra\Fields\WinZipAesEntryExtraField; use PhpZip\Model\ZipEntry; use PhpZip\Util\DateTimeConverter; use PhpZip\Util\StringUtil; -use PhpZip\ZipFileInterface; +use PhpZip\ZipFile; /** * Abstract ZIP entry. @@ -26,16 +26,22 @@ abstract class ZipAbstractEntry implements ZipEntry private $name; /** @var int Made by platform */ - private $platform = self::UNKNOWN; + private $createdOS = self::UNKNOWN; + + /** @var int Extracted by platform */ + private $extractedOS = self::UNKNOWN; /** @var int */ - private $versionNeededToExtract = 20; + private $softwareVersion = self::UNKNOWN; + + /** @var int */ + private $versionNeededToExtract = self::UNKNOWN; /** @var int Compression method */ private $method = self::UNKNOWN; /** @var int */ - private $general = 0; + private $generalPurposeBitFlags = 0; /** @var int Dos time */ private $dosTime = self::UNKNOWN; @@ -49,11 +55,14 @@ abstract class ZipAbstractEntry implements ZipEntry /** @var int Uncompressed size */ private $size = self::UNKNOWN; + /** @var int Internal attributes */ + private $internalAttributes = 0; + /** @var int External attributes */ private $externalAttributes = 0; /** @var int relative Offset Of Local File Header */ - private $offset = self::UNKNOWN; + private $offset = 0; /** * Collections of Extra Fields. @@ -73,17 +82,17 @@ abstract class ZipAbstractEntry implements ZipEntry /** * Encryption method. * - * @see ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 + * @see ZipFile::ENCRYPTION_METHOD_TRADITIONAL + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128 + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192 + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256 * * @var int */ - private $encryptionMethod = ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL; + private $encryptionMethod = ZipFile::ENCRYPTION_METHOD_TRADITIONAL; /** @var int */ - private $compressionLevel = ZipFileInterface::LEVEL_DEFAULT_COMPRESSION; + private $compressionLevel = ZipFile::LEVEL_DEFAULT_COMPRESSION; /** * ZipAbstractEntry constructor. @@ -101,7 +110,9 @@ abstract class ZipAbstractEntry implements ZipEntry public function setEntry(ZipEntry $entry) { $this->setName($entry->getName()); - $this->setPlatform($entry->getPlatform()); + $this->setSoftwareVersion($entry->getSoftwareVersion()); + $this->setCreatedOS($entry->getCreatedOS()); + $this->setExtractedOS($entry->getExtractedOS()); $this->setVersionNeededToExtract($entry->getVersionNeededToExtract()); $this->setMethod($entry->getMethod()); $this->setGeneralPurposeBitFlags($entry->getGeneralPurposeBitFlags()); @@ -109,6 +120,7 @@ abstract class ZipAbstractEntry implements ZipEntry $this->setCrc($entry->getCrc()); $this->setCompressedSize($entry->getCompressedSize()); $this->setSize($entry->getSize()); + $this->setInternalAttributes($entry->getInternalAttributes()); $this->setExternalAttributes($entry->getExternalAttributes()); $this->setOffset($entry->getOffset()); $this->setExtra($entry->getExtra()); @@ -163,20 +175,48 @@ abstract class ZipAbstractEntry implements ZipEntry public function setGeneralPurposeBitFlag($mask, $bit) { if ($bit) { - $this->general |= $mask; + $this->generalPurposeBitFlags |= $mask; } else { - $this->general &= ~$mask; + $this->generalPurposeBitFlags &= ~$mask; } return $this; } /** - * @return int platform + * @return int Get platform + * + * @deprecated Use {@see ZipEntry::getCreatedOS()} */ public function getPlatform() { - return $this->platform; + @trigger_error('ZipEntry::getPlatform() is deprecated. Use ZipEntry::getCreatedOS()', \E_USER_DEPRECATED); + + return $this->getCreatedOS(); + } + + /** + * @param int $platform + * + * @throws ZipException + * + * @return ZipEntry + * + * @deprecated Use {@see ZipEntry::setCreatedOS()} + */ + public function setPlatform($platform) + { + @trigger_error('ZipEntry::setPlatform() is deprecated. Use ZipEntry::setCreatedOS()', \E_USER_DEPRECATED); + + return $this->setCreatedOS($platform); + } + + /** + * @return int platform + */ + public function getCreatedOS() + { + return $this->createdOS; } /** @@ -188,16 +228,63 @@ abstract class ZipAbstractEntry implements ZipEntry * * @return ZipEntry */ - public function setPlatform($platform) + public function setCreatedOS($platform) { - if ($platform !== self::UNKNOWN) { - if ($platform < 0x00 || $platform > 0xff) { - throw new ZipException('Platform out of range'); - } - $this->platform = $platform; - } else { - $this->platform = 0; // ms-dos + $platform = (int) $platform; + + if ($platform < 0x00 || $platform > 0xff) { + throw new ZipException('Platform out of range'); } + $this->createdOS = $platform; + + return $this; + } + + /** + * @return int + */ + public function getExtractedOS() + { + return $this->extractedOS; + } + + /** + * Set extracted OS. + * + * @param int $platform + * + * @throws ZipException + * + * @return ZipEntry + */ + public function setExtractedOS($platform) + { + $platform = (int) $platform; + + if ($platform < 0x00 || $platform > 0xff) { + throw new ZipException('Platform out of range'); + } + $this->extractedOS = $platform; + + return $this; + } + + /** + * @return int + */ + public function getSoftwareVersion() + { + return $this->softwareVersion; + } + + /** + * @param int $softwareVersion + * + * @return ZipEntry + */ + public function setSoftwareVersion($softwareVersion) + { + $this->softwareVersion = (int) $softwareVersion; return $this; } @@ -209,6 +296,24 @@ abstract class ZipAbstractEntry implements ZipEntry */ public function getVersionNeededToExtract() { + if ($this->versionNeededToExtract === self::UNKNOWN) { + $method = $this->getMethod(); + + if ($method === self::METHOD_WINZIP_AES) { + return 51; + } + + if ($method === ZipFile::METHOD_BZIP2) { + return 46; + } + + if ($this->isZip64ExtensionsRequired()) { + return 45; + } + + return $method === ZipFile::METHOD_DEFLATED || $this->isDirectory() ? 20 : 10; + } + return $this->versionNeededToExtract; } @@ -300,7 +405,7 @@ abstract class ZipAbstractEntry implements ZipEntry */ public function setOffset($offset) { - $this->offset = $offset; + $this->offset = (int) $offset; return $this; } @@ -312,7 +417,7 @@ abstract class ZipAbstractEntry implements ZipEntry */ public function getGeneralPurposeBitFlags() { - return $this->general & 0xffff; + return $this->generalPurposeBitFlags & 0xffff; } /** @@ -331,20 +436,20 @@ abstract class ZipAbstractEntry implements ZipEntry if ($general < 0x0000 || $general > 0xffff) { throw new ZipException('general out of range'); } - $this->general = $general; + $this->generalPurposeBitFlags = $general; - if ($this->method === ZipFileInterface::METHOD_DEFLATED) { + if ($this->method === ZipFile::METHOD_DEFLATED) { $bit1 = $this->getGeneralPurposeBitFlag(self::GPBF_COMPRESSION_FLAG1); $bit2 = $this->getGeneralPurposeBitFlag(self::GPBF_COMPRESSION_FLAG2); if ($bit1 && !$bit2) { - $this->compressionLevel = ZipFileInterface::LEVEL_BEST_COMPRESSION; + $this->compressionLevel = ZipFile::LEVEL_BEST_COMPRESSION; } elseif (!$bit1 && $bit2) { - $this->compressionLevel = ZipFileInterface::LEVEL_FAST; + $this->compressionLevel = ZipFile::LEVEL_FAST; } elseif ($bit1 && $bit2) { - $this->compressionLevel = ZipFileInterface::LEVEL_SUPER_FAST; + $this->compressionLevel = ZipFile::LEVEL_SUPER_FAST; } else { - $this->compressionLevel = ZipFileInterface::LEVEL_DEFAULT_COMPRESSION; + $this->compressionLevel = ZipFile::LEVEL_DEFAULT_COMPRESSION; } } @@ -370,7 +475,7 @@ abstract class ZipAbstractEntry implements ZipEntry */ public function getGeneralPurposeBitFlag($mask) { - return ($this->general & $mask) !== 0; + return ($this->generalPurposeBitFlags & $mask) !== 0; } /** @@ -447,9 +552,9 @@ abstract class ZipAbstractEntry implements ZipEntry } switch ($method) { case self::METHOD_WINZIP_AES: - case ZipFileInterface::METHOD_STORED: - case ZipFileInterface::METHOD_DEFLATED: - case ZipFileInterface::METHOD_BZIP2: + case ZipFile::METHOD_STORED: + case ZipFile::METHOD_DEFLATED: + case ZipFile::METHOD_BZIP2: $this->method = $method; break; @@ -490,6 +595,8 @@ abstract class ZipAbstractEntry implements ZipEntry * @param int $dosTime * * @throws ZipException + * + * @return ZipEntry */ public function setDosTime($dosTime) { @@ -499,6 +606,8 @@ abstract class ZipAbstractEntry implements ZipEntry throw new ZipException('DosTime out of range'); } $this->dosTime = $dosTime; + + return $this; } /** @@ -547,6 +656,30 @@ abstract class ZipAbstractEntry implements ZipEntry return $this; } + /** + * Sets the internal file attributes. + * + * @param int $attributes the internal file attributes + * + * @return ZipEntry + */ + public function setInternalAttributes($attributes) + { + $this->internalAttributes = (int) $attributes; + + return $this; + } + + /** + * Returns the internal file attributes. + * + * @return int the internal file attributes + */ + public function getInternalAttributes() + { + return $this->internalAttributes; + } + /** * Returns true if and only if this ZIP entry represents a directory entry * (i.e. end with '/'). @@ -589,10 +722,14 @@ abstract class ZipAbstractEntry implements ZipEntry * @param string $data the byte array holding the serialized Extra Fields * * @throws ZipException if the serialized Extra Fields exceed 64 KB + * + * @return ZipEntry */ public function setExtra($data) { $this->extraFieldsCollection = ExtraFieldsFactory::createExtraFieldCollections($data, $this); + + return $this; } /** @@ -713,19 +850,19 @@ abstract class ZipAbstractEntry implements ZipEntry * * @return ZipEntry * - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 - * @see ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256 + * @see ZipFile::ENCRYPTION_METHOD_TRADITIONAL + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128 + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192 */ public function setEncryptionMethod($encryptionMethod) { if ($encryptionMethod !== null) { if ( - $encryptionMethod !== ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL - && $encryptionMethod !== ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 - && $encryptionMethod !== ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 - && $encryptionMethod !== ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 + $encryptionMethod !== ZipFile::ENCRYPTION_METHOD_TRADITIONAL + && $encryptionMethod !== ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128 + && $encryptionMethod !== ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192 + && $encryptionMethod !== ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256 ) { throw new ZipException('Invalid encryption method'); } @@ -748,14 +885,14 @@ abstract class ZipAbstractEntry implements ZipEntry * * @return ZipEntry */ - public function setCompressionLevel($compressionLevel = ZipFileInterface::LEVEL_DEFAULT_COMPRESSION) + public function setCompressionLevel($compressionLevel = ZipFile::LEVEL_DEFAULT_COMPRESSION) { - if ($compressionLevel < ZipFileInterface::LEVEL_DEFAULT_COMPRESSION || - $compressionLevel > ZipFileInterface::LEVEL_BEST_COMPRESSION + if ($compressionLevel < ZipFile::LEVEL_DEFAULT_COMPRESSION || + $compressionLevel > ZipFile::LEVEL_BEST_COMPRESSION ) { throw new InvalidArgumentException( 'Invalid compression level. Minimum level ' . - ZipFileInterface::LEVEL_DEFAULT_COMPRESSION . '. Maximum level ' . ZipFileInterface::LEVEL_BEST_COMPRESSION + ZipFile::LEVEL_DEFAULT_COMPRESSION . '. Maximum level ' . ZipFile::LEVEL_BEST_COMPRESSION ); } $this->compressionLevel = $compressionLevel; diff --git a/src/PhpZip/Model/Entry/ZipChangesEntry.php b/src/PhpZip/Model/Entry/ZipChangesEntry.php index f2f1b46..c17415f 100644 --- a/src/PhpZip/Model/Entry/ZipChangesEntry.php +++ b/src/PhpZip/Model/Entry/ZipChangesEntry.php @@ -10,6 +10,8 @@ use PhpZip\Exception\ZipException; * * @author Ne-Lexa alexey@nelexa.ru * @license MIT + * + * @internal */ class ZipChangesEntry extends ZipAbstractEntry { diff --git a/src/PhpZip/Model/Entry/ZipNewEntry.php b/src/PhpZip/Model/Entry/ZipNewEntry.php index 2f8a3f8..5930a74 100644 --- a/src/PhpZip/Model/Entry/ZipNewEntry.php +++ b/src/PhpZip/Model/Entry/ZipNewEntry.php @@ -3,7 +3,6 @@ namespace PhpZip\Model\Entry; use PhpZip\Exception\InvalidArgumentException; -use PhpZip\ZipFileInterface; /** * @author Ne-Lexa alexey@nelexa.ru @@ -50,25 +49,6 @@ class ZipNewEntry extends ZipAbstractEntry return $this->content; } - /** - * Version needed to extract. - * - * @return int - */ - public function getVersionNeededToExtract() - { - $method = $this->getMethod(); - - return $method === self::METHOD_WINZIP_AES ? 51 : - ( - $method === ZipFileInterface::METHOD_BZIP2 ? 46 : - ( - $this->isZip64ExtensionsRequired() ? 45 : - ($method === ZipFileInterface::METHOD_DEFLATED || $this->isDirectory() ? 20 : 10) - ) - ); - } - /** * Clone extra fields. */ diff --git a/src/PhpZip/Model/ZipEntry.php b/src/PhpZip/Model/ZipEntry.php index 7f9ece0..1360a71 100644 --- a/src/PhpZip/Model/ZipEntry.php +++ b/src/PhpZip/Model/ZipEntry.php @@ -4,7 +4,7 @@ namespace PhpZip\Model; use PhpZip\Exception\ZipException; use PhpZip\Extra\ExtraFieldsCollection; -use PhpZip\ZipFileInterface; +use PhpZip\ZipFile; /** * ZIP file entry. @@ -16,9 +16,6 @@ use PhpZip\ZipFileInterface; */ interface ZipEntry { - // Bit masks for initialized fields. - const BIT_EXTERNAL_ATTR = 128; - /** The unknown value for numeric properties. */ const UNKNOWN = -1; @@ -118,11 +115,31 @@ interface ZipEntry /** * @return int Get platform + * + * @deprecated Use {@see ZipEntry::getCreatedOS()} */ public function getPlatform(); /** - * Set platform. + * @param int $platform + * + * @throws ZipException + * + * @return ZipEntry + * + * @deprecated Use {@see ZipEntry::setCreatedOS()} + */ + public function setPlatform($platform); + + /** + * Returns created OS. + * + * @return int Get platform + */ + public function getCreatedOS(); + + /** + * Set created OS. * * @param int $platform * @@ -130,7 +147,35 @@ interface ZipEntry * * @return ZipEntry */ - public function setPlatform($platform); + public function setCreatedOS($platform); + + /** + * @return int + */ + public function getExtractedOS(); + + /** + * Set extracted OS. + * + * @param int $platform + * + * @throws ZipException + * + * @return ZipEntry + */ + public function setExtractedOS($platform); + + /** + * @return int + */ + public function getSoftwareVersion(); + + /** + * @param int $softwareVersion + * + * @return ZipEntry + */ + public function setSoftwareVersion($softwareVersion); /** * Version needed to extract. @@ -323,6 +368,8 @@ interface ZipEntry * @param int $dosTime * * @throws ZipException + * + * @return ZipEntry */ public function setDosTime($dosTime); @@ -333,6 +380,24 @@ interface ZipEntry */ public function getExternalAttributes(); + /** + * Sets the internal file attributes. + * + * @param int $attributes the internal file attributes + * + * @throws ZipException + * + * @return ZipEntry + */ + public function setInternalAttributes($attributes); + + /** + * Returns the internal file attributes. + * + * @return int the internal file attributes + */ + public function getInternalAttributes(); + /** * Sets the external file attributes. * @@ -368,6 +433,8 @@ interface ZipEntry * @param string $data the byte array holding the serialized Extra Fields * * @throws ZipException if the serialized Extra Fields exceed 64 KB + * + * @return ZipEntry */ public function setExtra($data); @@ -439,10 +506,10 @@ interface ZipEntry * * @return ZipEntry * - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 - * @see ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 - * @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256 + * @see ZipFile::ENCRYPTION_METHOD_TRADITIONAL + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128 + * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192 */ public function setEncryptionMethod($encryptionMethod); @@ -460,7 +527,7 @@ interface ZipEntry * * @return ZipEntry */ - public function setCompressionLevel($compressionLevel = ZipFileInterface::LEVEL_DEFAULT_COMPRESSION); + public function setCompressionLevel($compressionLevel = ZipFile::LEVEL_DEFAULT_COMPRESSION); /** * @return int diff --git a/src/PhpZip/Model/ZipInfo.php b/src/PhpZip/Model/ZipInfo.php index 19b90fa..0e959b2 100644 --- a/src/PhpZip/Model/ZipInfo.php +++ b/src/PhpZip/Model/ZipInfo.php @@ -6,7 +6,7 @@ use PhpZip\Exception\ZipException; use PhpZip\Extra\Fields\NtfsExtraField; use PhpZip\Extra\Fields\WinZipAesEntryExtraField; use PhpZip\Util\FilesUtil; -use PhpZip\ZipFileInterface; +use PhpZip\ZipFile; /** * Zip info. @@ -132,7 +132,7 @@ class ZipInfo private static $valuesCompressionMethod = [ ZipEntry::UNKNOWN => 'unknown', - ZipFileInterface::METHOD_STORED => 'no compression', + ZipFile::METHOD_STORED => 'no compression', 1 => 'shrink', 2 => 'reduce level 1', 3 => 'reduce level 2', @@ -140,7 +140,7 @@ class ZipInfo 5 => 'reduce level 4', 6 => 'implode', 7 => 'reserved for Tokenizing compression algorithm', - ZipFileInterface::METHOD_DEFLATED => 'deflate', + ZipFile::METHOD_DEFLATED => 'deflate', 9 => 'deflate64', 10 => 'PKWARE Data Compression Library Imploding (old IBM TERSE)', 11 => 'reserved by PKWARE', @@ -252,10 +252,10 @@ class ZipInfo $attributes = str_repeat(' ', 12); $externalAttributes = $entry->getExternalAttributes(); $xattr = (($externalAttributes >> 16) & 0xFFFF); - switch ($entry->getPlatform()) { + switch ($entry->getCreatedOS()) { case self::MADE_BY_MS_DOS: case self::MADE_BY_WINDOWS_NTFS: - if ($entry->getPlatform() !== self::MADE_BY_MS_DOS || + if ($entry->getCreatedOS() !== self::MADE_BY_MS_DOS || ($xattr & self::UNX_IRWXU) !== (self::UNX_IRUSR | (!($externalAttributes & 1) << 7) | @@ -420,8 +420,8 @@ class ZipInfo */ public static function getPlatformName(ZipEntry $entry) { - if (isset(self::$valuesMadeBy[$entry->getPlatform()])) { - return self::$valuesMadeBy[$entry->getPlatform()]; + if (isset(self::$valuesMadeBy[$entry->getCreatedOS()])) { + return self::$valuesMadeBy[$entry->getCreatedOS()]; } return 'unknown'; diff --git a/src/PhpZip/Model/ZipModel.php b/src/PhpZip/Model/ZipModel.php index 39fb999..7e5b0af 100644 --- a/src/PhpZip/Model/ZipModel.php +++ b/src/PhpZip/Model/ZipModel.php @@ -7,7 +7,7 @@ use PhpZip\Exception\ZipEntryNotFoundException; use PhpZip\Exception\ZipException; use PhpZip\Model\Entry\ZipChangesEntry; use PhpZip\Model\Entry\ZipSourceEntry; -use PhpZip\ZipFileInterface; +use PhpZip\ZipFile; /** * Zip Model. @@ -203,8 +203,8 @@ class ZipModel implements \Countable /** * @param string|ZipEntry $entry * - * @throws ZipException * @throws ZipEntryNotFoundException + * @throws ZipException * * @return ZipChangesEntry|ZipEntry */ @@ -352,7 +352,7 @@ class ZipModel implements \Countable /** * @param int $encryptionMethod */ - public function setEncryptionMethod($encryptionMethod = ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256) + public function setEncryptionMethod($encryptionMethod = ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256) { $this->matcher()->all()->setEncryptionMethod($encryptionMethod); } diff --git a/src/PhpZip/Stream/ZipInputStream.php b/src/PhpZip/Stream/ZipInputStream.php index 1f42647..6d1779d 100644 --- a/src/PhpZip/Stream/ZipInputStream.php +++ b/src/PhpZip/Stream/ZipInputStream.php @@ -14,15 +14,13 @@ use PhpZip\Extra\ExtraFieldsCollection; use PhpZip\Extra\ExtraFieldsFactory; use PhpZip\Extra\Fields\ApkAlignmentExtraField; use PhpZip\Extra\Fields\WinZipAesEntryExtraField; -use PhpZip\Mapper\OffsetPositionMapper; -use PhpZip\Mapper\PositionMapper; use PhpZip\Model\EndOfCentralDirectory; use PhpZip\Model\Entry\ZipSourceEntry; use PhpZip\Model\ZipEntry; use PhpZip\Model\ZipModel; use PhpZip\Util\PackUtil; use PhpZip\Util\StringUtil; -use PhpZip\ZipFileInterface; +use PhpZip\ZipFile; /** * Read zip file. @@ -35,15 +33,6 @@ class ZipInputStream implements ZipInputStreamInterface /** @var resource */ protected $in; - /** @var PositionMapper */ - protected $mapper; - - /** @var int the number of bytes in the preamble of this ZIP file */ - protected $preamble = 0; - - /** @var int the number of bytes in the postamble of this ZIP file */ - protected $postamble = 0; - /** @var ZipModel */ protected $zipModel; @@ -58,7 +47,6 @@ class ZipInputStream implements ZipInputStreamInterface throw new RuntimeException('$in must be resource'); } $this->in = $in; - $this->mapper = new PositionMapper(); } /** @@ -95,8 +83,8 @@ class ZipInputStream implements ZipInputStreamInterface if ( $signature !== ZipEntry::LOCAL_FILE_HEADER_SIG - && $signature !== EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG - && $signature !== EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG + && $signature !== EndOfCentralDirectory::ZIP64_END_OF_CD_RECORD_SIG + && $signature !== EndOfCentralDirectory::END_OF_CD_SIG ) { throw new ZipException( 'Expected Local File Header or (ZIP64) End Of Central Directory Record! Signature: ' . $signature @@ -111,145 +99,179 @@ class ZipInputStream implements ZipInputStreamInterface */ protected function readEndOfCentralDirectory() { + if (!$this->findEndOfCentralDirectory()) { + throw new ZipException('Invalid zip file. The end of the central directory could not be found.'); + } + + $positionECD = ftell($this->in) - 4; + $buffer = fread($this->in, fstat($this->in)['size'] - $positionECD); + + $unpack = unpack( + 'vdiskNo/vcdDiskNo/vcdEntriesDisk/' . + 'vcdEntries/VcdSize/VcdPos/vcommentLength', + substr($buffer, 0, 18) + ); + + if ( + $unpack['diskNo'] !== 0 || + $unpack['cdDiskNo'] !== 0 || + $unpack['cdEntriesDisk'] !== $unpack['cdEntries'] + ) { + throw new ZipException( + 'ZIP file spanning/splitting is not supported!' + ); + } + // .ZIP file comment (variable sizeECD) $comment = null; - // Search for End of central directory record. - $stats = fstat($this->in); - $size = $stats['size']; - $max = $size - EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN; + + if ($unpack['commentLength'] > 0) { + $comment = substr($buffer, 18, $unpack['commentLength']); + } + + // Check for ZIP64 End Of Central Directory Locator exists. + $zip64ECDLocatorPosition = $positionECD - EndOfCentralDirectory::ZIP64_END_OF_CD_LOCATOR_LEN; + fseek($this->in, $zip64ECDLocatorPosition); + // zip64 end of central dir locator + // signature 4 bytes (0x07064b50) + if ($zip64ECDLocatorPosition > 0 && unpack( + 'V', + fread($this->in, 4) + )[1] === EndOfCentralDirectory::ZIP64_END_OF_CD_LOCATOR_SIG) { + $positionECD = $this->findZip64ECDPosition(); + $endCentralDirectory = $this->readZip64EndOfCentralDirectory($positionECD); + $endCentralDirectory->setComment($comment); + } else { + $endCentralDirectory = new EndOfCentralDirectory( + $unpack['cdEntries'], + $unpack['cdPos'], + $unpack['cdSize'], + false, + $comment + ); + } + + return $endCentralDirectory; + } + + /** + * @throws ZipException + * + * @return bool + */ + protected function findEndOfCentralDirectory() + { + $max = fstat($this->in)['size'] - EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN; + + if ($max < 0) { + throw new ZipException('Too short to be a zip file'); + } $min = $max >= 0xffff ? $max - 0xffff : 0; - for ($endOfCentralDirRecordPos = $max; $endOfCentralDirRecordPos >= $min; $endOfCentralDirRecordPos--) { - fseek($this->in, $endOfCentralDirRecordPos, \SEEK_SET); + // Search for End of central directory record. + for ($position = $max; $position >= $min; $position--) { + fseek($this->in, $position); // end of central dir signature 4 bytes (0x06054b50) - if (unpack('V', fread($this->in, 4))[1] !== EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG) { + if (unpack('V', fread($this->in, 4))[1] !== EndOfCentralDirectory::END_OF_CD_SIG) { continue; } - // number of this disk - 2 bytes - // number of the disk with the start of the - // central directory - 2 bytes - // total number of entries in the central - // directory on this disk - 2 bytes - // total number of entries in the central - // directory - 2 bytes - // size of the central directory - 4 bytes - // offset of start of central directory with - // respect to the starting disk number - 4 bytes - // ZIP file comment length - 2 bytes - $data = unpack( - 'vdiskNo/vcdDiskNo/vcdEntriesDisk/vcdEntries/VcdSize/VcdPos/vcommentLength', - fread($this->in, 18) - ); - - if ($data['diskNo'] !== 0 || $data['cdDiskNo'] !== 0 || $data['cdEntriesDisk'] !== $data['cdEntries']) { - throw new ZipException( - 'ZIP file spanning/splitting is not supported!' - ); - } - // .ZIP file comment (variable size) - if ($data['commentLength'] > 0) { - $comment = ''; - $offset = 0; - - while ($offset < $data['commentLength']) { - $read = min(8192 /* chunk size */, $data['commentLength'] - $offset); - $comment .= fread($this->in, $read); - $offset += $read; - } - } - $this->preamble = $endOfCentralDirRecordPos; - $this->postamble = $size - ftell($this->in); - - // Check for ZIP64 End Of Central Directory Locator. - $endOfCentralDirLocatorPos = $endOfCentralDirRecordPos - EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_LEN; - - fseek($this->in, $endOfCentralDirLocatorPos, \SEEK_SET); - // zip64 end of central dir locator - // signature 4 bytes (0x07064b50) - if ( - $endOfCentralDirLocatorPos < 0 || - ftell($this->in) === $size || - unpack( - 'V', - fread($this->in, 4) - )[1] !== EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG - ) { - // Seek and check first CFH, probably requiring an offset mapper. - $offset = $endOfCentralDirRecordPos - $data['cdSize']; - fseek($this->in, $offset, \SEEK_SET); - $offset -= $data['cdPos']; - - if ($offset !== 0) { - $this->mapper = new OffsetPositionMapper($offset); - } - $entryCount = $data['cdEntries']; - - return new EndOfCentralDirectory($entryCount, $comment); - } - - // number of the disk with the - // start of the zip64 end of - // central directory 4 bytes - $zip64EndOfCentralDirectoryRecordDisk = unpack('V', fread($this->in, 4))[1]; - // relative offset of the zip64 - // end of central directory record 8 bytes - $zip64EndOfCentralDirectoryRecordPos = PackUtil::unpackLongLE(fread($this->in, 8)); - // total number of disks 4 bytes - $totalDisks = unpack('V', fread($this->in, 4))[1]; - - if ($zip64EndOfCentralDirectoryRecordDisk !== 0 || $totalDisks !== 1) { - throw new ZipException('ZIP file spanning/splitting is not supported!'); - } - fseek($this->in, $zip64EndOfCentralDirectoryRecordPos, \SEEK_SET); - // zip64 end of central dir - // signature 4 bytes (0x06064b50) - $zip64EndOfCentralDirSig = unpack('V', fread($this->in, 4))[1]; - - if ($zip64EndOfCentralDirSig !== EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG) { - throw new ZipException('Expected ZIP64 End Of Central Directory Record!'); - } - // size of zip64 end of central - // directory record 8 bytes - // version made by 2 bytes - // version needed to extract 2 bytes - fseek($this->in, 12, \SEEK_CUR); - // number of this disk 4 bytes - $diskNo = unpack('V', fread($this->in, 4))[1]; - // number of the disk with the - // start of the central directory 4 bytes - $cdDiskNo = unpack('V', fread($this->in, 4))[1]; - // total number of entries in the - // central directory on this disk 8 bytes - $cdEntriesDisk = PackUtil::unpackLongLE(fread($this->in, 8)); - // total number of entries in the - // central directory 8 bytes - $cdEntries = PackUtil::unpackLongLE(fread($this->in, 8)); - - if ($diskNo !== 0 || $cdDiskNo !== 0 || $cdEntriesDisk !== $cdEntries) { - throw new ZipException('ZIP file spanning/splitting is not supported!'); - } - - if ($cdEntries < 0 || $cdEntries > 0x7fffffff) { - throw new ZipException('Total Number Of Entries In The Central Directory out of range!'); - } - // size of the central directory 8 bytes - fseek($this->in, 8, \SEEK_CUR); - // offset of start of central - // directory with respect to - // the starting disk number 8 bytes - $cdPos = PackUtil::unpackLongLE(fread($this->in, 8)); - // zip64 extensible data sector (variable size) - fseek($this->in, $cdPos, \SEEK_SET); - $this->preamble = $zip64EndOfCentralDirectoryRecordPos; - $entryCount = $cdEntries; - $zip64 = true; - - return new EndOfCentralDirectory($entryCount, $comment, $zip64); + return true; } - // Start recovering file entries from min. - $this->preamble = $min; - $this->postamble = $size - $min; - return new EndOfCentralDirectory(0, $comment); + return false; + } + + /** + * Read Zip64 end of central directory locator and returns + * Zip64 end of central directory position. + * + * number of the disk with the + * start of the zip64 end of + * central directory 4 bytes + * relative offset of the zip64 + * end of central directory record 8 bytes + * total number of disks 4 bytes + * + * @throws ZipException + * + * @return int Zip64 End Of Central Directory position + */ + protected function findZip64ECDPosition() + { + $diskNo = unpack('V', fread($this->in, 4))[1]; + $zip64ECDPos = PackUtil::unpackLongLE(fread($this->in, 8)); + $totalDisks = unpack('V', fread($this->in, 4))[1]; + + if ($diskNo !== 0 || $totalDisks > 1) { + throw new ZipException('ZIP file spanning/splitting is not supported!'); + } + + return $zip64ECDPos; + } + + /** + * Read zip64 end of central directory locator and zip64 end + * of central directory record. + * + * zip64 end of central dir + * signature 4 bytes (0x06064b50) + * size of zip64 end of central + * directory record 8 bytes + * version made by 2 bytes + * version needed to extract 2 bytes + * number of this disk 4 bytes + * number of the disk with the + * start of the central directory 4 bytes + * total number of entries in the + * central directory on this disk 8 bytes + * total number of entries in the + * central directory 8 bytes + * size of the central directory 8 bytes + * offset of start of central + * directory with respect to + * the starting disk number 8 bytes + * zip64 extensible data sector (variable size) + * + * @param int $zip64ECDPosition + * + * @throws ZipException + * + * @return EndOfCentralDirectory + */ + protected function readZip64EndOfCentralDirectory($zip64ECDPosition) + { + fseek($this->in, $zip64ECDPosition); + + $buffer = fread($this->in, 56 /* zip64 end of cd rec length */); + + if (unpack('V', $buffer)[1] !== EndOfCentralDirectory::ZIP64_END_OF_CD_RECORD_SIG) { + throw new ZipException('Expected ZIP64 End Of Central Directory Record!'); + } + + $data = unpack( + 'VdiskNo/VcdDiskNo', + substr($buffer, 16) + ); + $cdEntriesDisk = PackUtil::unpackLongLE(substr($buffer, 24, 8)); + $entryCount = PackUtil::unpackLongLE(substr($buffer, 32, 8)); + $cdSize = PackUtil::unpackLongLE(substr($buffer, 40, 8)); + $cdPos = PackUtil::unpackLongLE(substr($buffer, 48, 8)); + + if ($data['diskNo'] !== 0 || $data['cdDiskNo'] !== 0 || $entryCount !== $cdEntriesDisk) { + throw new ZipException('ZIP file spanning/splitting is not supported!'); + } + + if ($entryCount < 0 || $entryCount > 0x7fffffff) { + throw new ZipException('Total Number Of Entries In The Central Directory out of range!'); + } + + // skip zip64 extensible data sector (variable sizeEndCD) + + return new EndOfCentralDirectory( + $entryCount, + $cdPos, + $cdSize, + true + ); } /** @@ -268,122 +290,108 @@ class ZipInputStream implements ZipInputStreamInterface */ protected function mountCentralDirectory(EndOfCentralDirectory $endOfCentralDirectory) { - $numEntries = $endOfCentralDirectory->getEntryCount(); $entries = []; - for (; $numEntries > 0; $numEntries--) { - $entry = $this->readEntry(); - // Re-load virtual offset after ZIP64 Extended Information - // Extra Field may have been parsed, map it to the real - // offset and conditionally update the preamble size from it. - $lfhOff = $this->mapper->map($entry->getOffset()); + fseek($this->in, $endOfCentralDirectory->getCdOffset()); - if ($lfhOff < $this->preamble) { - $this->preamble = $lfhOff; - } + if (!($cdStream = fopen('php://temp', 'w+b'))) { + throw new ZipException('Temp resource can not open from write'); + } + stream_copy_to_stream($this->in, $cdStream, $endOfCentralDirectory->getCdSize()); + rewind($cdStream); + for ($numEntries = $endOfCentralDirectory->getEntryCount(); $numEntries > 0; $numEntries--) { + $entry = $this->readCentralDirectoryEntry($cdStream); $entries[$entry->getName()] = $entry; } - - if (($numEntries % 0x10000) !== 0) { - throw new ZipException( - 'Expected ' . abs($numEntries) . - ($numEntries > 0 ? ' more' : ' less') . - ' entries in the Central Directory!' - ); - } - - if ($this->preamble + $this->postamble >= fstat($this->in)['size']) { - $this->checkZipFileSignature(); - } + fclose($cdStream); return $entries; } /** + * Read central directory entry. + * + * central file header signature 4 bytes (0x02014b50) + * version made by 2 bytes + * version needed to extract 2 bytes + * general purpose bit flag 2 bytes + * compression method 2 bytes + * last mod file time 2 bytes + * last mod file date 2 bytes + * crc-32 4 bytes + * compressed size 4 bytes + * uncompressed size 4 bytes + * file name length 2 bytes + * extra field length 2 bytes + * file comment length 2 bytes + * disk number start 2 bytes + * internal file attributes 2 bytes + * external file attributes 4 bytes + * relative offset of local header 4 bytes + * + * file name (variable size) + * extra field (variable size) + * file comment (variable size) + * + * @param resource $stream + * * @throws ZipException * * @return ZipEntry */ - public function readEntry() + public function readCentralDirectoryEntry($stream) { - // central file header signature 4 bytes (0x02014b50) - $fileHeaderSig = unpack('V', fread($this->in, 4))[1]; - - if ($fileHeaderSig !== ZipOutputStreamInterface::CENTRAL_FILE_HEADER_SIG) { - throw new InvalidArgumentException('Corrupt zip file. Can not read zip entry.'); + if (unpack('V', fread($stream, 4))[1] !== ZipOutputStreamInterface::CENTRAL_FILE_HEADER_SIG) { + throw new ZipException('Corrupt zip file. Cannot read central dir entry.'); } - // version made by 2 bytes - // version needed to extract 2 bytes - // general purpose bit flag 2 bytes - // compression method 2 bytes - // last mod file time 2 bytes - // last mod file date 2 bytes - // crc-32 4 bytes - // compressed size 4 bytes - // uncompressed size 4 bytes - // file name length 2 bytes - // extra field length 2 bytes - // file comment length 2 bytes - // disk number start 2 bytes - // internal file attributes 2 bytes - // external file attributes 4 bytes - // relative offset of local header 4 bytes $data = unpack( - 'vversionMadeBy/vversionNeededToExtract/vgpbf/' . - 'vrawMethod/VrawTime/VrawCrc/VrawCompressedSize/' . - 'VrawSize/vfileLength/vextraLength/vcommentLength/' . - 'VrawInternalAttributes/VrawExternalAttributes/VlfhOff', - fread($this->in, 42) + 'vversionMadeBy/vversionNeededToExtract/' . + 'vgeneralPurposeBitFlag/vcompressionMethod/' . + 'VlastModFile/Vcrc/VcompressedSize/' . + 'VuncompressedSize/vfileNameLength/vextraFieldLength/' . + 'vfileCommentLength/vdiskNumberStart/vinternalFileAttributes/' . + 'VexternalFileAttributes/VoffsetLocalHeader', + fread($stream, 42) ); -// $utf8 = ($data['gpbf'] & ZipEntry::GPBF_UTF8) !== 0; + $createdOS = ($data['versionMadeBy'] & 0xFF00) >> 8; + $softwareVersion = $data['versionMadeBy'] & 0x00FF; - // See appendix D of PKWARE's ZIP File Format Specification. - $name = ''; - $offset = 0; + $extractOS = ($data['versionNeededToExtract'] & 0xFF00) >> 8; + $extractVersion = $data['versionNeededToExtract'] & 0x00FF; - while ($offset < $data['fileLength']) { - $read = min(8192 /* chunk size */, $data['fileLength'] - $offset); - $name .= fread($this->in, $read); - $offset += $read; + $name = fread($stream, $data['fileNameLength']); + + $extra = ''; + + if ($data['extraFieldLength'] > 0) { + $extra = fread($stream, $data['extraFieldLength']); + } + + $comment = null; + + if ($data['fileCommentLength'] > 0) { + $comment = fread($stream, $data['fileCommentLength']); } $entry = new ZipSourceEntry($this); $entry->setName($name); - $entry->setVersionNeededToExtract($data['versionNeededToExtract']); - $entry->setPlatform($data['versionMadeBy'] >> 8); - $entry->setMethod($data['rawMethod']); - $entry->setGeneralPurposeBitFlags($data['gpbf']); - $entry->setDosTime($data['rawTime']); - $entry->setCrc($data['rawCrc']); - $entry->setCompressedSize($data['rawCompressedSize']); - $entry->setSize($data['rawSize']); - $entry->setExternalAttributes($data['rawExternalAttributes']); - $entry->setOffset($data['lfhOff']); // must be unmapped! - if ($data['extraLength'] > 0) { - $extra = ''; - $offset = 0; - - while ($offset < $data['extraLength']) { - $read = min(8192 /* chunk size */, $data['extraLength'] - $offset); - $extra .= fread($this->in, $read); - $offset += $read; - } - $entry->setExtra($extra); - } - - if ($data['commentLength'] > 0) { - $comment = ''; - $offset = 0; - - while ($offset < $data['commentLength']) { - $read = min(8192 /* chunk size */, $data['commentLength'] - $offset); - $comment .= fread($this->in, $read); - $offset += $read; - } - $entry->setComment($comment); - } + $entry->setCreatedOS($createdOS); + $entry->setSoftwareVersion($softwareVersion); + $entry->setVersionNeededToExtract($extractVersion); + $entry->setExtractedOS($extractOS); + $entry->setMethod($data['compressionMethod']); + $entry->setGeneralPurposeBitFlags($data['generalPurposeBitFlag']); + $entry->setDosTime($data['lastModFile']); + $entry->setCrc($data['crc']); + $entry->setCompressedSize($data['compressedSize']); + $entry->setSize($data['uncompressedSize']); + $entry->setInternalAttributes($data['internalFileAttributes']); + $entry->setExternalAttributes($data['externalFileAttributes']); + $entry->setOffset($data['offsetLocalHeader']); + $entry->setComment($comment); + $entry->setExtra($extra); return $entry; } @@ -410,9 +418,8 @@ class ZipInputStream implements ZipInputStreamInterface throw new ZipException('Can not password from entry ' . $entry->getName()); } - $pos = $entry->getOffset(); + $startPos = $pos = $entry->getOffset(); - $startPos = $pos = $this->mapper->map($pos); fseek($this->in, $startPos); // local file header signature 4 bytes (0x04034b50) @@ -465,7 +472,7 @@ class ZipInputStream implements ZipInputStreamInterface // Traditional PKWARE Decryption $zipCryptoEngine = new TraditionalPkwareEncryptionEngine($entry); $content = $zipCryptoEngine->decrypt($content); - $entry->setEncryptionMethod(ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); + $entry->setEncryptionMethod(ZipFile::ENCRYPTION_METHOD_TRADITIONAL); } if (!$skipCheckCrc) { @@ -500,15 +507,15 @@ class ZipInputStream implements ZipInputStreamInterface } switch ($method) { - case ZipFileInterface::METHOD_STORED: + case ZipFile::METHOD_STORED: break; - case ZipFileInterface::METHOD_DEFLATED: + case ZipFile::METHOD_DEFLATED: /** @noinspection PhpUsageOfSilenceOperatorInspection */ $content = @gzinflate($content); break; - case ZipFileInterface::METHOD_BZIP2: + case ZipFile::METHOD_BZIP2: if (!\extension_loaded('bz2')) { throw new ZipException('Extension bzip2 not install'); } @@ -589,8 +596,6 @@ class ZipInputStream implements ZipInputStreamInterface throw new ZipException(sprintf('Missing local header offset for entry %s', $entry->getName())); } - $pos = $this->mapper->map($pos); - $nameLength = \strlen($entry->getName()); fseek($this->in, $pos + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, \SEEK_SET); @@ -625,7 +630,7 @@ class ZipInputStream implements ZipInputStreamInterface if ( $this->zipModel->isZipAlign() && !$entry->isEncrypted() && - $entry->getMethod() === ZipFileInterface::METHOD_STORED + $entry->getMethod() === ZipFile::METHOD_STORED ) { if (StringUtil::endsWith($entry->getName(), '.so')) { $dataAlignmentMultiple = ApkAlignmentExtraField::ANDROID_COMMON_PAGE_ALIGNMENT_BYTES; @@ -688,7 +693,6 @@ class ZipInputStream implements ZipInputStreamInterface public function copyEntryData(ZipEntry $entry, ZipOutputStreamInterface $out) { $offset = $entry->getOffset(); - $offset = $this->mapper->map($offset); $nameLength = \strlen($entry->getName()); fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, \SEEK_SET); diff --git a/src/PhpZip/Stream/ZipInputStreamInterface.php b/src/PhpZip/Stream/ZipInputStreamInterface.php index 5c21091..e4f2c9c 100644 --- a/src/PhpZip/Stream/ZipInputStreamInterface.php +++ b/src/PhpZip/Stream/ZipInputStreamInterface.php @@ -20,9 +20,15 @@ interface ZipInputStreamInterface public function readZip(); /** + * Read central directory entry. + * + * @param resource $stream + * + * @throws ZipException + * * @return ZipEntry */ - public function readEntry(); + public function readCentralDirectoryEntry($stream); /** * @param ZipEntry $entry diff --git a/src/PhpZip/Stream/ZipOutputStream.php b/src/PhpZip/Stream/ZipOutputStream.php index 897b5d1..ae36c2b 100644 --- a/src/PhpZip/Stream/ZipOutputStream.php +++ b/src/PhpZip/Stream/ZipOutputStream.php @@ -19,7 +19,7 @@ use PhpZip\Model\ZipEntry; use PhpZip\Model\ZipModel; use PhpZip\Util\PackUtil; use PhpZip\Util\StringUtil; -use PhpZip\ZipFileInterface; +use PhpZip\ZipFile; /** * Write zip file. @@ -97,7 +97,7 @@ class ZipOutputStream implements ZipOutputStreamInterface if ( $this->zipModel->isZipAlign() && !$entry->isEncrypted() && - $entry->getMethod() === ZipFileInterface::METHOD_STORED + $entry->getMethod() === ZipFile::METHOD_STORED ) { $dataAlignmentMultiple = $this->zipModel->getZipAlign(); @@ -144,7 +144,7 @@ class ZipOutputStream implements ZipOutputStreamInterface // local file header signature 4 bytes (0x04034b50) ZipEntry::LOCAL_FILE_HEADER_SIG, // version needed to extract 2 bytes - $entry->getVersionNeededToExtract(), + ($entry->getExtractedOS() << 8) | $entry->getVersionNeededToExtract(), // general purpose bit flag 2 bytes $entry->getGeneralPurposeBitFlags(), // compression method 2 bytes @@ -221,8 +221,12 @@ class ZipOutputStream implements ZipOutputStreamInterface */ protected function entryCommitChangesAndReturnContent(ZipEntry $entry) { - if ($entry->getPlatform() === ZipEntry::UNKNOWN) { - $entry->setPlatform(ZipEntry::PLATFORM_UNIX); + if ($entry->getCreatedOS() === ZipEntry::UNKNOWN) { + $entry->setCreatedOS(ZipEntry::PLATFORM_UNIX); + } + + if ($entry->getExtractedOS() === ZipEntry::UNKNOWN) { + $entry->setExtractedOS(ZipEntry::PLATFORM_UNIX); } if ($entry->getTime() === ZipEntry::UNKNOWN) { @@ -265,16 +269,15 @@ class ZipOutputStream implements ZipOutputStreamInterface } switch ($method) { - case ZipFileInterface::METHOD_STORED: + case ZipFile::METHOD_STORED: break; - case ZipFileInterface::METHOD_DEFLATED: + case ZipFile::METHOD_DEFLATED: $entryContent = gzdeflate($entryContent, $entry->getCompressionLevel()); break; - case ZipFileInterface::METHOD_BZIP2: - $compressionLevel = $entry->getCompressionLevel( - ) === ZipFileInterface::LEVEL_DEFAULT_COMPRESSION ? + case ZipFile::METHOD_BZIP2: + $compressionLevel = $entry->getCompressionLevel() === ZipFile::LEVEL_DEFAULT_COMPRESSION ? ZipEntry::LEVEL_DEFAULT_BZIP2_COMPRESSION : $entry->getCompressionLevel(); /** @noinspection PhpComposerExtensionStubsInspection */ @@ -294,19 +297,19 @@ class ZipOutputStream implements ZipOutputStreamInterface throw new ZipException($entry->getName() . ' (unsupported compression method ' . $method . ')'); } - if ($method === ZipFileInterface::METHOD_DEFLATED) { + if ($method === ZipFile::METHOD_DEFLATED) { $bit1 = false; $bit2 = false; switch ($entry->getCompressionLevel()) { - case ZipFileInterface::LEVEL_BEST_COMPRESSION: + case ZipFile::LEVEL_BEST_COMPRESSION: $bit1 = true; break; - case ZipFileInterface::LEVEL_FAST: + case ZipFile::LEVEL_FAST: $bit2 = true; break; - case ZipFileInterface::LEVEL_SUPER_FAST: + case ZipFile::LEVEL_SUPER_FAST: $bit1 = true; $bit2 = true; break; @@ -320,9 +323,9 @@ class ZipOutputStream implements ZipOutputStreamInterface if (\in_array( $entry->getEncryptionMethod(), [ - ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128, - ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192, - ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256, + ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128, + ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192, + ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256, ], true )) { @@ -334,7 +337,7 @@ class ZipOutputStream implements ZipOutputStreamInterface $field->setMethod($method); $size = $entry->getSize(); - if ($size >= 20 && $method !== ZipFileInterface::METHOD_BZIP2) { + if ($size >= 20 && $method !== ZipFile::METHOD_BZIP2) { $field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_1); } else { $field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_2); @@ -345,7 +348,7 @@ class ZipOutputStream implements ZipOutputStreamInterface $winZipAesEngine = new WinZipAesEngine($entry); $entryContent = $winZipAesEngine->encrypt($entryContent); - } elseif ($entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL) { + } elseif ($entry->getEncryptionMethod() === ZipFile::ENCRYPTION_METHOD_TRADITIONAL) { $zipCryptoEngine = new TraditionalPkwareEncryptionEngine($entry); $entryContent = $zipCryptoEngine->encrypt($entryContent); } @@ -382,11 +385,11 @@ class ZipOutputStream implements ZipOutputStreamInterface $entryContent = gzdeflate($content, $entry->getCompressionLevel()); if (\strlen($entryContent) < \strlen($content)) { - $entry->setMethod(ZipFileInterface::METHOD_DEFLATED); + $entry->setMethod(ZipFile::METHOD_DEFLATED); return $entryContent; } - $entry->setMethod(ZipFileInterface::METHOD_STORED); + $entry->setMethod(ZipFile::METHOD_STORED); } return $content; @@ -418,9 +421,9 @@ class ZipOutputStream implements ZipOutputStreamInterface // central file header signature 4 bytes (0x02014b50) self::CENTRAL_FILE_HEADER_SIG, // version made by 2 bytes - ($entry->getPlatform() << 8) | 63, + ($entry->getCreatedOS() << 8) | $entry->getSoftwareVersion(), // version needed to extract 2 bytes - $entry->getVersionNeededToExtract(), + ($entry->getExtractedOS() << 8) | $entry->getVersionNeededToExtract(), // general purpose bit flag 2 bytes $entry->getGeneralPurposeBitFlags(), // compression method 2 bytes @@ -442,7 +445,7 @@ class ZipOutputStream implements ZipOutputStreamInterface // disk number start 2 bytes 0, // internal file attributes 2 bytes - 0, + $entry->getInternalAttributes(), // external file attributes 4 bytes $entry->getExternalAttributes(), // relative offset of local header 4 bytes @@ -468,75 +471,99 @@ class ZipOutputStream implements ZipOutputStreamInterface */ protected function writeEndOfCentralDirectoryRecord($centralDirectoryOffset) { - $centralDirectoryOffset = (int) $centralDirectoryOffset; - $centralDirectoryEntriesCount = \count($this->zipModel); + $cdEntriesCount = \count($this->zipModel); + $position = ftell($this->out); $centralDirectorySize = $position - $centralDirectoryOffset; - $centralDirectoryEntriesZip64 = $centralDirectoryEntriesCount > 0xffff; - $centralDirectorySizeZip64 = $centralDirectorySize > 0xffffffff; - $centralDirectoryOffsetZip64 = $centralDirectoryOffset > 0xffffffff; - $centralDirectoryEntries16 = $centralDirectoryEntriesZip64 ? 0xffff : $centralDirectoryEntriesCount; - $centralDirectorySize32 = $centralDirectorySizeZip64 ? 0xffffffff : $centralDirectorySize; - $centralDirectoryOffset32 = $centralDirectoryOffsetZip64 ? 0xffffffff : $centralDirectoryOffset; - $zip64 // ZIP64 extensions? - = $centralDirectoryEntriesZip64 - || $centralDirectorySizeZip64 - || $centralDirectoryOffsetZip64; - if ($zip64) { - // [zip64 end of central directory record] - // relative offset of the zip64 end of central directory record - $zip64EndOfCentralDirectoryOffset = $position; - // zip64 end of central dir + $cdEntriesZip64 = $cdEntriesCount > 0xFFFF; + $cdSizeZip64 = $centralDirectorySize > 0xFFFFFFFF; + $cdOffsetZip64 = $centralDirectoryOffset > 0xFFFFFFFF; + + $zip64Required = $cdEntriesZip64 || $cdSizeZip64 || $cdOffsetZip64; + + if ($zip64Required) { + $zip64EndOfCentralDirectoryOffset = ftell($this->out); + + // find max software version, version needed to extract and most common platform + list($softwareVersion, $versionNeededToExtract) = array_reduce( + $this->zipModel->getEntries(), + static function (array $carry, ZipEntry $entry) { + $carry[0] = max($carry[0], $entry->getSoftwareVersion() & 0xFF); + $carry[1] = max($carry[1], $entry->getVersionNeededToExtract() & 0xFF); + + return $carry; + }, + [10 /* simple file min ver */, 45 /* zip64 ext min ver */] + ); + + $createdOS = $extractedOS = ZipEntry::PLATFORM_FAT; + $versionMadeBy = ($createdOS << 8) | max($softwareVersion, 45 /* zip64 ext min ver */); + $versionExtractedBy = ($extractedOS << 8) | max($versionNeededToExtract, 45 /* zip64 ext min ver */); + // signature 4 bytes (0x06064b50) - fwrite($this->out, pack('V', EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG)); + fwrite($this->out, pack('V', EndOfCentralDirectory::ZIP64_END_OF_CD_RECORD_SIG)); // size of zip64 end of central // directory record 8 bytes + fwrite($this->out, PackUtil::packLongLE(44)); fwrite( $this->out, - PackUtil::packLongLE(EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN - 12) + pack( + 'vvVV', + // version made by 2 bytes + $versionMadeBy & 0xFFFF, + // version needed to extract 2 bytes + $versionExtractedBy & 0xFFFF, + // number of this disk 4 bytes + 0, + // number of the disk with the + // start of the central directory 4 bytes + 0 + ) ); - // version made by 2 bytes - // version needed to extract 2 bytes - // due to potential use of BZIP2 compression - // number of this disk 4 bytes - // number of the disk with the - // start of the central directory 4 bytes - fwrite($this->out, pack('vvVV', 63, 46, 0, 0)); // total number of entries in the // central directory on this disk 8 bytes - fwrite($this->out, PackUtil::packLongLE($centralDirectoryEntriesCount)); + fwrite($this->out, PackUtil::packLongLE($cdEntriesCount)); // total number of entries in the // central directory 8 bytes - fwrite($this->out, PackUtil::packLongLE($centralDirectoryEntriesCount)); + fwrite($this->out, PackUtil::packLongLE($cdEntriesCount)); // size of the central directory 8 bytes fwrite($this->out, PackUtil::packLongLE($centralDirectorySize)); // offset of start of central // directory with respect to // the starting disk number 8 bytes fwrite($this->out, PackUtil::packLongLE($centralDirectoryOffset)); - // zip64 extensible data sector (variable size) - // [zip64 end of central directory locator] - // signature 4 bytes (0x07064b50) - // number of the disk with the - // start of the zip64 end of - // central directory 4 bytes - fwrite($this->out, pack('VV', EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG, 0)); + // write zip64 end of central directory locator + fwrite( + $this->out, + pack( + 'VV', + // zip64 end of central dir locator + // signature 4 bytes (0x07064b50) + EndOfCentralDirectory::ZIP64_END_OF_CD_LOCATOR_SIG, + // number of the disk with the + // start of the zip64 end of + // central directory 4 bytes + 0 + ) + ); // relative offset of the zip64 // end of central directory record 8 bytes fwrite($this->out, PackUtil::packLongLE($zip64EndOfCentralDirectoryOffset)); // total number of disks 4 bytes fwrite($this->out, pack('V', 1)); } + $comment = $this->zipModel->getArchiveComment(); - $commentLength = \strlen($comment); + $commentLength = $comment !== null ? \strlen($comment) : 0; + fwrite( $this->out, pack( 'VvvvvVVv', // end of central dir signature 4 bytes (0x06054b50) - EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG, + EndOfCentralDirectory::END_OF_CD_SIG, // number of this disk 2 bytes 0, // number of the disk with the @@ -544,16 +571,16 @@ class ZipOutputStream implements ZipOutputStreamInterface 0, // total number of entries in the // central directory on this disk 2 bytes - $centralDirectoryEntries16, + $cdEntriesZip64 ? 0xFFFF : $cdEntriesCount, // total number of entries in // the central directory 2 bytes - $centralDirectoryEntries16, + $cdEntriesZip64 ? 0xFFFF : $cdEntriesCount, // size of the central directory 4 bytes - $centralDirectorySize32, + $cdSizeZip64 ? 0xFFFFFFFF : $centralDirectorySize, // offset of start of central // directory with respect to // the starting disk number 4 bytes - $centralDirectoryOffset32, + $cdOffsetZip64 ? 0xFFFFFFFF : $centralDirectoryOffset, // .ZIP file comment length 2 bytes $commentLength ) diff --git a/src/PhpZip/ZipFile.php b/src/PhpZip/ZipFile.php index 2a3aba4..52969f9 100644 --- a/src/PhpZip/ZipFile.php +++ b/src/PhpZip/ZipFile.php @@ -234,8 +234,8 @@ class ZipFile implements ZipFileInterface * @param string $entryName * @param string|null $comment * - * @throws ZipEntryNotFoundException * @throws ZipException + * @throws ZipEntryNotFoundException * * @return ZipFileInterface */ @@ -277,8 +277,8 @@ class ZipFile implements ZipFileInterface * * @param string|ZipEntry $entryName * - * @throws ZipException * @throws ZipEntryNotFoundException + * @throws ZipException * * @return ZipInfo */ @@ -398,9 +398,9 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addFromString($localName, $contents, $compressionMethod = null) { @@ -454,9 +454,9 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addFile($filename, $localName = null, $compressionMethod = null) { @@ -520,9 +520,9 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addFromStream($stream, $localName, $compressionMethod = null) { @@ -655,9 +655,9 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addDirRecursive($inputDir, $localPath = '/', $compressionMethod = null) { @@ -693,9 +693,9 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addFilesFromIterator( \Iterator $iterator, @@ -1091,10 +1091,10 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @see ZipFileInterface::LEVEL_DEFAULT_COMPRESSION - * @see ZipFileInterface::LEVEL_SUPER_FAST - * @see ZipFileInterface::LEVEL_FAST - * @see ZipFileInterface::LEVEL_BEST_COMPRESSION + * @see ZipFile::LEVEL_DEFAULT_COMPRESSION + * @see ZipFile::LEVEL_SUPER_FAST + * @see ZipFile::LEVEL_FAST + * @see ZipFile::LEVEL_BEST_COMPRESSION */ public function setCompressionLevel($compressionLevel = self::LEVEL_DEFAULT_COMPRESSION) { @@ -1123,16 +1123,16 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @see ZipFileInterface::LEVEL_DEFAULT_COMPRESSION - * @see ZipFileInterface::LEVEL_SUPER_FAST - * @see ZipFileInterface::LEVEL_FAST - * @see ZipFileInterface::LEVEL_BEST_COMPRESSION + * @see ZipFile::LEVEL_DEFAULT_COMPRESSION + * @see ZipFile::LEVEL_SUPER_FAST + * @see ZipFile::LEVEL_FAST + * @see ZipFile::LEVEL_BEST_COMPRESSION */ public function setCompressionLevelEntry($entryName, $compressionLevel) { if ($compressionLevel !== null) { - if ($compressionLevel < ZipFileInterface::LEVEL_DEFAULT_COMPRESSION || - $compressionLevel > ZipFileInterface::LEVEL_BEST_COMPRESSION + if ($compressionLevel < self::LEVEL_DEFAULT_COMPRESSION || + $compressionLevel > self::LEVEL_BEST_COMPRESSION ) { throw new InvalidArgumentException( 'Invalid compression level. Minimum level ' . @@ -1158,9 +1158,9 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function setCompressionMethodEntry($entryName, $compressionMethod) { @@ -1204,7 +1204,7 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @deprecated using ZipFileInterface::setReadPassword() + * @deprecated using ZipFile::setReadPassword() */ public function withReadPassword($password) { @@ -1254,7 +1254,7 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @deprecated using ZipFileInterface::setPassword() + * @deprecated using ZipFile::setPassword() */ public function withNewPassword($password, $encryptionMethod = self::ENCRYPTION_METHOD_WINZIP_AES_256) { @@ -1311,7 +1311,7 @@ class ZipFile implements ZipFileInterface * * @return ZipFileInterface * - * @deprecated using ZipFileInterface::disableEncryption() + * @deprecated using ZipFile::disableEncryption() */ public function withoutPassword() { diff --git a/src/PhpZip/ZipFileInterface.php b/src/PhpZip/ZipFileInterface.php index b876cc4..c17db22 100644 --- a/src/PhpZip/ZipFileInterface.php +++ b/src/PhpZip/ZipFileInterface.php @@ -233,9 +233,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addFromString($localName, $contents, $compressionMethod = null); @@ -250,9 +250,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addFile($filename, $localName = null, $compressionMethod = null); @@ -267,9 +267,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addFromStream($stream, $localName, $compressionMethod = null); @@ -306,9 +306,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addDirRecursive($inputDir, $localPath = '/', $compressionMethod = null); @@ -323,9 +323,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function addFilesFromIterator(\Iterator $iterator, $localPath = '/', $compressionMethod = null); @@ -456,10 +456,10 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @see ZipFileInterface::LEVEL_SUPER_FAST - * @see ZipFileInterface::LEVEL_FAST - * @see ZipFileInterface::LEVEL_BEST_COMPRESSION - * @see ZipFileInterface::LEVEL_DEFAULT_COMPRESSION + * @see ZipFile::LEVEL_SUPER_FAST + * @see ZipFile::LEVEL_FAST + * @see ZipFile::LEVEL_BEST_COMPRESSION + * @see ZipFile::LEVEL_DEFAULT_COMPRESSION */ public function setCompressionLevel($compressionLevel = self::LEVEL_DEFAULT_COMPRESSION); @@ -471,10 +471,10 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @see ZipFileInterface::LEVEL_DEFAULT_COMPRESSION - * @see ZipFileInterface::LEVEL_SUPER_FAST - * @see ZipFileInterface::LEVEL_FAST - * @see ZipFileInterface::LEVEL_BEST_COMPRESSION + * @see ZipFile::LEVEL_DEFAULT_COMPRESSION + * @see ZipFile::LEVEL_SUPER_FAST + * @see ZipFile::LEVEL_FAST + * @see ZipFile::LEVEL_BEST_COMPRESSION */ public function setCompressionLevelEntry($entryName, $compressionLevel); @@ -486,9 +486,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @see ZipFileInterface::METHOD_STORED - * @see ZipFileInterface::METHOD_DEFLATED - * @see ZipFileInterface::METHOD_BZIP2 + * @see ZipFile::METHOD_STORED + * @see ZipFile::METHOD_DEFLATED + * @see ZipFile::METHOD_BZIP2 */ public function setCompressionMethodEntry($entryName, $compressionMethod); @@ -510,7 +510,7 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @deprecated using ZipFileInterface::setReadPassword() + * @deprecated using ZipFile::setReadPassword() */ public function withReadPassword($password); @@ -541,7 +541,7 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @deprecated using ZipFileInterface::setPassword() + * @deprecated using ZipFile::setPassword() */ public function withNewPassword($password, $encryptionMethod = self::ENCRYPTION_METHOD_WINZIP_AES_256); @@ -571,7 +571,7 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator * * @return ZipFileInterface * - * @deprecated using ZipFileInterface::disableEncryption() + * @deprecated using ZipFile::disableEncryption() */ public function withoutPassword(); diff --git a/tests/PhpZip/PhpZipExtResourceTest.php b/tests/PhpZip/PhpZipExtResourceTest.php index 1c1ee9a..859ebe5 100644 --- a/tests/PhpZip/PhpZipExtResourceTest.php +++ b/tests/PhpZip/PhpZipExtResourceTest.php @@ -127,7 +127,10 @@ class PhpZipExtResourceTest extends ZipTestCase public function testBug70752() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException(RuntimeException::class, 'Traditional PKWARE Encryption is not supported in 32-bit PHP.'); + $this->setExpectedException( + RuntimeException::class, + 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' + ); } else { // php 64 bit $this->setExpectedException( ZipAuthenticationException::class, @@ -163,19 +166,11 @@ class PhpZipExtResourceTest extends ZipTestCase */ public function testPecl12414() { - $filename = __DIR__ . '/php-zip-ext-test-resources/pecl12414.zip'; + $this->setExpectedException(ZipException::class, 'Corrupt zip file. Cannot read central dir entry.'); - $entryName = 'MYLOGOV2.GFX'; + $filename = __DIR__ . '/php-zip-ext-test-resources/pecl12414.zip'; $zipFile = new ZipFile(); $zipFile->openFile($filename); - - $info = $zipFile->getEntryInfo($entryName); - static::assertTrue($info->getSize() > 0); - - $contents = $zipFile[$entryName]; - static::assertSame(\strlen($contents), $info->getSize()); - - $zipFile->close(); } } diff --git a/tests/PhpZip/ZipAlignTest.php b/tests/PhpZip/ZipAlignTest.php index 177f0a9..8201b83 100644 --- a/tests/PhpZip/ZipAlignTest.php +++ b/tests/PhpZip/ZipAlignTest.php @@ -54,7 +54,7 @@ class ZipAlignTest extends ZipTestCase $zipFile->addFromString( 'entry' . $i . '.txt', CryptoUtil::randomBytes(mt_rand(100, 4096)), - ZipFileInterface::METHOD_STORED + ZipFile::METHOD_STORED ); } $zipFile->saveAsFile($this->outputFilename); @@ -95,7 +95,7 @@ class ZipAlignTest extends ZipTestCase $zipFile->addFromString( 'entry' . $i . '.txt', CryptoUtil::randomBytes(mt_rand(100, 4096)), - ZipFileInterface::METHOD_STORED + ZipFile::METHOD_STORED ); } $zipFile->setZipAlign(4); @@ -123,7 +123,7 @@ class ZipAlignTest extends ZipTestCase $zipFile->addFromString( 'entry' . $i . '.txt', CryptoUtil::randomBytes(mt_rand(100, 4096)), - ZipFileInterface::METHOD_STORED + ZipFile::METHOD_STORED ); } $zipFile->saveAsFile($this->outputFilename); @@ -149,8 +149,8 @@ class ZipAlignTest extends ZipTestCase 'entry_new_' . ($isStored ? 'stored' : 'deflated') . '_' . $i . '.txt', CryptoUtil::randomBytes(mt_rand(100, 4096)), $isStored ? - ZipFileInterface::METHOD_STORED : - ZipFileInterface::METHOD_DEFLATED + ZipFile::METHOD_STORED : + ZipFile::METHOD_DEFLATED ); } $zipFile->setZipAlign(4); diff --git a/tests/PhpZip/ZipFileTest.php b/tests/PhpZip/ZipFileTest.php index fa97374..5f80f95 100644 --- a/tests/PhpZip/ZipFileTest.php +++ b/tests/PhpZip/ZipFileTest.php @@ -909,12 +909,12 @@ class ZipFileTest extends ZipTestCase $entries = [ '1' => [ 'data' => CryptoUtil::randomBytes(255), - 'method' => ZipFileInterface::METHOD_STORED, + 'method' => ZipFile::METHOD_STORED, 'expected' => 'No compression', ], '2' => [ 'data' => CryptoUtil::randomBytes(255), - 'method' => ZipFileInterface::METHOD_DEFLATED, + 'method' => ZipFile::METHOD_DEFLATED, 'expected' => 'Deflate', ], ]; @@ -922,7 +922,7 @@ class ZipFileTest extends ZipTestCase if (\extension_loaded('bz2')) { $entries['3'] = [ 'data' => CryptoUtil::randomBytes(255), - 'method' => ZipFileInterface::METHOD_BZIP2, + 'method' => ZipFile::METHOD_BZIP2, 'expected' => 'Bzip2', ]; } @@ -938,7 +938,7 @@ class ZipFileTest extends ZipTestCase static::assertCorrectZipArchive($this->outputFilename); $zipFile->openFile($this->outputFilename); - $zipFile->setCompressionLevel(ZipFileInterface::LEVEL_BEST_COMPRESSION); + $zipFile->setCompressionLevel(ZipFile::LEVEL_BEST_COMPRESSION); $zipAllInfo = $zipFile->getAllInfo(); foreach ($zipAllInfo as $entryName => $info) { @@ -1693,14 +1693,14 @@ class ZipFileTest extends ZipTestCase $files['file' . $i . '.txt'] = CryptoUtil::randomBytes(255); } - $methods = [ZipFileInterface::METHOD_STORED, ZipFileInterface::METHOD_DEFLATED]; + $methods = [ZipFile::METHOD_STORED, ZipFile::METHOD_DEFLATED]; if (\extension_loaded('bz2')) { - $methods[] = ZipFileInterface::METHOD_BZIP2; + $methods[] = ZipFile::METHOD_BZIP2; } $zipFile = new ZipFile(); - $zipFile->setCompressionLevel(ZipFileInterface::LEVEL_BEST_SPEED); + $zipFile->setCompressionLevel(ZipFile::LEVEL_BEST_SPEED); foreach ($files as $entryName => $content) { $zipFile->addFromString($entryName, $content, $methods[array_rand($methods)]); @@ -1985,14 +1985,14 @@ class ZipFileTest extends ZipTestCase { $zipFile = new ZipFile(); $zipFile - ->addFromString('file', 'content', ZipFileInterface::METHOD_DEFLATED) - ->setCompressionLevelEntry('file', ZipFileInterface::LEVEL_BEST_COMPRESSION) - ->addFromString('file2', 'content', ZipFileInterface::METHOD_DEFLATED) - ->setCompressionLevelEntry('file2', ZipFileInterface::LEVEL_FAST) - ->addFromString('file3', 'content', ZipFileInterface::METHOD_DEFLATED) - ->setCompressionLevelEntry('file3', ZipFileInterface::LEVEL_SUPER_FAST) - ->addFromString('file4', 'content', ZipFileInterface::METHOD_DEFLATED) - ->setCompressionLevelEntry('file4', ZipFileInterface::LEVEL_DEFAULT_COMPRESSION) + ->addFromString('file', 'content', ZipFile::METHOD_DEFLATED) + ->setCompressionLevelEntry('file', ZipFile::LEVEL_BEST_COMPRESSION) + ->addFromString('file2', 'content', ZipFile::METHOD_DEFLATED) + ->setCompressionLevelEntry('file2', ZipFile::LEVEL_FAST) + ->addFromString('file3', 'content', ZipFile::METHOD_DEFLATED) + ->setCompressionLevelEntry('file3', ZipFile::LEVEL_SUPER_FAST) + ->addFromString('file4', 'content', ZipFile::METHOD_DEFLATED) + ->setCompressionLevelEntry('file4', ZipFile::LEVEL_DEFAULT_COMPRESSION) ->saveAsFile($this->outputFilename) ->close() ; @@ -2003,22 +2003,22 @@ class ZipFileTest extends ZipTestCase static::assertSame( $zipFile->getEntryInfo('file') ->getCompressionLevel(), - ZipFileInterface::LEVEL_BEST_COMPRESSION + ZipFile::LEVEL_BEST_COMPRESSION ); static::assertSame( $zipFile->getEntryInfo('file2') ->getCompressionLevel(), - ZipFileInterface::LEVEL_FAST + ZipFile::LEVEL_FAST ); static::assertSame( $zipFile->getEntryInfo('file3') ->getCompressionLevel(), - ZipFileInterface::LEVEL_SUPER_FAST + ZipFile::LEVEL_SUPER_FAST ); static::assertSame( $zipFile->getEntryInfo('file4') ->getCompressionLevel(), - ZipFileInterface::LEVEL_DEFAULT_COMPRESSION + ZipFile::LEVEL_DEFAULT_COMPRESSION ); $zipFile->close(); } @@ -2054,10 +2054,10 @@ class ZipFileTest extends ZipTestCase { $zipFile = new ZipFile(); for ($i = 0; $i < 10; $i++) { - $zipFile->addFromString('file' . $i, 'content', ZipFileInterface::METHOD_DEFLATED); + $zipFile->addFromString('file' . $i, 'content', ZipFile::METHOD_DEFLATED); } $zipFile - ->setCompressionLevel(ZipFileInterface::LEVEL_BEST_SPEED) + ->setCompressionLevel(ZipFile::LEVEL_BEST_SPEED) ->saveAsFile($this->outputFilename) ->close() ; @@ -2069,7 +2069,7 @@ class ZipFileTest extends ZipTestCase array_walk( $infoList, function (ZipInfo $zipInfo) { - $this->assertSame($zipInfo->getCompressionLevel(), ZipFileInterface::LEVEL_BEST_SPEED); + $this->assertSame($zipInfo->getCompressionLevel(), ZipFile::LEVEL_BEST_SPEED); } ); $zipFile->close(); @@ -2082,13 +2082,13 @@ class ZipFileTest extends ZipTestCase public function testCompressionMethodEntry() { $zipFile = new ZipFile(); - $zipFile->addFromString('file', 'content', ZipFileInterface::METHOD_STORED); + $zipFile->addFromString('file', 'content', ZipFile::METHOD_STORED); $zipFile->saveAsFile($this->outputFilename); $zipFile->close(); $zipFile->openFile($this->outputFilename); static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'No compression'); - $zipFile->setCompressionMethodEntry('file', ZipFileInterface::METHOD_DEFLATED); + $zipFile->setCompressionMethodEntry('file', ZipFile::METHOD_DEFLATED); static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'Deflate'); $zipFile->rewrite(); @@ -2103,7 +2103,7 @@ class ZipFileTest extends ZipTestCase $this->setExpectedException(ZipUnsupportMethodException::class, 'Unsupported method'); $zipFile = new ZipFile(); - $zipFile->addFromString('file', 'content', ZipFileInterface::METHOD_STORED); + $zipFile->addFromString('file', 'content', ZipFile::METHOD_STORED); $zipFile->setCompressionMethodEntry('file', 99); } diff --git a/tests/PhpZip/ZipMatcherTest.php b/tests/PhpZip/ZipMatcherTest.php index debf574..11d8fc7 100644 --- a/tests/PhpZip/ZipMatcherTest.php +++ b/tests/PhpZip/ZipMatcherTest.php @@ -38,8 +38,16 @@ class ZipMatcherTest extends TestCase $matcher->match('~^[2][1-5]|[3][6-9]|40$~s'); static::assertCount(10, $matcher); $actualMatches = [ - '21', '22', '23', '24', '25', - '36', '37', '38', '39', '40', + '21', + '22', + '23', + '24', + '25', + '36', + '37', + '38', + '39', + '40', ]; static::assertSame($matcher->getMatches(), $actualMatches); $matcher->setPassword('qwerty'); diff --git a/tests/PhpZip/ZipPasswordTest.php b/tests/PhpZip/ZipPasswordTest.php index dc00b26..b147b70 100644 --- a/tests/PhpZip/ZipPasswordTest.php +++ b/tests/PhpZip/ZipPasswordTest.php @@ -22,11 +22,15 @@ class ZipPasswordTest extends ZipFileAddDirTest * Test archive password. * * @throws ZipException + * @noinspection PhpRedundantCatchClauseInspection */ public function testSetPassword() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException(RuntimeException::class, 'Traditional PKWARE Encryption is not supported in 32-bit PHP.'); + $this->setExpectedException( + RuntimeException::class, + 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' + ); } $password = base64_encode(CryptoUtil::randomBytes(100)); @@ -35,7 +39,7 @@ class ZipPasswordTest extends ZipFileAddDirTest // create encryption password with ZipCrypto $zipFile = new ZipFile(); $zipFile->addDir(__DIR__); - $zipFile->setPassword($password, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); + $zipFile->setPassword($password, ZipFile::ENCRYPTION_METHOD_TRADITIONAL); $zipFile->saveAsFile($this->outputFilename); $zipFile->close(); @@ -66,7 +70,7 @@ class ZipPasswordTest extends ZipFileAddDirTest } // change encryption method to WinZip Aes and update file - $zipFile->setPassword($password, ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES); + $zipFile->setPassword($password, ZipFile::ENCRYPTION_METHOD_WINZIP_AES); $zipFile->saveAsFile($this->outputFilename); $zipFile->close(); @@ -121,14 +125,17 @@ class ZipPasswordTest extends ZipFileAddDirTest public function testTraditionalEncryption() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException(RuntimeException::class, 'Traditional PKWARE Encryption is not supported in 32-bit PHP.'); + $this->setExpectedException( + RuntimeException::class, + 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' + ); } $password = base64_encode(CryptoUtil::randomBytes(50)); $zip = new ZipFile(); $zip->addDirRecursive($this->outputDirname); - $zip->setPassword($password, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); + $zip->setPassword($password, ZipFile::ENCRYPTION_METHOD_TRADITIONAL); $zip->saveAsFile($this->outputFilename); $zip->close(); @@ -187,10 +194,10 @@ class ZipPasswordTest extends ZipFileAddDirTest public function winZipKeyStrengthProvider() { return [ - [ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128, 128], - [ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192, 192], - [ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES, 256], - [ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256, 256], + [ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128, 128], + [ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192, 192], + [ZipFile::ENCRYPTION_METHOD_WINZIP_AES, 256], + [ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256, 256], ]; } @@ -201,7 +208,10 @@ class ZipPasswordTest extends ZipFileAddDirTest public function testEncryptionEntries() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException(RuntimeException::class, 'Traditional PKWARE Encryption is not supported in 32-bit PHP.'); + $this->setExpectedException( + RuntimeException::class, + 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' + ); } $password1 = '353442434235424234'; @@ -209,8 +219,8 @@ class ZipPasswordTest extends ZipFileAddDirTest $zip = new ZipFile(); $zip->addDir($this->outputDirname); - $zip->setPasswordEntry('.hidden', $password1, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); - $zip->setPasswordEntry('text file.txt', $password2, ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES); + $zip->setPasswordEntry('.hidden', $password1, ZipFile::ENCRYPTION_METHOD_TRADITIONAL); + $zip->setPasswordEntry('text file.txt', $password2, ZipFile::ENCRYPTION_METHOD_WINZIP_AES); $zip->saveAsFile($this->outputFilename); $zip->close(); @@ -248,7 +258,10 @@ class ZipPasswordTest extends ZipFileAddDirTest public function testEncryptionEntriesWithDefaultPassword() { if (\PHP_INT_SIZE === 4) { // php 32 bit - $this->setExpectedException(RuntimeException::class, 'Traditional PKWARE Encryption is not supported in 32-bit PHP.'); + $this->setExpectedException( + RuntimeException::class, + 'Traditional PKWARE Encryption is not supported in 32-bit PHP.' + ); } $password1 = '353442434235424234'; @@ -258,8 +271,8 @@ class ZipPasswordTest extends ZipFileAddDirTest $zip = new ZipFile(); $zip->addDir($this->outputDirname); $zip->setPassword($defaultPassword); - $zip->setPasswordEntry('.hidden', $password1, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); - $zip->setPasswordEntry('text file.txt', $password2, ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES); + $zip->setPasswordEntry('.hidden', $password1, ZipFile::ENCRYPTION_METHOD_TRADITIONAL); + $zip->setPasswordEntry('text file.txt', $password2, ZipFile::ENCRYPTION_METHOD_WINZIP_AES); $zip->saveAsFile($this->outputFilename); $zip->close(); @@ -350,7 +363,7 @@ class ZipPasswordTest extends ZipFileAddDirTest $this->setExpectedException(ZipException::class, 'Invalid encryption method'); $zipFile = new ZipFile(); - $zipFile->addFromString('file', 'content', ZipFileInterface::METHOD_STORED); + $zipFile->addFromString('file', 'content', ZipFile::METHOD_STORED); $zipFile->setPasswordEntry('file', 'pass', 99); } diff --git a/tests/PhpZip/ZipTestCase.php b/tests/PhpZip/ZipTestCase.php index 5dfd400..a00e172 100644 --- a/tests/PhpZip/ZipTestCase.php +++ b/tests/PhpZip/ZipTestCase.php @@ -129,7 +129,7 @@ abstract class ZipTestCase extends TestCase static::assertContains('Empty zipfile', $output); } - $actualEmptyZipData = pack('VVVVVv', EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG, 0, 0, 0, 0, 0); + $actualEmptyZipData = pack('VVVVVv', EndOfCentralDirectory::END_OF_CD_SIG, 0, 0, 0, 0, 0); static::assertStringEqualsFile($filename, $actualEmptyZipData); }