浏览代码

Merge tag '3.1.3' into develop

Tagging version 3.1.3 3.1.3
Ne-Lexa 8 年之前
父节点
当前提交
e58cf0f337

+ 7 - 10
src/PhpZip/Model/Entry/ZipAbstractEntry.php

@@ -255,11 +255,8 @@ abstract class ZipAbstractEntry implements ZipEntry
      */
     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()
-            || 0xffffffff <= $this->getSize()
-            || 0xffffffff <= sprintf('%u', $this->getOffset());
+            || 0xffffffff <= $this->getSize();
     }
 
     /**
@@ -432,7 +429,10 @@ abstract class ZipAbstractEntry implements ZipEntry
      */
     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) {
             $this->method = $method;
+            $this->setInit(self::BIT_METHOD, false);
             return $this;
         }
         if (0x0000 > $method || $method > 0xffff) {
-            throw new ZipException('method out of range');
+            throw new ZipException('method out of range: ' . $method);
         }
         switch ($method) {
             case self::METHOD_WINZIP_AES:
-                $this->method = $method;
-                $this->setInit(self::BIT_METHOD, true);
-                break;
-
             case ZipFileInterface::METHOD_STORED:
             case ZipFileInterface::METHOD_DEFLATED:
             case ZipFileInterface::METHOD_BZIP2:

+ 1 - 1
src/PhpZip/Model/ZipEntry.php

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

+ 1 - 1
src/PhpZip/Model/ZipModel.php

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

+ 23 - 58
src/PhpZip/Stream/ZipOutputStream.php

@@ -223,7 +223,6 @@ class ZipOutputStream implements ZipOutputStreamInterface
             | ($entry->isDataDescriptorRequired() ? ZipEntry::GPBF_DATA_DESCRIPTOR : 0)
             | ($utf8 ? ZipEntry::GPBF_UTF8 : 0);
 
-        $skipCrc = false;
         $entryContent = null;
         $extraFieldsCollection = $entry->getExtraFieldsCollection();
         if (!($entry instanceof ZipChangesEntry && !$entry->isChangedContent())) {
@@ -233,57 +232,13 @@ class ZipOutputStream implements ZipOutputStreamInterface
                 $entry->setSize(strlen($entryContent));
                 $entry->setCrc(crc32($entryContent));
 
-                if (
-                    $encrypted &&
-                    (
-                        ZipEntry::METHOD_WINZIP_AES === $method ||
-                        $entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 ||
-                        $entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 ||
-                        $entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256
-                    )
-                ) {
-                    $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);
+                if ($encrypted && ZipEntry::METHOD_WINZIP_AES === $method) {
+                    /**
+                     * @var WinZipAesEntryExtraField $field
+                     */
+                    $field = $extraFieldsCollection->get(WinZipAesEntryExtraField::getHeaderId());
+                    if (null !== $field) {
+                        $method = $field->getMethod();
                     }
                 }
 
@@ -337,14 +292,23 @@ class ZipOutputStream implements ZipOutputStreamInterface
                 }
 
                 if ($encrypted) {
-                    if (
-                        $entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128 ||
-                        $entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192 ||
-                        $entry->getEncryptionMethod() === ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256
-                    ) {
-                        if ($skipCrc) {
+                    if (in_array($entry->getEncryptionMethod(), [
+                        ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_128,
+                        ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_192,
+                        ZipFileInterface::ENCRYPTION_METHOD_WINZIP_AES_256,
+                    ], true)) {
+                        $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);
                         }
+                        $extraFieldsCollection->add($field);
                         $entry->setMethod(ZipEntry::METHOD_WINZIP_AES);
 
                         $winZipAesEngine = new WinZipAesEngine($entry);
@@ -375,6 +339,7 @@ class ZipOutputStream implements ZipOutputStreamInterface
      * @param ZipEntry $entry
      * @param string $content
      * @return string
+     * @throws ZipException
      */
     protected function determineBestCompressionMethod(ZipEntry $entry, $content)
     {

+ 1 - 1
tests/PhpZip/ZipFileTest.php

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

+ 50 - 0
tests/PhpZip/ZipPasswordTest.php

@@ -346,4 +346,54 @@ class ZipPasswordTest extends ZipFileAddDirTest
 
         $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();
+    }
 }

二进制
tests/PhpZip/resources/aes_password_archive.zip