From a485ad1a1c0c3f972bb76b18dd5d1409b194056a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADt=20Rozs=C3=ADval?= Date: Wed, 1 Jul 2020 10:45:50 +0200 Subject: [PATCH] Fix zip archive with directories and subdirectories --- src/Utils/Zip/ZipArchive.php | 54 +++++++++++++++---- ...{ZipArchiveFile.php => ZipArchiveItem.php} | 2 +- tests/UtilsTests/ZipArchive/.gitignore | 5 +- .../UtilsTests/ZipArchive/ZipArchiveTest.php | 18 ++++--- 4 files changed, 58 insertions(+), 21 deletions(-) rename src/Utils/Zip/{ZipArchiveFile.php => ZipArchiveItem.php} (94%) diff --git a/src/Utils/Zip/ZipArchive.php b/src/Utils/Zip/ZipArchive.php index 6620432..a9344cc 100644 --- a/src/Utils/Zip/ZipArchive.php +++ b/src/Utils/Zip/ZipArchive.php @@ -4,7 +4,9 @@ use Nette\FileNotFoundException; use Nette\SmartObject; +use SplFileInfo; use Wavevision\Utils\FileInfo; +use Wavevision\Utils\Finder; use Wavevision\Utils\Path; use ZipArchive as Zip; @@ -13,25 +15,27 @@ class ZipArchive use SmartObject; + private const INITIAL_DEPTH = 1; + /** - * @var ZipArchiveFile[] + * @var ZipArchiveItem[] */ - private array $files; + private array $items; private string $path; private Zip $zip; - public function __construct(string $path, ZipArchiveFile ...$files) + public function __construct(string $path, ZipArchiveItem ...$items) { - $this->files = $files; + $this->items = $items; $this->path = $path; $this->zip = new Zip(); } - public function addFile(ZipArchiveFile $file): self + public function addItem(ZipArchiveItem $item): self { - $this->files[] = $file; + $this->items[] = $item; return $this; } @@ -43,8 +47,13 @@ public function close(): self public function compress(): self { - foreach ($this->files as $file) { - $this->zip->addFile($this->getFilePath($file), $file->getName()); + foreach ($this->items as $item) { + $path = $this->getItemPath($item); + if (is_dir($path)) { + $this->addDir($item, self::INITIAL_DEPTH); + } else { + $this->zip->addFile($path, $item->getName()); + } } return $this->close(); } @@ -78,17 +87,40 @@ public function write(): self return $this; } + /** + * @param string[] $parents + */ + private function addDir(ZipArchiveItem $item, int $depth, array $parents = []): void + { + $deep = $depth > self::INITIAL_DEPTH; + $dir = $item->getName(); + if ($deep) { + $parents = [...$parents, $dir]; + $this->zip->addEmptyDir(Path::join(...$parents)); + } + /** @var SplFileInfo $subItem */ + foreach (Finder::find('*')->in($item->getPath()) as $subItem) { + $path = $subItem->getPathname(); + if ($subItem->isDir()) { + $this->addDir(new ZipArchiveItem($path), $depth + 1, $parents); + } else { + $name = $subItem->getFilename(); + $this->zip->addFile($path, $deep ? Path::join(...[...$parents, $name]) : $name); + } + } + } + private function getExtractDir(): string { $fileInfo = new FileInfo($this->getPath()); return Path::join($fileInfo->getDirName(), $fileInfo->getBaseName(true)); } - private function getFilePath(ZipArchiveFile $file): string + private function getItemPath(ZipArchiveItem $item): string { - $path = $file->getPath(); + $path = $item->getPath(); if (!file_exists($path)) { - throw new FileNotFoundException("Zip archive file '$path' not found."); + throw new FileNotFoundException("Zip archive item '$path' not found."); } return $path; } diff --git a/src/Utils/Zip/ZipArchiveFile.php b/src/Utils/Zip/ZipArchiveItem.php similarity index 94% rename from src/Utils/Zip/ZipArchiveFile.php rename to src/Utils/Zip/ZipArchiveItem.php index fed26a9..3c020c5 100644 --- a/src/Utils/Zip/ZipArchiveFile.php +++ b/src/Utils/Zip/ZipArchiveItem.php @@ -4,7 +4,7 @@ use Nette\SmartObject; -final class ZipArchiveFile +final class ZipArchiveItem { use SmartObject; diff --git a/tests/UtilsTests/ZipArchive/.gitignore b/tests/UtilsTests/ZipArchive/.gitignore index b1d8ee6..5be7dab 100644 --- a/tests/UtilsTests/ZipArchive/.gitignore +++ b/tests/UtilsTests/ZipArchive/.gitignore @@ -1,2 +1,3 @@ -test -test.zip +input +output +output.zip diff --git a/tests/UtilsTests/ZipArchive/ZipArchiveTest.php b/tests/UtilsTests/ZipArchive/ZipArchiveTest.php index 20b2ff4..802cf9a 100644 --- a/tests/UtilsTests/ZipArchive/ZipArchiveTest.php +++ b/tests/UtilsTests/ZipArchive/ZipArchiveTest.php @@ -5,22 +5,26 @@ use Nette\FileNotFoundException; use PHPUnit\Framework\TestCase; use Wavevision\Utils\Zip\ZipArchive; -use Wavevision\Utils\Zip\ZipArchiveFile; +use Wavevision\Utils\Zip\ZipArchiveItem; class ZipArchiveTest extends TestCase { public function testZipArchive(): void { - $path = __DIR__ . '/test.zip'; - $zip = new ZipArchive($path, new ZipArchiveFile(__DIR__ . '/../file.txt')); - $this->assertEquals('test.zip', $zip->getName()); + $path = __DIR__ . '/output.zip'; + $zip = new ZipArchive( + $path, + new ZipArchiveItem(__DIR__ . '/input/dir'), + new ZipArchiveItem(__DIR__ . '/input/file.txt') + ); + $this->assertEquals('output.zip', $zip->getName()); $zip->write()->compress(); $this->assertFileExists($path); $zip->read()->extract(); - $this->assertDirectoryExists(__DIR__ . '/test'); - $zip->addFile(new ZipArchiveFile('')); - $this->expectExceptionObject(new FileNotFoundException("Zip archive file '' not found.")); + $this->assertDirectoryExists(__DIR__ . '/output'); + $zip->addItem(new ZipArchiveItem('')); + $this->expectExceptionObject(new FileNotFoundException("Zip archive item '' not found.")); $zip->write()->compress(); }