1
0
mirror of https://github.com/Ne-Lexa/php-zip.git synced 2025-07-17 14:11:13 +02:00

Fix resave aligned archive

This commit is contained in:
Ne-Lexa
2017-11-15 10:48:29 +03:00
parent 0788892831
commit ba2e314ca2
4 changed files with 178 additions and 122 deletions

View File

@@ -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()

View 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);
}
}

View File

@@ -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();

Binary file not shown.