1
0
mirror of https://github.com/Ne-Lexa/php-zip.git synced 2025-07-25 01:31:20 +02:00

Merge branch 'hotfix/3.1.3'

This commit is contained in:
Ne-Lexa
2017-12-06 15:43:25 +03:00
7 changed files with 83 additions and 71 deletions

View File

@@ -255,11 +255,8 @@ abstract class ZipAbstractEntry implements ZipEntry
*/ */
public function isZip64ExtensionsRequired() public function isZip64ExtensionsRequired()
{ {
// Offset MUST be considered in decision about ZIP64 format - see
// description of Data Descriptor in ZIP File Format Specification!
return 0xffffffff <= $this->getCompressedSize() return 0xffffffff <= $this->getCompressedSize()
|| 0xffffffff <= $this->getSize() || 0xffffffff <= $this->getSize();
|| 0xffffffff <= sprintf('%u', $this->getOffset());
} }
/** /**
@@ -432,7 +429,10 @@ abstract class ZipAbstractEntry implements ZipEntry
*/ */
public function getMethod() public function getMethod()
{ {
return $this->isInit(self::BIT_METHOD) ? $this->method & 0xffff : self::UNKNOWN; $isInit = $this->isInit(self::BIT_METHOD);
return $isInit ?
$this->method & 0xffff :
self::UNKNOWN;
} }
/** /**
@@ -446,17 +446,14 @@ abstract class ZipAbstractEntry implements ZipEntry
{ {
if (self::UNKNOWN === $method) { if (self::UNKNOWN === $method) {
$this->method = $method; $this->method = $method;
$this->setInit(self::BIT_METHOD, false);
return $this; return $this;
} }
if (0x0000 > $method || $method > 0xffff) { if (0x0000 > $method || $method > 0xffff) {
throw new ZipException('method out of range'); throw new ZipException('method out of range: ' . $method);
} }
switch ($method) { switch ($method) {
case self::METHOD_WINZIP_AES: case self::METHOD_WINZIP_AES:
$this->method = $method;
$this->setInit(self::BIT_METHOD, true);
break;
case ZipFileInterface::METHOD_STORED: case ZipFileInterface::METHOD_STORED:
case ZipFileInterface::METHOD_DEFLATED: case ZipFileInterface::METHOD_DEFLATED:
case ZipFileInterface::METHOD_BZIP2: case ZipFileInterface::METHOD_BZIP2:

View File

@@ -18,7 +18,7 @@ interface ZipEntry
// Bit masks for initialized fields. // Bit masks for initialized fields.
const BIT_PLATFORM = 1, const BIT_PLATFORM = 1,
BIT_METHOD = 2 /* 1 << 1 */, BIT_METHOD = 2 /* 1 << 1 */,
BIT_CRC = 2 /* 1 << 2 */, BIT_CRC = 4 /* 1 << 2 */,
BIT_DATE_TIME = 64 /* 1 << 6 */, BIT_DATE_TIME = 64 /* 1 << 6 */,
BIT_EXTERNAL_ATTR = 128 /* 1 << 7*/ BIT_EXTERNAL_ATTR = 128 /* 1 << 7*/
; ;

View File

@@ -224,7 +224,7 @@ class ZipModel implements \Countable
if (isset($this->outEntries[$entryName])) { if (isset($this->outEntries[$entryName])) {
return $this->outEntries[$entryName]; return $this->outEntries[$entryName];
} }
throw new ZipNotFoundEntry('Zip entry ' . $entryName . ' not found'); throw new ZipNotFoundEntry('Zip entry "' . $entryName . '" not found');
} }
/** /**

View File

@@ -223,7 +223,6 @@ class ZipOutputStream implements ZipOutputStreamInterface
| ($entry->isDataDescriptorRequired() ? ZipEntry::GPBF_DATA_DESCRIPTOR : 0) | ($entry->isDataDescriptorRequired() ? ZipEntry::GPBF_DATA_DESCRIPTOR : 0)
| ($utf8 ? ZipEntry::GPBF_UTF8 : 0); | ($utf8 ? ZipEntry::GPBF_UTF8 : 0);
$skipCrc = false;
$entryContent = null; $entryContent = null;
$extraFieldsCollection = $entry->getExtraFieldsCollection(); $extraFieldsCollection = $entry->getExtraFieldsCollection();
if (!($entry instanceof ZipChangesEntry && !$entry->isChangedContent())) { if (!($entry instanceof ZipChangesEntry && !$entry->isChangedContent())) {
@@ -233,57 +232,13 @@ class ZipOutputStream implements ZipOutputStreamInterface
$entry->setSize(strlen($entryContent)); $entry->setSize(strlen($entryContent));
$entry->setCrc(crc32($entryContent)); $entry->setCrc(crc32($entryContent));
if ( if ($encrypted && ZipEntry::METHOD_WINZIP_AES === $method) {
$encrypted && /**
( * @var WinZipAesEntryExtraField $field
ZipEntry::METHOD_WINZIP_AES === $method || */
$entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 || $field = $extraFieldsCollection->get(WinZipAesEntryExtraField::getHeaderId());
$entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 || if (null !== $field) {
$entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 $method = $field->getMethod();
)
) {
$field = null;
$method = $entry->getMethod();
$keyStrength = WinZipAesEntryExtraField::getKeyStrangeFromEncryptionMethod($entry->getEncryptionMethod()); // size bits
$compressedSize = $entry->getCompressedSize();
if (ZipEntry::METHOD_WINZIP_AES === $method) {
/**
* @var WinZipAesEntryExtraField $field
*/
$field = $extraFieldsCollection->get(WinZipAesEntryExtraField::getHeaderId());
if (null !== $field) {
$method = $field->getMethod();
if (ZipEntry::UNKNOWN !== $compressedSize) {
$compressedSize -= $field->getKeyStrength() / 2 // salt value
+ 2 // password verification value
+ 10; // authentication code
}
$entry->setMethod($method);
}
}
if (null === $field) {
$field = ExtraFieldsFactory::createWinZipAesEntryExtra();
}
$field->setKeyStrength($keyStrength);
$field->setMethod($method);
$size = $entry->getSize();
if (20 <= $size && ZipFileInterface::METHOD_BZIP2 !== $method) {
$field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_1);
} else {
$field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_2);
$skipCrc = true;
}
$extraFieldsCollection->add($field);
if (ZipEntry::UNKNOWN !== $compressedSize) {
$compressedSize += $field->getKeyStrength() / 2 // salt value
+ 2 // password verification value
+ 10; // authentication code
$entry->setCompressedSize($compressedSize);
}
if ($skipCrc) {
$entry->setCrc(0);
} }
} }
@@ -337,14 +292,23 @@ class ZipOutputStream implements ZipOutputStreamInterface
} }
if ($encrypted) { if ($encrypted) {
if ( if (in_array($entry->getEncryptionMethod(), [
$entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 || ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128,
$entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 || ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192,
$entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256 ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256,
) { ], true)) {
if ($skipCrc) { $keyStrength = WinZipAesEntryExtraField::getKeyStrangeFromEncryptionMethod($entry->getEncryptionMethod()); // size bits
$field = ExtraFieldsFactory::createWinZipAesEntryExtra();
$field->setKeyStrength($keyStrength);
$field->setMethod($method);
$size = $entry->getSize();
if (20 <= $size && ZipFileInterface::METHOD_BZIP2 !== $method) {
$field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_1);
} else {
$field->setVendorVersion(WinZipAesEntryExtraField::VV_AE_2);
$entry->setCrc(0); $entry->setCrc(0);
} }
$extraFieldsCollection->add($field);
$entry->setMethod(ZipEntry::METHOD_WINZIP_AES); $entry->setMethod(ZipEntry::METHOD_WINZIP_AES);
$winZipAesEngine = new WinZipAesEngine($entry); $winZipAesEngine = new WinZipAesEngine($entry);
@@ -375,6 +339,7 @@ class ZipOutputStream implements ZipOutputStreamInterface
* @param ZipEntry $entry * @param ZipEntry $entry
* @param string $content * @param string $content
* @return string * @return string
* @throws ZipException
*/ */
protected function determineBestCompressionMethod(ZipEntry $entry, $content) protected function determineBestCompressionMethod(ZipEntry $entry, $content)
{ {

View File

@@ -1672,7 +1672,7 @@ class ZipFileTest extends ZipTestCase
/** /**
* @expectedException \PhpZip\Exception\ZipNotFoundEntry * @expectedException \PhpZip\Exception\ZipNotFoundEntry
* @expectedExceptionMessage Zip entry bad entry name not found * @expectedExceptionMessage Zip entry "bad entry name" not found
*/ */
public function testNotFoundEntry() public function testNotFoundEntry()
{ {

View File

@@ -346,4 +346,54 @@ class ZipPasswordTest extends ZipFileAddDirTest
$zipFile->close(); $zipFile->close();
} }
/**
* @see https://github.com/Ne-Lexa/php-zip/issues/9
*/
public function testIssues9()
{
$contents = str_pad('', 1000, 'test;test2;test3' . PHP_EOL, STR_PAD_RIGHT);
$password = base64_encode(CryptoUtil::randomBytes(20));
$encryptMethod = ZipFile::ENCRYPTION_METHOD_WINZIP_AES_256;
$zipFile = new ZipFile();
$zipFile
->addFromString('codes.csv', $contents)
->setPassword($password, $encryptMethod)
->saveAsFile($this->outputFilename)
->close();
$this->assertCorrectZipArchive($this->outputFilename, $password);
$zipFile->openFile($this->outputFilename);
$zipFile->setReadPassword($password);
$this->assertEquals($zipFile['codes.csv'], $contents);
$zipFile->close();
}
public function testReadAesEncryptedAndRewriteArchive()
{
$file = __DIR__ . '/resources/aes_password_archive.zip';
$password = '1234567890';
$zipFile = new ZipFile();
$zipFile->openFile($file);
$zipFile->setReadPassword($password);
$zipFile->setEntryComment('contents.txt', 'comment'); // change entry, but not changed contents
$zipFile->saveAsFile($this->outputFilename);
$zipFile2 = new ZipFile();
$zipFile2->openFile($this->outputFilename);
$zipFile2->setReadPassword($password);
$this->assertEquals($zipFile2->getListFiles(), $zipFile->getListFiles());
foreach ($zipFile as $name => $contents) {
$this->assertNotEmpty($name);
$this->assertNotEmpty($contents);
$this->assertContains('test contents', $contents);
$this->assertEquals($zipFile2[$name], $contents);
}
$zipFile2->close();
$zipFile->close();
}
} }

Binary file not shown.