mirror of
https://github.com/Ne-Lexa/php-zip.git
synced 2025-07-17 22:21:13 +02:00
Fix resave aligned archive
This commit is contained in:
@@ -481,9 +481,11 @@ class ZipInputStream implements ZipInputStreamInterface
|
|||||||
$pos = PHP_INT_SIZE === 4 ? sprintf('%u', $pos) : $pos;
|
$pos = PHP_INT_SIZE === 4 ? sprintf('%u', $pos) : $pos;
|
||||||
$pos = $this->mapper->map($pos);
|
$pos = $this->mapper->map($pos);
|
||||||
|
|
||||||
$extraLength = strlen($entry->getExtra());
|
|
||||||
$nameLength = strlen($entry->getName());
|
$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;
|
$length = ZipEntry::LOCAL_FILE_HEADER_MIN_LEN + $extraLength + $nameLength;
|
||||||
|
|
||||||
$padding = 0;
|
$padding = 0;
|
||||||
@@ -505,7 +507,7 @@ class ZipInputStream implements ZipInputStreamInterface
|
|||||||
} else {
|
} else {
|
||||||
stream_copy_to_stream($this->in, $out->getStream(), $length);
|
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)) {
|
if ($entry->getGeneralPurposeBitFlag(ZipEntry::GPBF_DATA_DESCRIPTOR)) {
|
||||||
$length = 12;
|
$length = 12;
|
||||||
if ($entry->isZip64ExtensionsRequired()) {
|
if ($entry->isZip64ExtensionsRequired()) {
|
||||||
@@ -524,11 +526,13 @@ class ZipInputStream implements ZipInputStreamInterface
|
|||||||
$offset = $entry->getOffset();
|
$offset = $entry->getOffset();
|
||||||
$offset = PHP_INT_SIZE === 4 ? sprintf('%u', $offset) : $offset;
|
$offset = PHP_INT_SIZE === 4 ? sprintf('%u', $offset) : $offset;
|
||||||
$offset = $this->mapper->map($offset);
|
$offset = $this->mapper->map($offset);
|
||||||
$position = $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN +
|
$nameLength = strlen($entry->getName());
|
||||||
strlen($entry->getName()) + strlen($entry->getExtra());
|
|
||||||
$length = $entry->getCompressedSize();
|
fseek($this->in, $offset + ZipEntry::LOCAL_FILE_HEADER_MIN_LEN - 2, SEEK_SET);
|
||||||
fseek($this->in, $position, SEEK_SET);
|
$extraLength = unpack('v', fread($this->in, 2))[1];
|
||||||
stream_copy_to_stream($this->in, $out->getStream(), $length);
|
|
||||||
|
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()
|
public function __destruct()
|
||||||
|
157
tests/PhpZip/ZipAlignTest.php
Normal file
157
tests/PhpZip/ZipAlignTest.php
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace PhpZip;
|
||||||
|
|
||||||
|
use PhpZip\Util\CryptoUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test ZipAlign
|
||||||
|
*/
|
||||||
|
class ZipAlignTest extends ZipTestCase
|
||||||
|
{
|
||||||
|
public function testApkAlignedAndReSave()
|
||||||
|
{
|
||||||
|
$filename = __DIR__ . '/resources/test.apk';
|
||||||
|
|
||||||
|
self::assertCorrectZipArchive($filename);
|
||||||
|
self::doZipAlignVerify($this->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);
|
||||||
|
}
|
||||||
|
}
|
@@ -404,7 +404,11 @@ class ZipFileTest extends ZipTestCase
|
|||||||
$zipFile->openFile($this->outputFilename);
|
$zipFile->openFile($this->outputFilename);
|
||||||
$zipFile->rename($oldName, $newName);
|
$zipFile->rename($oldName, $newName);
|
||||||
$zipFile->addFromString('file1.txt', 'content');
|
$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->saveAsFile($this->outputFilename);
|
||||||
$zipFile->close();
|
$zipFile->close();
|
||||||
|
|
||||||
@@ -414,7 +418,11 @@ class ZipFileTest extends ZipTestCase
|
|||||||
self::assertFalse(isset($zipFile[$oldName]));
|
self::assertFalse(isset($zipFile[$oldName]));
|
||||||
self::assertTrue(isset($zipFile[$newName]));
|
self::assertTrue(isset($zipFile[$newName]));
|
||||||
self::assertFalse(isset($zipFile['file1.txt']));
|
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();
|
$zipFile->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1737,119 +1745,6 @@ class ZipFileTest extends ZipTestCase
|
|||||||
$zipFile->rewrite();
|
$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()
|
public function testFilename0()
|
||||||
{
|
{
|
||||||
$zipFile = new ZipFile();
|
$zipFile = new ZipFile();
|
||||||
|
BIN
tests/PhpZip/resources/test.apk
Normal file
BIN
tests/PhpZip/resources/test.apk
Normal file
Binary file not shown.
Reference in New Issue
Block a user