1
0
mirror of https://github.com/Ne-Lexa/php-zip.git synced 2025-07-27 18:50:11 +02:00

refactoring zip64, add property softwareVersion, internal attrs, extracted os

This commit is contained in:
Ne-Lexa
2019-12-06 17:36:22 +03:00
parent e2c058840c
commit 95e3312e60
24 changed files with 821 additions and 626 deletions

View File

@@ -25,11 +25,6 @@
"ext-zlib": "*", "ext-zlib": "*",
"psr/http-message": "^1.0" "psr/http-message": "^1.0"
}, },
"config": {
"platform": {
"php": "5.5"
}
},
"require-dev": { "require-dev": {
"phpunit/phpunit": "^4.8|^5.7", "phpunit/phpunit": "^4.8|^5.7",
"zendframework/zend-diactoros": "^1.4" "zendframework/zend-diactoros": "^1.4"

View File

@@ -49,9 +49,9 @@ class WinZipAesEngine implements ZipEncryptionEngine
* *
* @param string $content Input stream buffer * @param string $content Input stream buffer
* *
* @throws ZipCryptoException
* @throws ZipException * @throws ZipException
* @throws ZipAuthenticationException * @throws ZipAuthenticationException
* @throws ZipCryptoException
* *
* @return string * @return string
*/ */

View File

@@ -4,7 +4,7 @@ namespace PhpZip\Extra\Fields;
use PhpZip\Exception\ZipException; use PhpZip\Exception\ZipException;
use PhpZip\Extra\ExtraField; use PhpZip\Extra\ExtraField;
use PhpZip\ZipFileInterface; use PhpZip\ZipFile;
/** /**
* WinZip AES Extra Field. * WinZip AES Extra Field.
@@ -49,9 +49,9 @@ class WinZipAesEntryExtraField implements ExtraField
]; ];
protected static $encryptionMethods = [ protected static $encryptionMethods = [
self::KEY_STRENGTH_128BIT => ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128, self::KEY_STRENGTH_128BIT => ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128,
self::KEY_STRENGTH_192BIT => ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192, self::KEY_STRENGTH_192BIT => ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192,
self::KEY_STRENGTH_256BIT => ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256, self::KEY_STRENGTH_256BIT => ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256,
]; ];
/** /**

View File

@@ -1,43 +0,0 @@
<?php
namespace PhpZip\Mapper;
/**
* Adds a offset value to the given position.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class OffsetPositionMapper extends PositionMapper
{
/** @var int */
private $offset;
/**
* @param int $offset
*/
public function __construct($offset)
{
$this->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;
}
}

View File

@@ -1,32 +0,0 @@
<?php
namespace PhpZip\Mapper;
/**
* Maps a given position.
*
* @author Ne-Lexa alexey@nelexa.ru
* @license MIT
*/
class PositionMapper
{
/**
* @param int $position
*
* @return int
*/
public function map($position)
{
return $position;
}
/**
* @param int $position
*
* @return int
*/
public function unmap($position)
{
return $position;
}
}

View File

@@ -3,7 +3,7 @@
namespace PhpZip\Model; namespace PhpZip\Model;
/** /**
* Read End of Central Directory. * End of Central Directory.
* *
* @author Ne-Lexa alexey@nelexa.ru * @author Ne-Lexa alexey@nelexa.ru
* @license MIT * @license MIT
@@ -11,13 +11,13 @@ namespace PhpZip\Model;
class EndOfCentralDirectory class EndOfCentralDirectory
{ {
/** Zip64 End Of Central Directory Record. */ /** Zip64 End Of Central Directory Record. */
const ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG = 0x06064B50; const ZIP64_END_OF_CD_RECORD_SIG = 0x06064B50;
/** Zip64 End Of Central Directory Locator. */ /** Zip64 End Of Central Directory Locator. */
const ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG = 0x07064B50; const ZIP64_END_OF_CD_LOCATOR_SIG = 0x07064B50;
/** End Of Central Directory Record signature. */ /** End Of Central Directory Record signature. */
const END_OF_CENTRAL_DIRECTORY_RECORD_SIG = 0x06054B50; const END_OF_CD_SIG = 0x06054B50;
/** /**
* The minimum length of the End Of Central Directory Record. * The minimum length of the End Of Central Directory Record.
@@ -49,7 +49,7 @@ class EndOfCentralDirectory
* end of central directory record 8 * end of central directory record 8
* total number of disks 4. * total number of disks 4.
*/ */
const ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_LEN = 20; const ZIP64_END_OF_CD_LOCATOR_LEN = 20;
/** /**
* The minimum length of the Zip64 End Of Central Directory Record. * The minimum length of the Zip64 End Of Central Directory Record.
@@ -74,35 +74,45 @@ class EndOfCentralDirectory
*/ */
const ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN = 56; const ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN = 56;
/** @var string|null the archive comment */ /** @var int Count files. */
private $comment;
/** @var int */
private $entryCount; private $entryCount;
/** @var bool */ /** @var int Central Directory Offset. */
private $cdOffset;
/** @var int */
private $cdSize;
/** @var string|null The archive comment. */
private $comment;
/** @var bool Zip64 extension */
private $zip64; private $zip64;
/** /**
* EndOfCentralDirectory constructor. * EndOfCentralDirectory constructor.
* *
* @param int $entryCount * @param int $entryCount
* @param string|null $comment * @param int $cdOffset
* @param int $cdSize
* @param bool $zip64 * @param bool $zip64
* @param mixed|null $comment
*/ */
public function __construct($entryCount, $comment, $zip64 = false) public function __construct($entryCount, $cdOffset, $cdSize, $zip64, $comment = null)
{ {
$this->entryCount = $entryCount; $this->entryCount = $entryCount;
$this->comment = $comment; $this->cdOffset = $cdOffset;
$this->cdSize = $cdSize;
$this->zip64 = $zip64; $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 $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 * @return bool
*/ */

View File

@@ -9,6 +9,8 @@ use PhpZip\Model\ZipEntry;
* *
* @author Ne-Lexa alexey@nelexa.ru * @author Ne-Lexa alexey@nelexa.ru
* @license MIT * @license MIT
*
* @internal
*/ */
class OutputOffsetEntry class OutputOffsetEntry
{ {

View File

@@ -10,7 +10,7 @@ use PhpZip\Extra\Fields\WinZipAesEntryExtraField;
use PhpZip\Model\ZipEntry; use PhpZip\Model\ZipEntry;
use PhpZip\Util\DateTimeConverter; use PhpZip\Util\DateTimeConverter;
use PhpZip\Util\StringUtil; use PhpZip\Util\StringUtil;
use PhpZip\ZipFileInterface; use PhpZip\ZipFile;
/** /**
* Abstract ZIP entry. * Abstract ZIP entry.
@@ -26,16 +26,22 @@ abstract class ZipAbstractEntry implements ZipEntry
private $name; private $name;
/** @var int Made by platform */ /** @var int Made by platform */
private $platform = self::UNKNOWN; private $createdOS = self::UNKNOWN;
/** @var int Extracted by platform */
private $extractedOS = self::UNKNOWN;
/** @var int */ /** @var int */
private $versionNeededToExtract = 20; private $softwareVersion = self::UNKNOWN;
/** @var int */
private $versionNeededToExtract = self::UNKNOWN;
/** @var int Compression method */ /** @var int Compression method */
private $method = self::UNKNOWN; private $method = self::UNKNOWN;
/** @var int */ /** @var int */
private $general = 0; private $generalPurposeBitFlags = 0;
/** @var int Dos time */ /** @var int Dos time */
private $dosTime = self::UNKNOWN; private $dosTime = self::UNKNOWN;
@@ -49,11 +55,14 @@ abstract class ZipAbstractEntry implements ZipEntry
/** @var int Uncompressed size */ /** @var int Uncompressed size */
private $size = self::UNKNOWN; private $size = self::UNKNOWN;
/** @var int Internal attributes */
private $internalAttributes = 0;
/** @var int External attributes */ /** @var int External attributes */
private $externalAttributes = 0; private $externalAttributes = 0;
/** @var int relative Offset Of Local File Header */ /** @var int relative Offset Of Local File Header */
private $offset = self::UNKNOWN; private $offset = 0;
/** /**
* Collections of Extra Fields. * Collections of Extra Fields.
@@ -73,17 +82,17 @@ abstract class ZipAbstractEntry implements ZipEntry
/** /**
* Encryption method. * Encryption method.
* *
* @see ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL * @see ZipFile::ENCRYPTION_METHOD_TRADITIONAL
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256
* *
* @var int * @var int
*/ */
private $encryptionMethod = ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL; private $encryptionMethod = ZipFile::ENCRYPTION_METHOD_TRADITIONAL;
/** @var int */ /** @var int */
private $compressionLevel = ZipFileInterface::LEVEL_DEFAULT_COMPRESSION; private $compressionLevel = ZipFile::LEVEL_DEFAULT_COMPRESSION;
/** /**
* ZipAbstractEntry constructor. * ZipAbstractEntry constructor.
@@ -101,7 +110,9 @@ abstract class ZipAbstractEntry implements ZipEntry
public function setEntry(ZipEntry $entry) public function setEntry(ZipEntry $entry)
{ {
$this->setName($entry->getName()); $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->setVersionNeededToExtract($entry->getVersionNeededToExtract());
$this->setMethod($entry->getMethod()); $this->setMethod($entry->getMethod());
$this->setGeneralPurposeBitFlags($entry->getGeneralPurposeBitFlags()); $this->setGeneralPurposeBitFlags($entry->getGeneralPurposeBitFlags());
@@ -109,6 +120,7 @@ abstract class ZipAbstractEntry implements ZipEntry
$this->setCrc($entry->getCrc()); $this->setCrc($entry->getCrc());
$this->setCompressedSize($entry->getCompressedSize()); $this->setCompressedSize($entry->getCompressedSize());
$this->setSize($entry->getSize()); $this->setSize($entry->getSize());
$this->setInternalAttributes($entry->getInternalAttributes());
$this->setExternalAttributes($entry->getExternalAttributes()); $this->setExternalAttributes($entry->getExternalAttributes());
$this->setOffset($entry->getOffset()); $this->setOffset($entry->getOffset());
$this->setExtra($entry->getExtra()); $this->setExtra($entry->getExtra());
@@ -163,20 +175,48 @@ abstract class ZipAbstractEntry implements ZipEntry
public function setGeneralPurposeBitFlag($mask, $bit) public function setGeneralPurposeBitFlag($mask, $bit)
{ {
if ($bit) { if ($bit) {
$this->general |= $mask; $this->generalPurposeBitFlags |= $mask;
} else { } else {
$this->general &= ~$mask; $this->generalPurposeBitFlags &= ~$mask;
} }
return $this; return $this;
} }
/** /**
* @return int platform * @return int Get platform
*
* @deprecated Use {@see ZipEntry::getCreatedOS()}
*/ */
public function getPlatform() 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,17 +228,64 @@ abstract class ZipAbstractEntry implements ZipEntry
* *
* @return ZipEntry * @return ZipEntry
*/ */
public function setPlatform($platform) public function setCreatedOS($platform)
{ {
if ($platform !== self::UNKNOWN) { $platform = (int) $platform;
if ($platform < 0x00 || $platform > 0xff) { if ($platform < 0x00 || $platform > 0xff) {
throw new ZipException('Platform out of range'); throw new ZipException('Platform out of range');
} }
$this->platform = $platform; $this->createdOS = $platform;
} else {
$this->platform = 0; // ms-dos 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; return $this;
} }
@@ -209,6 +296,24 @@ abstract class ZipAbstractEntry implements ZipEntry
*/ */
public function getVersionNeededToExtract() 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; return $this->versionNeededToExtract;
} }
@@ -300,7 +405,7 @@ abstract class ZipAbstractEntry implements ZipEntry
*/ */
public function setOffset($offset) public function setOffset($offset)
{ {
$this->offset = $offset; $this->offset = (int) $offset;
return $this; return $this;
} }
@@ -312,7 +417,7 @@ abstract class ZipAbstractEntry implements ZipEntry
*/ */
public function getGeneralPurposeBitFlags() 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) { if ($general < 0x0000 || $general > 0xffff) {
throw new ZipException('general out of range'); 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); $bit1 = $this->getGeneralPurposeBitFlag(self::GPBF_COMPRESSION_FLAG1);
$bit2 = $this->getGeneralPurposeBitFlag(self::GPBF_COMPRESSION_FLAG2); $bit2 = $this->getGeneralPurposeBitFlag(self::GPBF_COMPRESSION_FLAG2);
if ($bit1 && !$bit2) { if ($bit1 && !$bit2) {
$this->compressionLevel = ZipFileInterface::LEVEL_BEST_COMPRESSION; $this->compressionLevel = ZipFile::LEVEL_BEST_COMPRESSION;
} elseif (!$bit1 && $bit2) { } elseif (!$bit1 && $bit2) {
$this->compressionLevel = ZipFileInterface::LEVEL_FAST; $this->compressionLevel = ZipFile::LEVEL_FAST;
} elseif ($bit1 && $bit2) { } elseif ($bit1 && $bit2) {
$this->compressionLevel = ZipFileInterface::LEVEL_SUPER_FAST; $this->compressionLevel = ZipFile::LEVEL_SUPER_FAST;
} else { } 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) 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) { switch ($method) {
case self::METHOD_WINZIP_AES: case self::METHOD_WINZIP_AES:
case ZipFileInterface::METHOD_STORED: case ZipFile::METHOD_STORED:
case ZipFileInterface::METHOD_DEFLATED: case ZipFile::METHOD_DEFLATED:
case ZipFileInterface::METHOD_BZIP2: case ZipFile::METHOD_BZIP2:
$this->method = $method; $this->method = $method;
break; break;
@@ -490,6 +595,8 @@ abstract class ZipAbstractEntry implements ZipEntry
* @param int $dosTime * @param int $dosTime
* *
* @throws ZipException * @throws ZipException
*
* @return ZipEntry
*/ */
public function setDosTime($dosTime) public function setDosTime($dosTime)
{ {
@@ -499,6 +606,8 @@ abstract class ZipAbstractEntry implements ZipEntry
throw new ZipException('DosTime out of range'); throw new ZipException('DosTime out of range');
} }
$this->dosTime = $dosTime; $this->dosTime = $dosTime;
return $this;
} }
/** /**
@@ -547,6 +656,30 @@ abstract class ZipAbstractEntry implements ZipEntry
return $this; 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 * Returns true if and only if this ZIP entry represents a directory entry
* (i.e. end with '/'). * (i.e. end with '/').
@@ -589,10 +722,14 @@ abstract class ZipAbstractEntry implements ZipEntry
* @param string $data the byte array holding the serialized Extra Fields * @param string $data the byte array holding the serialized Extra Fields
* *
* @throws ZipException if the serialized Extra Fields exceed 64 KB * @throws ZipException if the serialized Extra Fields exceed 64 KB
*
* @return ZipEntry
*/ */
public function setExtra($data) public function setExtra($data)
{ {
$this->extraFieldsCollection = ExtraFieldsFactory::createExtraFieldCollections($data, $this); $this->extraFieldsCollection = ExtraFieldsFactory::createExtraFieldCollections($data, $this);
return $this;
} }
/** /**
@@ -713,19 +850,19 @@ abstract class ZipAbstractEntry implements ZipEntry
* *
* @return ZipEntry * @return ZipEntry
* *
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256
* @see ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL * @see ZipFile::ENCRYPTION_METHOD_TRADITIONAL
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192
*/ */
public function setEncryptionMethod($encryptionMethod) public function setEncryptionMethod($encryptionMethod)
{ {
if ($encryptionMethod !== null) { if ($encryptionMethod !== null) {
if ( if (
$encryptionMethod !== ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL $encryptionMethod !== ZipFile::ENCRYPTION_METHOD_TRADITIONAL
&& $encryptionMethod !== ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 && $encryptionMethod !== ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128
&& $encryptionMethod !== ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 && $encryptionMethod !== ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192
&& $encryptionMethod !== ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 && $encryptionMethod !== ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256
) { ) {
throw new ZipException('Invalid encryption method'); throw new ZipException('Invalid encryption method');
} }
@@ -748,14 +885,14 @@ abstract class ZipAbstractEntry implements ZipEntry
* *
* @return 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 || if ($compressionLevel < ZipFile::LEVEL_DEFAULT_COMPRESSION ||
$compressionLevel > ZipFileInterface::LEVEL_BEST_COMPRESSION $compressionLevel > ZipFile::LEVEL_BEST_COMPRESSION
) { ) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
'Invalid compression level. Minimum level ' . '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; $this->compressionLevel = $compressionLevel;

View File

@@ -10,6 +10,8 @@ use PhpZip\Exception\ZipException;
* *
* @author Ne-Lexa alexey@nelexa.ru * @author Ne-Lexa alexey@nelexa.ru
* @license MIT * @license MIT
*
* @internal
*/ */
class ZipChangesEntry extends ZipAbstractEntry class ZipChangesEntry extends ZipAbstractEntry
{ {

View File

@@ -3,7 +3,6 @@
namespace PhpZip\Model\Entry; namespace PhpZip\Model\Entry;
use PhpZip\Exception\InvalidArgumentException; use PhpZip\Exception\InvalidArgumentException;
use PhpZip\ZipFileInterface;
/** /**
* @author Ne-Lexa alexey@nelexa.ru * @author Ne-Lexa alexey@nelexa.ru
@@ -50,25 +49,6 @@ class ZipNewEntry extends ZipAbstractEntry
return $this->content; 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. * Clone extra fields.
*/ */

View File

@@ -4,7 +4,7 @@ namespace PhpZip\Model;
use PhpZip\Exception\ZipException; use PhpZip\Exception\ZipException;
use PhpZip\Extra\ExtraFieldsCollection; use PhpZip\Extra\ExtraFieldsCollection;
use PhpZip\ZipFileInterface; use PhpZip\ZipFile;
/** /**
* ZIP file entry. * ZIP file entry.
@@ -16,9 +16,6 @@ use PhpZip\ZipFileInterface;
*/ */
interface ZipEntry interface ZipEntry
{ {
// Bit masks for initialized fields.
const BIT_EXTERNAL_ATTR = 128;
/** The unknown value for numeric properties. */ /** The unknown value for numeric properties. */
const UNKNOWN = -1; const UNKNOWN = -1;
@@ -118,11 +115,31 @@ interface ZipEntry
/** /**
* @return int Get platform * @return int Get platform
*
* @deprecated Use {@see ZipEntry::getCreatedOS()}
*/ */
public function getPlatform(); 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 * @param int $platform
* *
@@ -130,7 +147,35 @@ interface ZipEntry
* *
* @return 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. * Version needed to extract.
@@ -323,6 +368,8 @@ interface ZipEntry
* @param int $dosTime * @param int $dosTime
* *
* @throws ZipException * @throws ZipException
*
* @return ZipEntry
*/ */
public function setDosTime($dosTime); public function setDosTime($dosTime);
@@ -333,6 +380,24 @@ interface ZipEntry
*/ */
public function getExternalAttributes(); 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. * Sets the external file attributes.
* *
@@ -368,6 +433,8 @@ interface ZipEntry
* @param string $data the byte array holding the serialized Extra Fields * @param string $data the byte array holding the serialized Extra Fields
* *
* @throws ZipException if the serialized Extra Fields exceed 64 KB * @throws ZipException if the serialized Extra Fields exceed 64 KB
*
* @return ZipEntry
*/ */
public function setExtra($data); public function setExtra($data);
@@ -439,10 +506,10 @@ interface ZipEntry
* *
* @return ZipEntry * @return ZipEntry
* *
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256
* @see ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL * @see ZipFile::ENCRYPTION_METHOD_TRADITIONAL
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128
* @see ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 * @see ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192
*/ */
public function setEncryptionMethod($encryptionMethod); public function setEncryptionMethod($encryptionMethod);
@@ -460,7 +527,7 @@ interface ZipEntry
* *
* @return ZipEntry * @return ZipEntry
*/ */
public function setCompressionLevel($compressionLevel = ZipFileInterface::LEVEL_DEFAULT_COMPRESSION); public function setCompressionLevel($compressionLevel = ZipFile::LEVEL_DEFAULT_COMPRESSION);
/** /**
* @return int * @return int

View File

@@ -6,7 +6,7 @@ use PhpZip\Exception\ZipException;
use PhpZip\Extra\Fields\NtfsExtraField; use PhpZip\Extra\Fields\NtfsExtraField;
use PhpZip\Extra\Fields\WinZipAesEntryExtraField; use PhpZip\Extra\Fields\WinZipAesEntryExtraField;
use PhpZip\Util\FilesUtil; use PhpZip\Util\FilesUtil;
use PhpZip\ZipFileInterface; use PhpZip\ZipFile;
/** /**
* Zip info. * Zip info.
@@ -132,7 +132,7 @@ class ZipInfo
private static $valuesCompressionMethod = [ private static $valuesCompressionMethod = [
ZipEntry::UNKNOWN => 'unknown', ZipEntry::UNKNOWN => 'unknown',
ZipFileInterface::METHOD_STORED => 'no compression', ZipFile::METHOD_STORED => 'no compression',
1 => 'shrink', 1 => 'shrink',
2 => 'reduce level 1', 2 => 'reduce level 1',
3 => 'reduce level 2', 3 => 'reduce level 2',
@@ -140,7 +140,7 @@ class ZipInfo
5 => 'reduce level 4', 5 => 'reduce level 4',
6 => 'implode', 6 => 'implode',
7 => 'reserved for Tokenizing compression algorithm', 7 => 'reserved for Tokenizing compression algorithm',
ZipFileInterface::METHOD_DEFLATED => 'deflate', ZipFile::METHOD_DEFLATED => 'deflate',
9 => 'deflate64', 9 => 'deflate64',
10 => 'PKWARE Data Compression Library Imploding (old IBM TERSE)', 10 => 'PKWARE Data Compression Library Imploding (old IBM TERSE)',
11 => 'reserved by PKWARE', 11 => 'reserved by PKWARE',
@@ -252,10 +252,10 @@ class ZipInfo
$attributes = str_repeat(' ', 12); $attributes = str_repeat(' ', 12);
$externalAttributes = $entry->getExternalAttributes(); $externalAttributes = $entry->getExternalAttributes();
$xattr = (($externalAttributes >> 16) & 0xFFFF); $xattr = (($externalAttributes >> 16) & 0xFFFF);
switch ($entry->getPlatform()) { switch ($entry->getCreatedOS()) {
case self::MADE_BY_MS_DOS: case self::MADE_BY_MS_DOS:
case self::MADE_BY_WINDOWS_NTFS: 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) !== ($xattr & self::UNX_IRWXU) !==
(self::UNX_IRUSR | (self::UNX_IRUSR |
(!($externalAttributes & 1) << 7) | (!($externalAttributes & 1) << 7) |
@@ -420,8 +420,8 @@ class ZipInfo
*/ */
public static function getPlatformName(ZipEntry $entry) public static function getPlatformName(ZipEntry $entry)
{ {
if (isset(self::$valuesMadeBy[$entry->getPlatform()])) { if (isset(self::$valuesMadeBy[$entry->getCreatedOS()])) {
return self::$valuesMadeBy[$entry->getPlatform()]; return self::$valuesMadeBy[$entry->getCreatedOS()];
} }
return 'unknown'; return 'unknown';

View File

@@ -7,7 +7,7 @@ use PhpZip\Exception\ZipEntryNotFoundException;
use PhpZip\Exception\ZipException; use PhpZip\Exception\ZipException;
use PhpZip\Model\Entry\ZipChangesEntry; use PhpZip\Model\Entry\ZipChangesEntry;
use PhpZip\Model\Entry\ZipSourceEntry; use PhpZip\Model\Entry\ZipSourceEntry;
use PhpZip\ZipFileInterface; use PhpZip\ZipFile;
/** /**
* Zip Model. * Zip Model.
@@ -203,8 +203,8 @@ class ZipModel implements \Countable
/** /**
* @param string|ZipEntry $entry * @param string|ZipEntry $entry
* *
* @throws ZipException
* @throws ZipEntryNotFoundException * @throws ZipEntryNotFoundException
* @throws ZipException
* *
* @return ZipChangesEntry|ZipEntry * @return ZipChangesEntry|ZipEntry
*/ */
@@ -352,7 +352,7 @@ class ZipModel implements \Countable
/** /**
* @param int $encryptionMethod * @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); $this->matcher()->all()->setEncryptionMethod($encryptionMethod);
} }

View File

@@ -14,15 +14,13 @@ use PhpZip\Extra\ExtraFieldsCollection;
use PhpZip\Extra\ExtraFieldsFactory; use PhpZip\Extra\ExtraFieldsFactory;
use PhpZip\Extra\Fields\ApkAlignmentExtraField; use PhpZip\Extra\Fields\ApkAlignmentExtraField;
use PhpZip\Extra\Fields\WinZipAesEntryExtraField; use PhpZip\Extra\Fields\WinZipAesEntryExtraField;
use PhpZip\Mapper\OffsetPositionMapper;
use PhpZip\Mapper\PositionMapper;
use PhpZip\Model\EndOfCentralDirectory; use PhpZip\Model\EndOfCentralDirectory;
use PhpZip\Model\Entry\ZipSourceEntry; use PhpZip\Model\Entry\ZipSourceEntry;
use PhpZip\Model\ZipEntry; use PhpZip\Model\ZipEntry;
use PhpZip\Model\ZipModel; use PhpZip\Model\ZipModel;
use PhpZip\Util\PackUtil; use PhpZip\Util\PackUtil;
use PhpZip\Util\StringUtil; use PhpZip\Util\StringUtil;
use PhpZip\ZipFileInterface; use PhpZip\ZipFile;
/** /**
* Read zip file. * Read zip file.
@@ -35,15 +33,6 @@ class ZipInputStream implements ZipInputStreamInterface
/** @var resource */ /** @var resource */
protected $in; 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 */ /** @var ZipModel */
protected $zipModel; protected $zipModel;
@@ -58,7 +47,6 @@ class ZipInputStream implements ZipInputStreamInterface
throw new RuntimeException('$in must be resource'); throw new RuntimeException('$in must be resource');
} }
$this->in = $in; $this->in = $in;
$this->mapper = new PositionMapper();
} }
/** /**
@@ -95,8 +83,8 @@ class ZipInputStream implements ZipInputStreamInterface
if ( if (
$signature !== ZipEntry::LOCAL_FILE_HEADER_SIG $signature !== ZipEntry::LOCAL_FILE_HEADER_SIG
&& $signature !== EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_SIG && $signature !== EndOfCentralDirectory::ZIP64_END_OF_CD_RECORD_SIG
&& $signature !== EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG && $signature !== EndOfCentralDirectory::END_OF_CD_SIG
) { ) {
throw new ZipException( throw new ZipException(
'Expected Local File Header or (ZIP64) End Of Central Directory Record! Signature: ' . $signature 'Expected Local File Header or (ZIP64) End Of Central Directory Record! Signature: ' . $signature
@@ -111,145 +99,179 @@ class ZipInputStream implements ZipInputStreamInterface
*/ */
protected function readEndOfCentralDirectory() protected function readEndOfCentralDirectory()
{ {
$comment = null; if (!$this->findEndOfCentralDirectory()) {
// Search for End of central directory record. throw new ZipException('Invalid zip file. The end of the central directory could not be found.');
$stats = fstat($this->in);
$size = $stats['size'];
$max = $size - EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN;
$min = $max >= 0xffff ? $max - 0xffff : 0;
for ($endOfCentralDirRecordPos = $max; $endOfCentralDirRecordPos >= $min; $endOfCentralDirRecordPos--) {
fseek($this->in, $endOfCentralDirRecordPos, \SEEK_SET);
// end of central dir signature 4 bytes (0x06054b50)
if (unpack('V', fread($this->in, 4))[1] !== EndOfCentralDirectory::END_OF_CENTRAL_DIRECTORY_RECORD_SIG) {
continue;
} }
// number of this disk - 2 bytes $positionECD = ftell($this->in) - 4;
// number of the disk with the start of the $buffer = fread($this->in, fstat($this->in)['size'] - $positionECD);
// central directory - 2 bytes
// total number of entries in the central $unpack = unpack(
// directory on this disk - 2 bytes 'vdiskNo/vcdDiskNo/vcdEntriesDisk/' .
// total number of entries in the central 'vcdEntries/VcdSize/VcdPos/vcommentLength',
// directory - 2 bytes substr($buffer, 0, 18)
// 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']) { if (
$unpack['diskNo'] !== 0 ||
$unpack['cdDiskNo'] !== 0 ||
$unpack['cdEntriesDisk'] !== $unpack['cdEntries']
) {
throw new ZipException( throw new ZipException(
'ZIP file spanning/splitting is not supported!' 'ZIP file spanning/splitting is not supported!'
); );
} }
// .ZIP file comment (variable size) // .ZIP file comment (variable sizeECD)
if ($data['commentLength'] > 0) { $comment = null;
$comment = '';
$offset = 0;
while ($offset < $data['commentLength']) { if ($unpack['commentLength'] > 0) {
$read = min(8192 /* chunk size */, $data['commentLength'] - $offset); $comment = substr($buffer, 18, $unpack['commentLength']);
$comment .= fread($this->in, $read);
$offset += $read;
} }
}
$this->preamble = $endOfCentralDirRecordPos;
$this->postamble = $size - ftell($this->in);
// Check for ZIP64 End Of Central Directory Locator. // Check for ZIP64 End Of Central Directory Locator exists.
$endOfCentralDirLocatorPos = $endOfCentralDirRecordPos - EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_LEN; $zip64ECDLocatorPosition = $positionECD - EndOfCentralDirectory::ZIP64_END_OF_CD_LOCATOR_LEN;
fseek($this->in, $zip64ECDLocatorPosition);
fseek($this->in, $endOfCentralDirLocatorPos, \SEEK_SET);
// zip64 end of central dir locator // zip64 end of central dir locator
// signature 4 bytes (0x07064b50) // signature 4 bytes (0x07064b50)
if ( if ($zip64ECDLocatorPosition > 0 && unpack(
$endOfCentralDirLocatorPos < 0 ||
ftell($this->in) === $size ||
unpack(
'V', 'V',
fread($this->in, 4) fread($this->in, 4)
)[1] !== EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG )[1] === EndOfCentralDirectory::ZIP64_END_OF_CD_LOCATOR_SIG) {
) { $positionECD = $this->findZip64ECDPosition();
// Seek and check first CFH, probably requiring an offset mapper. $endCentralDirectory = $this->readZip64EndOfCentralDirectory($positionECD);
$offset = $endOfCentralDirRecordPos - $data['cdSize']; $endCentralDirectory->setComment($comment);
fseek($this->in, $offset, \SEEK_SET); } else {
$offset -= $data['cdPos']; $endCentralDirectory = new EndOfCentralDirectory(
$unpack['cdEntries'],
if ($offset !== 0) { $unpack['cdPos'],
$this->mapper = new OffsetPositionMapper($offset); $unpack['cdSize'],
} false,
$entryCount = $data['cdEntries']; $comment
);
return new EndOfCentralDirectory($entryCount, $comment);
} }
// number of the disk with the return $endCentralDirectory;
// start of the zip64 end of }
// central directory 4 bytes
$zip64EndOfCentralDirectoryRecordDisk = unpack('V', fread($this->in, 4))[1]; /**
// relative offset of the zip64 * @throws ZipException
// end of central directory record 8 bytes *
$zip64EndOfCentralDirectoryRecordPos = PackUtil::unpackLongLE(fread($this->in, 8)); * @return bool
// total number of disks 4 bytes */
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;
// 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_CD_SIG) {
continue;
}
return true;
}
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]; $totalDisks = unpack('V', fread($this->in, 4))[1];
if ($zip64EndOfCentralDirectoryRecordDisk !== 0 || $totalDisks !== 1) { if ($diskNo !== 0 || $totalDisks > 1) {
throw new ZipException('ZIP file spanning/splitting is not supported!'); 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) { 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!'); 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) { $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!'); throw new ZipException('ZIP file spanning/splitting is not supported!');
} }
if ($cdEntries < 0 || $cdEntries > 0x7fffffff) { if ($entryCount < 0 || $entryCount > 0x7fffffff) {
throw new ZipException('Total Number Of Entries In The Central Directory out of range!'); 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); // skip zip64 extensible data sector (variable sizeEndCD)
}
// Start recovering file entries from min.
$this->preamble = $min;
$this->postamble = $size - $min;
return new EndOfCentralDirectory(0, $comment); return new EndOfCentralDirectory(
$entryCount,
$cdPos,
$cdSize,
true
);
} }
/** /**
@@ -268,122 +290,108 @@ class ZipInputStream implements ZipInputStreamInterface
*/ */
protected function mountCentralDirectory(EndOfCentralDirectory $endOfCentralDirectory) protected function mountCentralDirectory(EndOfCentralDirectory $endOfCentralDirectory)
{ {
$numEntries = $endOfCentralDirectory->getEntryCount();
$entries = []; $entries = [];
for (; $numEntries > 0; $numEntries--) { fseek($this->in, $endOfCentralDirectory->getCdOffset());
$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());
if ($lfhOff < $this->preamble) { if (!($cdStream = fopen('php://temp', 'w+b'))) {
$this->preamble = $lfhOff; 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; $entries[$entry->getName()] = $entry;
} }
fclose($cdStream);
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();
}
return $entries; 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 * @throws ZipException
* *
* @return ZipEntry * @return ZipEntry
*/ */
public function readEntry() public function readCentralDirectoryEntry($stream)
{ {
// central file header signature 4 bytes (0x02014b50) if (unpack('V', fread($stream, 4))[1] !== ZipOutputStreamInterface::CENTRAL_FILE_HEADER_SIG) {
$fileHeaderSig = unpack('V', fread($this->in, 4))[1]; throw new ZipException('Corrupt zip file. Cannot read central dir entry.');
if ($fileHeaderSig !== ZipOutputStreamInterface::CENTRAL_FILE_HEADER_SIG) {
throw new InvalidArgumentException('Corrupt zip file. Can not read zip 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( $data = unpack(
'vversionMadeBy/vversionNeededToExtract/vgpbf/' . 'vversionMadeBy/vversionNeededToExtract/' .
'vrawMethod/VrawTime/VrawCrc/VrawCompressedSize/' . 'vgeneralPurposeBitFlag/vcompressionMethod/' .
'VrawSize/vfileLength/vextraLength/vcommentLength/' . 'VlastModFile/Vcrc/VcompressedSize/' .
'VrawInternalAttributes/VrawExternalAttributes/VlfhOff', 'VuncompressedSize/vfileNameLength/vextraFieldLength/' .
fread($this->in, 42) '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. $extractOS = ($data['versionNeededToExtract'] & 0xFF00) >> 8;
$name = ''; $extractVersion = $data['versionNeededToExtract'] & 0x00FF;
$offset = 0;
while ($offset < $data['fileLength']) { $name = fread($stream, $data['fileNameLength']);
$read = min(8192 /* chunk size */, $data['fileLength'] - $offset);
$name .= fread($this->in, $read); $extra = '';
$offset += $read;
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 = new ZipSourceEntry($this);
$entry->setName($name); $entry->setName($name);
$entry->setVersionNeededToExtract($data['versionNeededToExtract']); $entry->setCreatedOS($createdOS);
$entry->setPlatform($data['versionMadeBy'] >> 8); $entry->setSoftwareVersion($softwareVersion);
$entry->setMethod($data['rawMethod']); $entry->setVersionNeededToExtract($extractVersion);
$entry->setGeneralPurposeBitFlags($data['gpbf']); $entry->setExtractedOS($extractOS);
$entry->setDosTime($data['rawTime']); $entry->setMethod($data['compressionMethod']);
$entry->setCrc($data['rawCrc']); $entry->setGeneralPurposeBitFlags($data['generalPurposeBitFlag']);
$entry->setCompressedSize($data['rawCompressedSize']); $entry->setDosTime($data['lastModFile']);
$entry->setSize($data['rawSize']); $entry->setCrc($data['crc']);
$entry->setExternalAttributes($data['rawExternalAttributes']); $entry->setCompressedSize($data['compressedSize']);
$entry->setOffset($data['lfhOff']); // must be unmapped! $entry->setSize($data['uncompressedSize']);
if ($data['extraLength'] > 0) { $entry->setInternalAttributes($data['internalFileAttributes']);
$extra = ''; $entry->setExternalAttributes($data['externalFileAttributes']);
$offset = 0; $entry->setOffset($data['offsetLocalHeader']);
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->setComment($comment);
} $entry->setExtra($extra);
return $entry; return $entry;
} }
@@ -410,9 +418,8 @@ class ZipInputStream implements ZipInputStreamInterface
throw new ZipException('Can not password from entry ' . $entry->getName()); 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); fseek($this->in, $startPos);
// local file header signature 4 bytes (0x04034b50) // local file header signature 4 bytes (0x04034b50)
@@ -465,7 +472,7 @@ class ZipInputStream implements ZipInputStreamInterface
// Traditional PKWARE Decryption // Traditional PKWARE Decryption
$zipCryptoEngine = new TraditionalPkwareEncryptionEngine($entry); $zipCryptoEngine = new TraditionalPkwareEncryptionEngine($entry);
$content = $zipCryptoEngine->decrypt($content); $content = $zipCryptoEngine->decrypt($content);
$entry->setEncryptionMethod(ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); $entry->setEncryptionMethod(ZipFile::ENCRYPTION_METHOD_TRADITIONAL);
} }
if (!$skipCheckCrc) { if (!$skipCheckCrc) {
@@ -500,15 +507,15 @@ class ZipInputStream implements ZipInputStreamInterface
} }
switch ($method) { switch ($method) {
case ZipFileInterface::METHOD_STORED: case ZipFile::METHOD_STORED:
break; break;
case ZipFileInterface::METHOD_DEFLATED: case ZipFile::METHOD_DEFLATED:
/** @noinspection PhpUsageOfSilenceOperatorInspection */ /** @noinspection PhpUsageOfSilenceOperatorInspection */
$content = @gzinflate($content); $content = @gzinflate($content);
break; break;
case ZipFileInterface::METHOD_BZIP2: case ZipFile::METHOD_BZIP2:
if (!\extension_loaded('bz2')) { if (!\extension_loaded('bz2')) {
throw new ZipException('Extension bzip2 not install'); 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())); throw new ZipException(sprintf('Missing local header offset for entry %s', $entry->getName()));
} }
$pos = $this->mapper->map($pos);
$nameLength = \strlen($entry->getName()); $nameLength = \strlen($entry->getName());
fseek($this->in, $pos + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, \SEEK_SET); fseek($this->in, $pos + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, \SEEK_SET);
@@ -625,7 +630,7 @@ class ZipInputStream implements ZipInputStreamInterface
if ( if (
$this->zipModel->isZipAlign() && $this->zipModel->isZipAlign() &&
!$entry->isEncrypted() && !$entry->isEncrypted() &&
$entry->getMethod() === ZipFileInterface::METHOD_STORED $entry->getMethod() === ZipFile::METHOD_STORED
) { ) {
if (StringUtil::endsWith($entry->getName(), '.so')) { if (StringUtil::endsWith($entry->getName(), '.so')) {
$dataAlignmentMultiple = ApkAlignmentExtraField::ANDROID_COMMON_PAGE_ALIGNMENT_BYTES; $dataAlignmentMultiple = ApkAlignmentExtraField::ANDROID_COMMON_PAGE_ALIGNMENT_BYTES;
@@ -688,7 +693,6 @@ class ZipInputStream implements ZipInputStreamInterface
public function copyEntryData(ZipEntry $entry, ZipOutputStreamInterface $out) public function copyEntryData(ZipEntry $entry, ZipOutputStreamInterface $out)
{ {
$offset = $entry->getOffset(); $offset = $entry->getOffset();
$offset = $this->mapper->map($offset);
$nameLength = \strlen($entry->getName()); $nameLength = \strlen($entry->getName());
fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, \SEEK_SET); fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, \SEEK_SET);

View File

@@ -20,9 +20,15 @@ interface ZipInputStreamInterface
public function readZip(); public function readZip();
/** /**
* Read central directory entry.
*
* @param resource $stream
*
* @throws ZipException
*
* @return ZipEntry * @return ZipEntry
*/ */
public function readEntry(); public function readCentralDirectoryEntry($stream);
/** /**
* @param ZipEntry $entry * @param ZipEntry $entry

View File

@@ -19,7 +19,7 @@ use PhpZip\Model\ZipEntry;
use PhpZip\Model\ZipModel; use PhpZip\Model\ZipModel;
use PhpZip\Util\PackUtil; use PhpZip\Util\PackUtil;
use PhpZip\Util\StringUtil; use PhpZip\Util\StringUtil;
use PhpZip\ZipFileInterface; use PhpZip\ZipFile;
/** /**
* Write zip file. * Write zip file.
@@ -97,7 +97,7 @@ class ZipOutputStream implements ZipOutputStreamInterface
if ( if (
$this->zipModel->isZipAlign() && $this->zipModel->isZipAlign() &&
!$entry->isEncrypted() && !$entry->isEncrypted() &&
$entry->getMethod() === ZipFileInterface::METHOD_STORED $entry->getMethod() === ZipFile::METHOD_STORED
) { ) {
$dataAlignmentMultiple = $this->zipModel->getZipAlign(); $dataAlignmentMultiple = $this->zipModel->getZipAlign();
@@ -144,7 +144,7 @@ class ZipOutputStream implements ZipOutputStreamInterface
// local file header signature 4 bytes (0x04034b50) // local file header signature 4 bytes (0x04034b50)
ZipEntry::LOCAL_FILE_HEADER_SIG, ZipEntry::LOCAL_FILE_HEADER_SIG,
// version needed to extract 2 bytes // version needed to extract 2 bytes
$entry->getVersionNeededToExtract(), ($entry->getExtractedOS() << 8) | $entry->getVersionNeededToExtract(),
// general purpose bit flag 2 bytes // general purpose bit flag 2 bytes
$entry->getGeneralPurposeBitFlags(), $entry->getGeneralPurposeBitFlags(),
// compression method 2 bytes // compression method 2 bytes
@@ -221,8 +221,12 @@ class ZipOutputStream implements ZipOutputStreamInterface
*/ */
protected function entryCommitChangesAndReturnContent(ZipEntry $entry) protected function entryCommitChangesAndReturnContent(ZipEntry $entry)
{ {
if ($entry->getPlatform() === ZipEntry::UNKNOWN) { if ($entry->getCreatedOS() === ZipEntry::UNKNOWN) {
$entry->setPlatform(ZipEntry::PLATFORM_UNIX); $entry->setCreatedOS(ZipEntry::PLATFORM_UNIX);
}
if ($entry->getExtractedOS() === ZipEntry::UNKNOWN) {
$entry->setExtractedOS(ZipEntry::PLATFORM_UNIX);
} }
if ($entry->getTime() === ZipEntry::UNKNOWN) { if ($entry->getTime() === ZipEntry::UNKNOWN) {
@@ -265,16 +269,15 @@ class ZipOutputStream implements ZipOutputStreamInterface
} }
switch ($method) { switch ($method) {
case ZipFileInterface::METHOD_STORED: case ZipFile::METHOD_STORED:
break; break;
case ZipFileInterface::METHOD_DEFLATED: case ZipFile::METHOD_DEFLATED:
$entryContent = gzdeflate($entryContent, $entry->getCompressionLevel()); $entryContent = gzdeflate($entryContent, $entry->getCompressionLevel());
break; break;
case ZipFileInterface::METHOD_BZIP2: case ZipFile::METHOD_BZIP2:
$compressionLevel = $entry->getCompressionLevel( $compressionLevel = $entry->getCompressionLevel() === ZipFile::LEVEL_DEFAULT_COMPRESSION ?
) === ZipFileInterface::LEVEL_DEFAULT_COMPRESSION ?
ZipEntry::LEVEL_DEFAULT_BZIP2_COMPRESSION : ZipEntry::LEVEL_DEFAULT_BZIP2_COMPRESSION :
$entry->getCompressionLevel(); $entry->getCompressionLevel();
/** @noinspection PhpComposerExtensionStubsInspection */ /** @noinspection PhpComposerExtensionStubsInspection */
@@ -294,19 +297,19 @@ class ZipOutputStream implements ZipOutputStreamInterface
throw new ZipException($entry->getName() . ' (unsupported compression method ' . $method . ')'); throw new ZipException($entry->getName() . ' (unsupported compression method ' . $method . ')');
} }
if ($method === ZipFileInterface::METHOD_DEFLATED) { if ($method === ZipFile::METHOD_DEFLATED) {
$bit1 = false; $bit1 = false;
$bit2 = false; $bit2 = false;
switch ($entry->getCompressionLevel()) { switch ($entry->getCompressionLevel()) {
case ZipFileInterface::LEVEL_BEST_COMPRESSION: case ZipFile::LEVEL_BEST_COMPRESSION:
$bit1 = true; $bit1 = true;
break; break;
case ZipFileInterface::LEVEL_FAST: case ZipFile::LEVEL_FAST:
$bit2 = true; $bit2 = true;
break; break;
case ZipFileInterface::LEVEL_SUPER_FAST: case ZipFile::LEVEL_SUPER_FAST:
$bit1 = true; $bit1 = true;
$bit2 = true; $bit2 = true;
break; break;
@@ -320,9 +323,9 @@ class ZipOutputStream implements ZipOutputStreamInterface
if (\in_array( if (\in_array(
$entry->getEncryptionMethod(), $entry->getEncryptionMethod(),
[ [
ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128, ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128,
ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192, ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192,
ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256, ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256,
], ],
true true
)) { )) {
@@ -334,7 +337,7 @@ class ZipOutputStream implements ZipOutputStreamInterface
$field->setMethod($method); $field->setMethod($method);
$size = $entry->getSize(); $size = $entry->getSize();
if ($size >= 20 && $method !== ZipFileInterface::METHOD_BZIP2) { if ($size >= 20 && $method !== ZipFile::METHOD_BZIP2) {
$field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_1); $field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_1);
} else { } else {
$field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_2); $field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_2);
@@ -345,7 +348,7 @@ class ZipOutputStream implements ZipOutputStreamInterface
$winZipAesEngine = new WinZipAesEngine($entry); $winZipAesEngine = new WinZipAesEngine($entry);
$entryContent = $winZipAesEngine->encrypt($entryContent); $entryContent = $winZipAesEngine->encrypt($entryContent);
} elseif ($entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL) { } elseif ($entry->getEncryptionMethod() === ZipFile::ENCRYPTION_METHOD_TRADITIONAL) {
$zipCryptoEngine = new TraditionalPkwareEncryptionEngine($entry); $zipCryptoEngine = new TraditionalPkwareEncryptionEngine($entry);
$entryContent = $zipCryptoEngine->encrypt($entryContent); $entryContent = $zipCryptoEngine->encrypt($entryContent);
} }
@@ -382,11 +385,11 @@ class ZipOutputStream implements ZipOutputStreamInterface
$entryContent = gzdeflate($content, $entry->getCompressionLevel()); $entryContent = gzdeflate($content, $entry->getCompressionLevel());
if (\strlen($entryContent) < \strlen($content)) { if (\strlen($entryContent) < \strlen($content)) {
$entry->setMethod(ZipFileInterface::METHOD_DEFLATED); $entry->setMethod(ZipFile::METHOD_DEFLATED);
return $entryContent; return $entryContent;
} }
$entry->setMethod(ZipFileInterface::METHOD_STORED); $entry->setMethod(ZipFile::METHOD_STORED);
} }
return $content; return $content;
@@ -418,9 +421,9 @@ class ZipOutputStream implements ZipOutputStreamInterface
// central file header signature 4 bytes (0x02014b50) // central file header signature 4 bytes (0x02014b50)
self::CENTRAL_FILE_HEADER_SIG, self::CENTRAL_FILE_HEADER_SIG,
// version made by 2 bytes // version made by 2 bytes
($entry->getPlatform() << 8) | 63, ($entry->getCreatedOS() << 8) | $entry->getSoftwareVersion(),
// version needed to extract 2 bytes // version needed to extract 2 bytes
$entry->getVersionNeededToExtract(), ($entry->getExtractedOS() << 8) | $entry->getVersionNeededToExtract(),
// general purpose bit flag 2 bytes // general purpose bit flag 2 bytes
$entry->getGeneralPurposeBitFlags(), $entry->getGeneralPurposeBitFlags(),
// compression method 2 bytes // compression method 2 bytes
@@ -442,7 +445,7 @@ class ZipOutputStream implements ZipOutputStreamInterface
// disk number start 2 bytes // disk number start 2 bytes
0, 0,
// internal file attributes 2 bytes // internal file attributes 2 bytes
0, $entry->getInternalAttributes(),
// external file attributes 4 bytes // external file attributes 4 bytes
$entry->getExternalAttributes(), $entry->getExternalAttributes(),
// relative offset of local header 4 bytes // relative offset of local header 4 bytes
@@ -468,75 +471,99 @@ class ZipOutputStream implements ZipOutputStreamInterface
*/ */
protected function writeEndOfCentralDirectoryRecord($centralDirectoryOffset) protected function writeEndOfCentralDirectoryRecord($centralDirectoryOffset)
{ {
$centralDirectoryOffset = (int) $centralDirectoryOffset; $cdEntriesCount = \count($this->zipModel);
$centralDirectoryEntriesCount = \count($this->zipModel);
$position = ftell($this->out); $position = ftell($this->out);
$centralDirectorySize = $position - $centralDirectoryOffset; $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) { $cdEntriesZip64 = $cdEntriesCount > 0xFFFF;
// [zip64 end of central directory record] $cdSizeZip64 = $centralDirectorySize > 0xFFFFFFFF;
// relative offset of the zip64 end of central directory record $cdOffsetZip64 = $centralDirectoryOffset > 0xFFFFFFFF;
$zip64EndOfCentralDirectoryOffset = $position;
// zip64 end of central dir $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) // 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 // size of zip64 end of central
// directory record 8 bytes // directory record 8 bytes
fwrite($this->out, PackUtil::packLongLE(44));
fwrite( fwrite(
$this->out, $this->out,
PackUtil::packLongLE(EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_RECORD_MIN_LEN - 12) pack(
); 'vvVV',
// version made by 2 bytes // version made by 2 bytes
$versionMadeBy & 0xFFFF,
// version needed to extract 2 bytes // version needed to extract 2 bytes
// due to potential use of BZIP2 compression $versionExtractedBy & 0xFFFF,
// number of this disk 4 bytes // number of this disk 4 bytes
0,
// number of the disk with the // number of the disk with the
// start of the central directory 4 bytes // start of the central directory 4 bytes
fwrite($this->out, pack('vvVV', 63, 46, 0, 0)); 0
)
);
// total number of entries in the // total number of entries in the
// central directory on this disk 8 bytes // 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 // total number of entries in the
// central directory 8 bytes // central directory 8 bytes
fwrite($this->out, PackUtil::packLongLE($centralDirectoryEntriesCount)); fwrite($this->out, PackUtil::packLongLE($cdEntriesCount));
// size of the central directory 8 bytes // size of the central directory 8 bytes
fwrite($this->out, PackUtil::packLongLE($centralDirectorySize)); fwrite($this->out, PackUtil::packLongLE($centralDirectorySize));
// offset of start of central // offset of start of central
// directory with respect to // directory with respect to
// the starting disk number 8 bytes // the starting disk number 8 bytes
fwrite($this->out, PackUtil::packLongLE($centralDirectoryOffset)); fwrite($this->out, PackUtil::packLongLE($centralDirectoryOffset));
// zip64 extensible data sector (variable size)
// [zip64 end of central directory locator] // write zip64 end of central directory locator
fwrite(
$this->out,
pack(
'VV',
// zip64 end of central dir locator
// signature 4 bytes (0x07064b50) // signature 4 bytes (0x07064b50)
EndOfCentralDirectory::ZIP64_END_OF_CD_LOCATOR_SIG,
// number of the disk with the // number of the disk with the
// start of the zip64 end of // start of the zip64 end of
// central directory 4 bytes // central directory 4 bytes
fwrite($this->out, pack('VV', EndOfCentralDirectory::ZIP64_END_OF_CENTRAL_DIRECTORY_LOCATOR_SIG, 0)); 0
)
);
// relative offset of the zip64 // relative offset of the zip64
// end of central directory record 8 bytes // end of central directory record 8 bytes
fwrite($this->out, PackUtil::packLongLE($zip64EndOfCentralDirectoryOffset)); fwrite($this->out, PackUtil::packLongLE($zip64EndOfCentralDirectoryOffset));
// total number of disks 4 bytes // total number of disks 4 bytes
fwrite($this->out, pack('V', 1)); fwrite($this->out, pack('V', 1));
} }
$comment = $this->zipModel->getArchiveComment(); $comment = $this->zipModel->getArchiveComment();
$commentLength = \strlen($comment); $commentLength = $comment !== null ? \strlen($comment) : 0;
fwrite( fwrite(
$this->out, $this->out,
pack( pack(
'VvvvvVVv', 'VvvvvVVv',
// end of central dir signature 4 bytes (0x06054b50) // 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 // number of this disk 2 bytes
0, 0,
// number of the disk with the // number of the disk with the
@@ -544,16 +571,16 @@ class ZipOutputStream implements ZipOutputStreamInterface
0, 0,
// total number of entries in the // total number of entries in the
// central directory on this disk 2 bytes // central directory on this disk 2 bytes
$centralDirectoryEntries16, $cdEntriesZip64 ? 0xFFFF : $cdEntriesCount,
// total number of entries in // total number of entries in
// the central directory 2 bytes // the central directory 2 bytes
$centralDirectoryEntries16, $cdEntriesZip64 ? 0xFFFF : $cdEntriesCount,
// size of the central directory 4 bytes // size of the central directory 4 bytes
$centralDirectorySize32, $cdSizeZip64 ? 0xFFFFFFFF : $centralDirectorySize,
// offset of start of central // offset of start of central
// directory with respect to // directory with respect to
// the starting disk number 4 bytes // the starting disk number 4 bytes
$centralDirectoryOffset32, $cdOffsetZip64 ? 0xFFFFFFFF : $centralDirectoryOffset,
// .ZIP file comment length 2 bytes // .ZIP file comment length 2 bytes
$commentLength $commentLength
) )

View File

@@ -234,8 +234,8 @@ class ZipFile implements ZipFileInterface
* @param string $entryName * @param string $entryName
* @param string|null $comment * @param string|null $comment
* *
* @throws ZipEntryNotFoundException
* @throws ZipException * @throws ZipException
* @throws ZipEntryNotFoundException
* *
* @return ZipFileInterface * @return ZipFileInterface
*/ */
@@ -277,8 +277,8 @@ class ZipFile implements ZipFileInterface
* *
* @param string|ZipEntry $entryName * @param string|ZipEntry $entryName
* *
* @throws ZipException
* @throws ZipEntryNotFoundException * @throws ZipEntryNotFoundException
* @throws ZipException
* *
* @return ZipInfo * @return ZipInfo
*/ */
@@ -398,9 +398,9 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addFromString($localName, $contents, $compressionMethod = null) public function addFromString($localName, $contents, $compressionMethod = null)
{ {
@@ -454,9 +454,9 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addFile($filename, $localName = null, $compressionMethod = null) public function addFile($filename, $localName = null, $compressionMethod = null)
{ {
@@ -520,9 +520,9 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addFromStream($stream, $localName, $compressionMethod = null) public function addFromStream($stream, $localName, $compressionMethod = null)
{ {
@@ -655,9 +655,9 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addDirRecursive($inputDir, $localPath = '/', $compressionMethod = null) public function addDirRecursive($inputDir, $localPath = '/', $compressionMethod = null)
{ {
@@ -693,9 +693,9 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addFilesFromIterator( public function addFilesFromIterator(
\Iterator $iterator, \Iterator $iterator,
@@ -1091,10 +1091,10 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::LEVEL_DEFAULT_COMPRESSION * @see ZipFile::LEVEL_DEFAULT_COMPRESSION
* @see ZipFileInterface::LEVEL_SUPER_FAST * @see ZipFile::LEVEL_SUPER_FAST
* @see ZipFileInterface::LEVEL_FAST * @see ZipFile::LEVEL_FAST
* @see ZipFileInterface::LEVEL_BEST_COMPRESSION * @see ZipFile::LEVEL_BEST_COMPRESSION
*/ */
public function setCompressionLevel($compressionLevel = self::LEVEL_DEFAULT_COMPRESSION) public function setCompressionLevel($compressionLevel = self::LEVEL_DEFAULT_COMPRESSION)
{ {
@@ -1123,16 +1123,16 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::LEVEL_DEFAULT_COMPRESSION * @see ZipFile::LEVEL_DEFAULT_COMPRESSION
* @see ZipFileInterface::LEVEL_SUPER_FAST * @see ZipFile::LEVEL_SUPER_FAST
* @see ZipFileInterface::LEVEL_FAST * @see ZipFile::LEVEL_FAST
* @see ZipFileInterface::LEVEL_BEST_COMPRESSION * @see ZipFile::LEVEL_BEST_COMPRESSION
*/ */
public function setCompressionLevelEntry($entryName, $compressionLevel) public function setCompressionLevelEntry($entryName, $compressionLevel)
{ {
if ($compressionLevel !== null) { if ($compressionLevel !== null) {
if ($compressionLevel < ZipFileInterface::LEVEL_DEFAULT_COMPRESSION || if ($compressionLevel < self::LEVEL_DEFAULT_COMPRESSION ||
$compressionLevel > ZipFileInterface::LEVEL_BEST_COMPRESSION $compressionLevel > self::LEVEL_BEST_COMPRESSION
) { ) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
'Invalid compression level. Minimum level ' . 'Invalid compression level. Minimum level ' .
@@ -1158,9 +1158,9 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function setCompressionMethodEntry($entryName, $compressionMethod) public function setCompressionMethodEntry($entryName, $compressionMethod)
{ {
@@ -1204,7 +1204,7 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @deprecated using ZipFileInterface::setReadPassword() * @deprecated using ZipFile::setReadPassword()
*/ */
public function withReadPassword($password) public function withReadPassword($password)
{ {
@@ -1254,7 +1254,7 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @deprecated using ZipFileInterface::setPassword() * @deprecated using ZipFile::setPassword()
*/ */
public function withNewPassword($password, $encryptionMethod = self::ENCRYPTION_METHOD_WINZIP_AES_256) public function withNewPassword($password, $encryptionMethod = self::ENCRYPTION_METHOD_WINZIP_AES_256)
{ {
@@ -1311,7 +1311,7 @@ class ZipFile implements ZipFileInterface
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @deprecated using ZipFileInterface::disableEncryption() * @deprecated using ZipFile::disableEncryption()
*/ */
public function withoutPassword() public function withoutPassword()
{ {

View File

@@ -233,9 +233,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addFromString($localName, $contents, $compressionMethod = null); public function addFromString($localName, $contents, $compressionMethod = null);
@@ -250,9 +250,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addFile($filename, $localName = null, $compressionMethod = null); public function addFile($filename, $localName = null, $compressionMethod = null);
@@ -267,9 +267,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addFromStream($stream, $localName, $compressionMethod = null); public function addFromStream($stream, $localName, $compressionMethod = null);
@@ -306,9 +306,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addDirRecursive($inputDir, $localPath = '/', $compressionMethod = null); public function addDirRecursive($inputDir, $localPath = '/', $compressionMethod = null);
@@ -323,9 +323,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function addFilesFromIterator(\Iterator $iterator, $localPath = '/', $compressionMethod = null); public function addFilesFromIterator(\Iterator $iterator, $localPath = '/', $compressionMethod = null);
@@ -456,10 +456,10 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::LEVEL_SUPER_FAST * @see ZipFile::LEVEL_SUPER_FAST
* @see ZipFileInterface::LEVEL_FAST * @see ZipFile::LEVEL_FAST
* @see ZipFileInterface::LEVEL_BEST_COMPRESSION * @see ZipFile::LEVEL_BEST_COMPRESSION
* @see ZipFileInterface::LEVEL_DEFAULT_COMPRESSION * @see ZipFile::LEVEL_DEFAULT_COMPRESSION
*/ */
public function setCompressionLevel($compressionLevel = self::LEVEL_DEFAULT_COMPRESSION); public function setCompressionLevel($compressionLevel = self::LEVEL_DEFAULT_COMPRESSION);
@@ -471,10 +471,10 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::LEVEL_DEFAULT_COMPRESSION * @see ZipFile::LEVEL_DEFAULT_COMPRESSION
* @see ZipFileInterface::LEVEL_SUPER_FAST * @see ZipFile::LEVEL_SUPER_FAST
* @see ZipFileInterface::LEVEL_FAST * @see ZipFile::LEVEL_FAST
* @see ZipFileInterface::LEVEL_BEST_COMPRESSION * @see ZipFile::LEVEL_BEST_COMPRESSION
*/ */
public function setCompressionLevelEntry($entryName, $compressionLevel); public function setCompressionLevelEntry($entryName, $compressionLevel);
@@ -486,9 +486,9 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @see ZipFileInterface::METHOD_STORED * @see ZipFile::METHOD_STORED
* @see ZipFileInterface::METHOD_DEFLATED * @see ZipFile::METHOD_DEFLATED
* @see ZipFileInterface::METHOD_BZIP2 * @see ZipFile::METHOD_BZIP2
*/ */
public function setCompressionMethodEntry($entryName, $compressionMethod); public function setCompressionMethodEntry($entryName, $compressionMethod);
@@ -510,7 +510,7 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @deprecated using ZipFileInterface::setReadPassword() * @deprecated using ZipFile::setReadPassword()
*/ */
public function withReadPassword($password); public function withReadPassword($password);
@@ -541,7 +541,7 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @deprecated using ZipFileInterface::setPassword() * @deprecated using ZipFile::setPassword()
*/ */
public function withNewPassword($password, $encryptionMethod = self::ENCRYPTION_METHOD_WINZIP_AES_256); public function withNewPassword($password, $encryptionMethod = self::ENCRYPTION_METHOD_WINZIP_AES_256);
@@ -571,7 +571,7 @@ interface ZipFileInterface extends \Countable, \ArrayAccess, \Iterator
* *
* @return ZipFileInterface * @return ZipFileInterface
* *
* @deprecated using ZipFileInterface::disableEncryption() * @deprecated using ZipFile::disableEncryption()
*/ */
public function withoutPassword(); public function withoutPassword();

View File

@@ -127,7 +127,10 @@ class PhpZipExtResourceTest extends ZipTestCase
public function testBug70752() public function testBug70752()
{ {
if (\PHP_INT_SIZE === 4) { // php 32 bit 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 } else { // php 64 bit
$this->setExpectedException( $this->setExpectedException(
ZipAuthenticationException::class, ZipAuthenticationException::class,
@@ -163,19 +166,11 @@ class PhpZipExtResourceTest extends ZipTestCase
*/ */
public function testPecl12414() 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 = new ZipFile();
$zipFile->openFile($filename); $zipFile->openFile($filename);
$info = $zipFile->getEntryInfo($entryName);
static::assertTrue($info->getSize() > 0);
$contents = $zipFile[$entryName];
static::assertSame(\strlen($contents), $info->getSize());
$zipFile->close();
} }
} }

View File

@@ -54,7 +54,7 @@ class ZipAlignTest extends ZipTestCase
$zipFile->addFromString( $zipFile->addFromString(
'entry' . $i . '.txt', 'entry' . $i . '.txt',
CryptoUtil::randomBytes(mt_rand(100, 4096)), CryptoUtil::randomBytes(mt_rand(100, 4096)),
ZipFileInterface::METHOD_STORED ZipFile::METHOD_STORED
); );
} }
$zipFile->saveAsFile($this->outputFilename); $zipFile->saveAsFile($this->outputFilename);
@@ -95,7 +95,7 @@ class ZipAlignTest extends ZipTestCase
$zipFile->addFromString( $zipFile->addFromString(
'entry' . $i . '.txt', 'entry' . $i . '.txt',
CryptoUtil::randomBytes(mt_rand(100, 4096)), CryptoUtil::randomBytes(mt_rand(100, 4096)),
ZipFileInterface::METHOD_STORED ZipFile::METHOD_STORED
); );
} }
$zipFile->setZipAlign(4); $zipFile->setZipAlign(4);
@@ -123,7 +123,7 @@ class ZipAlignTest extends ZipTestCase
$zipFile->addFromString( $zipFile->addFromString(
'entry' . $i . '.txt', 'entry' . $i . '.txt',
CryptoUtil::randomBytes(mt_rand(100, 4096)), CryptoUtil::randomBytes(mt_rand(100, 4096)),
ZipFileInterface::METHOD_STORED ZipFile::METHOD_STORED
); );
} }
$zipFile->saveAsFile($this->outputFilename); $zipFile->saveAsFile($this->outputFilename);
@@ -149,8 +149,8 @@ class ZipAlignTest extends ZipTestCase
'entry_new_' . ($isStored ? 'stored' : 'deflated') . '_' . $i . '.txt', 'entry_new_' . ($isStored ? 'stored' : 'deflated') . '_' . $i . '.txt',
CryptoUtil::randomBytes(mt_rand(100, 4096)), CryptoUtil::randomBytes(mt_rand(100, 4096)),
$isStored ? $isStored ?
ZipFileInterface::METHOD_STORED : ZipFile::METHOD_STORED :
ZipFileInterface::METHOD_DEFLATED ZipFile::METHOD_DEFLATED
); );
} }
$zipFile->setZipAlign(4); $zipFile->setZipAlign(4);

View File

@@ -909,12 +909,12 @@ class ZipFileTest extends ZipTestCase
$entries = [ $entries = [
'1' => [ '1' => [
'data' => CryptoUtil::randomBytes(255), 'data' => CryptoUtil::randomBytes(255),
'method' => ZipFileInterface::METHOD_STORED, 'method' => ZipFile::METHOD_STORED,
'expected' => 'No compression', 'expected' => 'No compression',
], ],
'2' => [ '2' => [
'data' => CryptoUtil::randomBytes(255), 'data' => CryptoUtil::randomBytes(255),
'method' => ZipFileInterface::METHOD_DEFLATED, 'method' => ZipFile::METHOD_DEFLATED,
'expected' => 'Deflate', 'expected' => 'Deflate',
], ],
]; ];
@@ -922,7 +922,7 @@ class ZipFileTest extends ZipTestCase
if (\extension_loaded('bz2')) { if (\extension_loaded('bz2')) {
$entries['3'] = [ $entries['3'] = [
'data' => CryptoUtil::randomBytes(255), 'data' => CryptoUtil::randomBytes(255),
'method' => ZipFileInterface::METHOD_BZIP2, 'method' => ZipFile::METHOD_BZIP2,
'expected' => 'Bzip2', 'expected' => 'Bzip2',
]; ];
} }
@@ -938,7 +938,7 @@ class ZipFileTest extends ZipTestCase
static::assertCorrectZipArchive($this->outputFilename); static::assertCorrectZipArchive($this->outputFilename);
$zipFile->openFile($this->outputFilename); $zipFile->openFile($this->outputFilename);
$zipFile->setCompressionLevel(ZipFileInterface::LEVEL_BEST_COMPRESSION); $zipFile->setCompressionLevel(ZipFile::LEVEL_BEST_COMPRESSION);
$zipAllInfo = $zipFile->getAllInfo(); $zipAllInfo = $zipFile->getAllInfo();
foreach ($zipAllInfo as $entryName => $info) { foreach ($zipAllInfo as $entryName => $info) {
@@ -1693,14 +1693,14 @@ class ZipFileTest extends ZipTestCase
$files['file' . $i . '.txt'] = CryptoUtil::randomBytes(255); $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')) { if (\extension_loaded('bz2')) {
$methods[] = ZipFileInterface::METHOD_BZIP2; $methods[] = ZipFile::METHOD_BZIP2;
} }
$zipFile = new ZipFile(); $zipFile = new ZipFile();
$zipFile->setCompressionLevel(ZipFileInterface::LEVEL_BEST_SPEED); $zipFile->setCompressionLevel(ZipFile::LEVEL_BEST_SPEED);
foreach ($files as $entryName => $content) { foreach ($files as $entryName => $content) {
$zipFile->addFromString($entryName, $content, $methods[array_rand($methods)]); $zipFile->addFromString($entryName, $content, $methods[array_rand($methods)]);
@@ -1985,14 +1985,14 @@ class ZipFileTest extends ZipTestCase
{ {
$zipFile = new ZipFile(); $zipFile = new ZipFile();
$zipFile $zipFile
->addFromString('file', 'content', ZipFileInterface::METHOD_DEFLATED) ->addFromString('file', 'content', ZipFile::METHOD_DEFLATED)
->setCompressionLevelEntry('file', ZipFileInterface::LEVEL_BEST_COMPRESSION) ->setCompressionLevelEntry('file', ZipFile::LEVEL_BEST_COMPRESSION)
->addFromString('file2', 'content', ZipFileInterface::METHOD_DEFLATED) ->addFromString('file2', 'content', ZipFile::METHOD_DEFLATED)
->setCompressionLevelEntry('file2', ZipFileInterface::LEVEL_FAST) ->setCompressionLevelEntry('file2', ZipFile::LEVEL_FAST)
->addFromString('file3', 'content', ZipFileInterface::METHOD_DEFLATED) ->addFromString('file3', 'content', ZipFile::METHOD_DEFLATED)
->setCompressionLevelEntry('file3', ZipFileInterface::LEVEL_SUPER_FAST) ->setCompressionLevelEntry('file3', ZipFile::LEVEL_SUPER_FAST)
->addFromString('file4', 'content', ZipFileInterface::METHOD_DEFLATED) ->addFromString('file4', 'content', ZipFile::METHOD_DEFLATED)
->setCompressionLevelEntry('file4', ZipFileInterface::LEVEL_DEFAULT_COMPRESSION) ->setCompressionLevelEntry('file4', ZipFile::LEVEL_DEFAULT_COMPRESSION)
->saveAsFile($this->outputFilename) ->saveAsFile($this->outputFilename)
->close() ->close()
; ;
@@ -2003,22 +2003,22 @@ class ZipFileTest extends ZipTestCase
static::assertSame( static::assertSame(
$zipFile->getEntryInfo('file') $zipFile->getEntryInfo('file')
->getCompressionLevel(), ->getCompressionLevel(),
ZipFileInterface::LEVEL_BEST_COMPRESSION ZipFile::LEVEL_BEST_COMPRESSION
); );
static::assertSame( static::assertSame(
$zipFile->getEntryInfo('file2') $zipFile->getEntryInfo('file2')
->getCompressionLevel(), ->getCompressionLevel(),
ZipFileInterface::LEVEL_FAST ZipFile::LEVEL_FAST
); );
static::assertSame( static::assertSame(
$zipFile->getEntryInfo('file3') $zipFile->getEntryInfo('file3')
->getCompressionLevel(), ->getCompressionLevel(),
ZipFileInterface::LEVEL_SUPER_FAST ZipFile::LEVEL_SUPER_FAST
); );
static::assertSame( static::assertSame(
$zipFile->getEntryInfo('file4') $zipFile->getEntryInfo('file4')
->getCompressionLevel(), ->getCompressionLevel(),
ZipFileInterface::LEVEL_DEFAULT_COMPRESSION ZipFile::LEVEL_DEFAULT_COMPRESSION
); );
$zipFile->close(); $zipFile->close();
} }
@@ -2054,10 +2054,10 @@ class ZipFileTest extends ZipTestCase
{ {
$zipFile = new ZipFile(); $zipFile = new ZipFile();
for ($i = 0; $i < 10; $i++) { for ($i = 0; $i < 10; $i++) {
$zipFile->addFromString('file' . $i, 'content', ZipFileInterface::METHOD_DEFLATED); $zipFile->addFromString('file' . $i, 'content', ZipFile::METHOD_DEFLATED);
} }
$zipFile $zipFile
->setCompressionLevel(ZipFileInterface::LEVEL_BEST_SPEED) ->setCompressionLevel(ZipFile::LEVEL_BEST_SPEED)
->saveAsFile($this->outputFilename) ->saveAsFile($this->outputFilename)
->close() ->close()
; ;
@@ -2069,7 +2069,7 @@ class ZipFileTest extends ZipTestCase
array_walk( array_walk(
$infoList, $infoList,
function (ZipInfo $zipInfo) { function (ZipInfo $zipInfo) {
$this->assertSame($zipInfo->getCompressionLevel(), ZipFileInterface::LEVEL_BEST_SPEED); $this->assertSame($zipInfo->getCompressionLevel(), ZipFile::LEVEL_BEST_SPEED);
} }
); );
$zipFile->close(); $zipFile->close();
@@ -2082,13 +2082,13 @@ class ZipFileTest extends ZipTestCase
public function testCompressionMethodEntry() public function testCompressionMethodEntry()
{ {
$zipFile = new ZipFile(); $zipFile = new ZipFile();
$zipFile->addFromString('file', 'content', ZipFileInterface::METHOD_STORED); $zipFile->addFromString('file', 'content', ZipFile::METHOD_STORED);
$zipFile->saveAsFile($this->outputFilename); $zipFile->saveAsFile($this->outputFilename);
$zipFile->close(); $zipFile->close();
$zipFile->openFile($this->outputFilename); $zipFile->openFile($this->outputFilename);
static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'No compression'); 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'); static::assertSame($zipFile->getEntryInfo('file')->getMethodName(), 'Deflate');
$zipFile->rewrite(); $zipFile->rewrite();
@@ -2103,7 +2103,7 @@ class ZipFileTest extends ZipTestCase
$this->setExpectedException(ZipUnsupportMethodException::class, 'Unsupported method'); $this->setExpectedException(ZipUnsupportMethodException::class, 'Unsupported method');
$zipFile = new ZipFile(); $zipFile = new ZipFile();
$zipFile->addFromString('file', 'content', ZipFileInterface::METHOD_STORED); $zipFile->addFromString('file', 'content', ZipFile::METHOD_STORED);
$zipFile->setCompressionMethodEntry('file', 99); $zipFile->setCompressionMethodEntry('file', 99);
} }

View File

@@ -38,8 +38,16 @@ class ZipMatcherTest extends TestCase
$matcher->match('~^[2][1-5]|[3][6-9]|40$~s'); $matcher->match('~^[2][1-5]|[3][6-9]|40$~s');
static::assertCount(10, $matcher); static::assertCount(10, $matcher);
$actualMatches = [ $actualMatches = [
'21', '22', '23', '24', '25', '21',
'36', '37', '38', '39', '40', '22',
'23',
'24',
'25',
'36',
'37',
'38',
'39',
'40',
]; ];
static::assertSame($matcher->getMatches(), $actualMatches); static::assertSame($matcher->getMatches(), $actualMatches);
$matcher->setPassword('qwerty'); $matcher->setPassword('qwerty');

View File

@@ -22,11 +22,15 @@ class ZipPasswordTest extends ZipFileAddDirTest
* Test archive password. * Test archive password.
* *
* @throws ZipException * @throws ZipException
* @noinspection PhpRedundantCatchClauseInspection
*/ */
public function testSetPassword() public function testSetPassword()
{ {
if (\PHP_INT_SIZE === 4) { // php 32 bit 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)); $password = base64_encode(CryptoUtil::randomBytes(100));
@@ -35,7 +39,7 @@ class ZipPasswordTest extends ZipFileAddDirTest
// create encryption password with ZipCrypto // create encryption password with ZipCrypto
$zipFile = new ZipFile(); $zipFile = new ZipFile();
$zipFile->addDir(__DIR__); $zipFile->addDir(__DIR__);
$zipFile->setPassword($password, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); $zipFile->setPassword($password, ZipFile::ENCRYPTION_METHOD_TRADITIONAL);
$zipFile->saveAsFile($this->outputFilename); $zipFile->saveAsFile($this->outputFilename);
$zipFile->close(); $zipFile->close();
@@ -66,7 +70,7 @@ class ZipPasswordTest extends ZipFileAddDirTest
} }
// change encryption method to WinZip Aes and update file // 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->saveAsFile($this->outputFilename);
$zipFile->close(); $zipFile->close();
@@ -121,14 +125,17 @@ class ZipPasswordTest extends ZipFileAddDirTest
public function testTraditionalEncryption() public function testTraditionalEncryption()
{ {
if (\PHP_INT_SIZE === 4) { // php 32 bit 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)); $password = base64_encode(CryptoUtil::randomBytes(50));
$zip = new ZipFile(); $zip = new ZipFile();
$zip->addDirRecursive($this->outputDirname); $zip->addDirRecursive($this->outputDirname);
$zip->setPassword($password, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); $zip->setPassword($password, ZipFile::ENCRYPTION_METHOD_TRADITIONAL);
$zip->saveAsFile($this->outputFilename); $zip->saveAsFile($this->outputFilename);
$zip->close(); $zip->close();
@@ -187,10 +194,10 @@ class ZipPasswordTest extends ZipFileAddDirTest
public function winZipKeyStrengthProvider() public function winZipKeyStrengthProvider()
{ {
return [ return [
[ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128, 128], [ZipFile::ENCRYPTION_METHOD_WINZIP_AES_128, 128],
[ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192, 192], [ZipFile::ENCRYPTION_METHOD_WINZIP_AES_192, 192],
[ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES, 256], [ZipFile::ENCRYPTION_METHOD_WINZIP_AES, 256],
[ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256, 256], [ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256, 256],
]; ];
} }
@@ -201,7 +208,10 @@ class ZipPasswordTest extends ZipFileAddDirTest
public function testEncryptionEntries() public function testEncryptionEntries()
{ {
if (\PHP_INT_SIZE === 4) { // php 32 bit 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'; $password1 = '353442434235424234';
@@ -209,8 +219,8 @@ class ZipPasswordTest extends ZipFileAddDirTest
$zip = new ZipFile(); $zip = new ZipFile();
$zip->addDir($this->outputDirname); $zip->addDir($this->outputDirname);
$zip->setPasswordEntry('.hidden', $password1, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); $zip->setPasswordEntry('.hidden', $password1, ZipFile::ENCRYPTION_METHOD_TRADITIONAL);
$zip->setPasswordEntry('text file.txt', $password2, ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES); $zip->setPasswordEntry('text file.txt', $password2, ZipFile::ENCRYPTION_METHOD_WINZIP_AES);
$zip->saveAsFile($this->outputFilename); $zip->saveAsFile($this->outputFilename);
$zip->close(); $zip->close();
@@ -248,7 +258,10 @@ class ZipPasswordTest extends ZipFileAddDirTest
public function testEncryptionEntriesWithDefaultPassword() public function testEncryptionEntriesWithDefaultPassword()
{ {
if (\PHP_INT_SIZE === 4) { // php 32 bit 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'; $password1 = '353442434235424234';
@@ -258,8 +271,8 @@ class ZipPasswordTest extends ZipFileAddDirTest
$zip = new ZipFile(); $zip = new ZipFile();
$zip->addDir($this->outputDirname); $zip->addDir($this->outputDirname);
$zip->setPassword($defaultPassword); $zip->setPassword($defaultPassword);
$zip->setPasswordEntry('.hidden', $password1, ZipFileInterface::ENCRYPTION_METHOD_TRADITIONAL); $zip->setPasswordEntry('.hidden', $password1, ZipFile::ENCRYPTION_METHOD_TRADITIONAL);
$zip->setPasswordEntry('text file.txt', $password2, ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES); $zip->setPasswordEntry('text file.txt', $password2, ZipFile::ENCRYPTION_METHOD_WINZIP_AES);
$zip->saveAsFile($this->outputFilename); $zip->saveAsFile($this->outputFilename);
$zip->close(); $zip->close();
@@ -350,7 +363,7 @@ class ZipPasswordTest extends ZipFileAddDirTest
$this->setExpectedException(ZipException::class, 'Invalid encryption method'); $this->setExpectedException(ZipException::class, 'Invalid encryption method');
$zipFile = new ZipFile(); $zipFile = new ZipFile();
$zipFile->addFromString('file', 'content', ZipFileInterface::METHOD_STORED); $zipFile->addFromString('file', 'content', ZipFile::METHOD_STORED);
$zipFile->setPasswordEntry('file', 'pass', 99); $zipFile->setPasswordEntry('file', 'pass', 99);
} }

View File

@@ -129,7 +129,7 @@ abstract class ZipTestCase extends TestCase
static::assertContains('Empty zipfile', $output); 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); static::assertStringEqualsFile($filename, $actualEmptyZipData);
} }