diff --git a/src/PhpZip/Stream/ZipInputStream.php b/src/PhpZip/Stream/ZipInputStream.php index df5bd35..2960805 100644 --- a/src/PhpZip/Stream/ZipInputStream.php +++ b/src/PhpZip/Stream/ZipInputStream.php @@ -481,9 +481,11 @@ class ZipInputStream implements ZipInputStreamInterface $pos = PHP_INT_SIZE === 4 ? sprintf('%u', $pos) : $pos; $pos = $this->mapper->map($pos); - $extraLength = strlen($entry->getExtra()); $nameLength = strlen($entry->getName()); + fseek($this->in, $pos + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, SEEK_SET); + $extraLength = unpack('v', fread($this->in, 2))[1]; + $length = ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $extraLength + $nameLength; $padding = 0; @@ -505,7 +507,7 @@ class ZipInputStream implements ZipInputStreamInterface } else { stream_copy_to_stream($this->in, $out->getStream(), $length); } - $this->copyEntryData($entry, $out); + stream_copy_to_stream($this->in, $out->getStream(), $entry->getCompressedSize()); if ($entry->getGeneralPurposeBitFlag(ZipEntry::GPBF_DATA_DESCRIPTOR)) { $length = 12; if ($entry->isZip64ExtensionsRequired()) { @@ -524,11 +526,13 @@ class ZipInputStream implements ZipInputStreamInterface $offset = $entry->getOffset(); $offset = PHP_INT_SIZE === 4 ? sprintf('%u', $offset) : $offset; $offset = $this->mapper->map($offset); - $position = $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + - strlen($entry->getName()) + strlen($entry->getExtra()); - $length = $entry->getCompressedSize(); - fseek($this->in, $position, SEEK_SET); - stream_copy_to_stream($this->in, $out->getStream(), $length); + $nameLength = strlen($entry->getName()); + + fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, SEEK_SET); + $extraLength = unpack('v', fread($this->in, 2))[1]; + + fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $nameLength + $extraLength, SEEK_SET); + stream_copy_to_stream($this->in, $out->getStream(), $entry->getCompressedSize()); } public function __destruct() diff --git a/tests/PhpZip/ZipAlignTest.php b/tests/PhpZip/ZipAlignTest.php new file mode 100644 index 0000000..ebd3ddb --- /dev/null +++ b/tests/PhpZip/ZipAlignTest.php @@ -0,0 +1,157 @@ +outputFilename); + + $zipFile = new ZipFile(); + $zipFile->openFile($filename); + $zipFile->saveAsFile($this->outputFilename); + $zipFile->close(); + + self::assertCorrectZipArchive($this->outputFilename); + self::doZipAlignVerify($this->outputFilename); + } + + public function testApkAlignedAndSetZipAlignAndReSave() + { + $filename = __DIR__ . '/resources/test.apk'; + + self::assertCorrectZipArchive($filename); + self::doZipAlignVerify($this->outputFilename); + + $zipFile = new ZipFile(); + $zipFile->openFile($filename); + $zipFile->setZipAlign(4); + $zipFile->saveAsFile($this->outputFilename); + $zipFile->close(); + + self::assertCorrectZipArchive($this->outputFilename); + self::doZipAlignVerify($this->outputFilename); + } + + /** + * Test zip alignment. + */ + public function testZipAlignSourceZip() + { + $zipFile = new ZipFile(); + for ($i = 0; $i < 100; $i++) { + $zipFile->addFromString( + 'entry' . $i . '.txt', + CryptoUtil::randomBytes(mt_rand(100, 4096)), + ZipFileInterface::METHOD_STORED + ); + } + $zipFile->saveAsFile($this->outputFilename); + $zipFile->close(); + + self::assertCorrectZipArchive($this->outputFilename); + + $result = self::doZipAlignVerify($this->outputFilename); + if ($result === null) { + return; + } // zip align not installed + + // check not zip align + self::assertFalse($result); + + $zipFile->openFile($this->outputFilename); + $zipFile->setZipAlign(4); + $zipFile->saveAsFile($this->outputFilename); + $zipFile->close(); + + self::assertCorrectZipArchive($this->outputFilename); + + $result = self::doZipAlignVerify($this->outputFilename, true); + self::assertNotNull($result); + + // check zip align + self::assertTrue($result); + } + + public function testZipAlignNewFiles() + { + $zipFile = new ZipFile(); + for ($i = 0; $i < 100; $i++) { + $zipFile->addFromString( + 'entry' . $i . '.txt', + CryptoUtil::randomBytes(mt_rand(100, 4096)), + ZipFileInterface::METHOD_STORED + ); + } + $zipFile->setZipAlign(4); + $zipFile->saveAsFile($this->outputFilename); + $zipFile->close(); + + self::assertCorrectZipArchive($this->outputFilename); + + $result = self::doZipAlignVerify($this->outputFilename); + if ($result === null) { + return; + } // zip align not installed + // check not zip align + self::assertTrue($result); + } + + public function testZipAlignFromModifiedZipArchive() + { + $zipFile = new ZipFile(); + for ($i = 0; $i < 100; $i++) { + $zipFile->addFromString( + 'entry' . $i . '.txt', + CryptoUtil::randomBytes(mt_rand(100, 4096)), + ZipFileInterface::METHOD_STORED + ); + } + $zipFile->saveAsFile($this->outputFilename); + $zipFile->close(); + + self::assertCorrectZipArchive($this->outputFilename); + + $result = self::doZipAlignVerify($this->outputFilename); + if ($result === null) { + return; + } // zip align not installed + + // check not zip align + self::assertFalse($result); + + $zipFile->openFile($this->outputFilename); + $zipFile->deleteFromRegex("~entry2[\d]+\.txt$~s"); + for ($i = 0; $i < 100; $i++) { + $isStored = (bool)mt_rand(0, 1); + + $zipFile->addFromString( + 'entry_new_' . ($isStored ? 'stored' : 'deflated') . '_' . $i . '.txt', + CryptoUtil::randomBytes(mt_rand(100, 4096)), + $isStored ? + ZipFileInterface::METHOD_STORED : + ZipFileInterface::METHOD_DEFLATED + ); + } + $zipFile->setZipAlign(4); + $zipFile->saveAsFile($this->outputFilename); + $zipFile->close(); + + self::assertCorrectZipArchive($this->outputFilename); + + $result = self::doZipAlignVerify($this->outputFilename, true); + self::assertNotNull($result); + + // check zip align + self::assertTrue($result); + } +} diff --git a/tests/PhpZip/ZipFileTest.php b/tests/PhpZip/ZipFileTest.php index e23d82e..774288d 100644 --- a/tests/PhpZip/ZipFileTest.php +++ b/tests/PhpZip/ZipFileTest.php @@ -404,7 +404,11 @@ class ZipFileTest extends ZipTestCase $zipFile->openFile($this->outputFilename); $zipFile->rename($oldName, $newName); $zipFile->addFromString('file1.txt', 'content'); - $zipFile->rename('file1.txt', 'file2.txt'); + $zipFile->addFromString('file2.txt', 'content'); + $zipFile->addFromString('file3.txt', 'content'); + $zipFile->rename('file1.txt', 'file_long_name.txt'); + $zipFile->rename('file2.txt', 'file4.txt'); + $zipFile->rename('file3.txt', 'fi.txt'); $zipFile->saveAsFile($this->outputFilename); $zipFile->close(); @@ -414,7 +418,11 @@ class ZipFileTest extends ZipTestCase self::assertFalse(isset($zipFile[$oldName])); self::assertTrue(isset($zipFile[$newName])); self::assertFalse(isset($zipFile['file1.txt'])); - self::assertTrue(isset($zipFile['file2.txt'])); + self::assertFalse(isset($zipFile['file2.txt'])); + self::assertFalse(isset($zipFile['file3.txt'])); + self::assertTrue(isset($zipFile['file_long_name.txt'])); + self::assertTrue(isset($zipFile['file4.txt'])); + self::assertTrue(isset($zipFile['fi.txt'])); $zipFile->close(); } @@ -1737,119 +1745,6 @@ class ZipFileTest extends ZipTestCase $zipFile->rewrite(); } - /** - * Test zip alignment. - */ - public function testZipAlignSourceZip() - { - $zipFile = new ZipFile(); - for ($i = 0; $i < 100; $i++) { - $zipFile->addFromString( - 'entry' . $i . '.txt', - CryptoUtil::randomBytes(mt_rand(100, 4096)), - ZipFileInterface::METHOD_STORED - ); - } - $zipFile->saveAsFile($this->outputFilename); - $zipFile->close(); - - self::assertCorrectZipArchive($this->outputFilename); - - $result = self::doZipAlignVerify($this->outputFilename); - if ($result === null) { - return; - } // zip align not installed - - // check not zip align - self::assertFalse($result); - - $zipFile->openFile($this->outputFilename); - $zipFile->setZipAlign(4); - $zipFile->saveAsFile($this->outputFilename); - $zipFile->close(); - - self::assertCorrectZipArchive($this->outputFilename); - - $result = self::doZipAlignVerify($this->outputFilename, true); - self::assertNotNull($result); - - // check zip align - self::assertTrue($result); - } - - public function testZipAlignNewFiles() - { - $zipFile = new ZipFile(); - for ($i = 0; $i < 100; $i++) { - $zipFile->addFromString( - 'entry' . $i . '.txt', - CryptoUtil::randomBytes(mt_rand(100, 4096)), - ZipFileInterface::METHOD_STORED - ); - } - $zipFile->setZipAlign(4); - $zipFile->saveAsFile($this->outputFilename); - $zipFile->close(); - - self::assertCorrectZipArchive($this->outputFilename); - - $result = self::doZipAlignVerify($this->outputFilename); - if ($result === null) { - return; - } // zip align not installed - // check not zip align - self::assertTrue($result); - } - - public function testZipAlignFromModifiedZipArchive() - { - $zipFile = new ZipFile(); - for ($i = 0; $i < 100; $i++) { - $zipFile->addFromString( - 'entry' . $i . '.txt', - CryptoUtil::randomBytes(mt_rand(100, 4096)), - ZipFileInterface::METHOD_STORED - ); - } - $zipFile->saveAsFile($this->outputFilename); - $zipFile->close(); - - self::assertCorrectZipArchive($this->outputFilename); - - $result = self::doZipAlignVerify($this->outputFilename); - if ($result === null) { - return; - } // zip align not installed - - // check not zip align - self::assertFalse($result); - - $zipFile->openFile($this->outputFilename); - $zipFile->deleteFromRegex("~entry2[\d]+\.txt$~s"); - for ($i = 0; $i < 100; $i++) { - $isStored = (bool)mt_rand(0, 1); - - $zipFile->addFromString( - 'entry_new_' . ($isStored ? 'stored' : 'deflated') . '_' . $i . '.txt', - CryptoUtil::randomBytes(mt_rand(100, 4096)), - $isStored ? - ZipFileInterface::METHOD_STORED : - ZipFileInterface::METHOD_DEFLATED - ); - } - $zipFile->setZipAlign(4); - $zipFile->saveAsFile($this->outputFilename); - $zipFile->close(); - - self::assertCorrectZipArchive($this->outputFilename); - - $result = self::doZipAlignVerify($this->outputFilename, true); - self::assertNotNull($result); - - // check zip align - self::assertTrue($result); - } - public function testFilename0() { $zipFile = new ZipFile(); diff --git a/tests/PhpZip/resources/test.apk b/tests/PhpZip/resources/test.apk new file mode 100644 index 0000000..00411d3 Binary files /dev/null and b/tests/PhpZip/resources/test.apk differ