Skip to content
This repository has been archived by the owner on Jul 28, 2024. It is now read-only.

Commit

Permalink
Fix zip archive with directories and subdirectories
Browse files Browse the repository at this point in the history
  • Loading branch information
rozsival committed Jul 1, 2020
1 parent e7489d3 commit a485ad1
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 21 deletions.
54 changes: 43 additions & 11 deletions src/Utils/Zip/ZipArchive.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;
}

Expand All @@ -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();
}
Expand Down Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

use Nette\SmartObject;

final class ZipArchiveFile
final class ZipArchiveItem
{

use SmartObject;
Expand Down
5 changes: 3 additions & 2 deletions tests/UtilsTests/ZipArchive/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
test
test.zip
input
output
output.zip
18 changes: 11 additions & 7 deletions tests/UtilsTests/ZipArchive/ZipArchiveTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down

0 comments on commit a485ad1

Please sign in to comment.