Browse Source

fix bug issues #9

Ne-Lexa 8 years ago
parent
commit
c34f90ac18

+ 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*/
     ;

+ 24 - 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,14 @@ 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();
+                        $entry->setMethod($method);
                     }
                 }
 
@@ -337,14 +293,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 +340,7 @@ class ZipOutputStream implements ZipOutputStreamInterface
      * @param ZipEntry $entry
      * @param string $content
      * @return string
+     * @throws ZipException
      */
     protected function determineBestCompressionMethod(ZipEntry $entry, $content)
     {

+ 24 - 0
tests/PhpZip/ZipPasswordTest.php

@@ -346,4 +346,28 @@ 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();
+    }
 }