Dev BMW

How to work with archives in PHP


Archive opening example:
<?php
...

$zip = new ZipArchive();

$archivePath = $archive->getPathname();
if (true !== $zip->open($archivePath)) {
    throw new \RuntimeException(sprintf('Cannot open archive "%s".', $archivePath));
}

...

Archive files iterating example (without extracting):
<?php
...

/** @var ZipArchive $zip */
for ($i = 0; $i < $zip->numFiles; ++$i) {
    $fileName = $zip->getNameIndex($i);

    $stream = $zip->getStream($fileName);
    if ($stream) {
        $content = stream_get_contents($stream);
        // do something with content
        // if content is text - you can easily work with them!
        fclose($stream);
    }
}
...

Archive extracting & recursive files iterating (via RecursiveIteratorIterator and RecursiveDirectoryIterator) example:
<?php
...

// extraction
$tempDir = sys_get_temp_dir() . sprintf('/%s', 'archive_') . uniqid('', true);
if (false === @mkdir($tempDir, 0777, true) && !is_dir($tempDir)) {
    throw new RuntimeException(sprintf('Unable to create the "%s" directory.', $tempDir));
}

$zip->extractTo($tempDir);
$zip->close();

// iteration
/** @var \SplFileInfo $file */
foreach ($filesFirstIterator as $file) {
    $pathName = $file->getPathname();

    if ($file->isDir()) {
        // do something
    }

    if($file->isFile()) {
        // do domething
    }
}

And make sure that after any actions with extracted files you will delete temporary directory with the extracted archive. I suggest doing this in finally construction in case there is any error during your code work:
<?php
    ...
    public function uploadArchiveAction(Request $request): Response
    {
        try {
            // your logic
        } catch (\Throwable $exception) {
            // do any actions
        } finally {
            $this->deleteDirectory($tempDir);
        }
    }


    private function deleteDirectory(string $dir): void
    {
        if (!is_dir($dir)) {
            return;
        }

        $filesFirst = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS),
            RecursiveIteratorIterator::CHILD_FIRST
        );

        foreach ($filesFirst as $file) {
            $pathName = $file->getPathname();

            if ($file->isDir()) {
                rmdir($pathName);
            } else {
                unlink($pathName);
            }
        }

        rmdir($dir);
    }
1 месяц назад