Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
2 / 2
CRAP
100.00% covered (success)
100.00%
1 / 1
Tar
100.00% covered (success)
100.00%
44 / 44
100.00% covered (success)
100.00%
2 / 2
18
100.00% covered (success)
100.00%
1 / 1
 pack
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
1 / 1
14
 unpack
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
4
1<?php
2/**
3 * Jingga
4 *
5 * PHP Version 8.1
6 *
7 * @package   phpOMS\Utils\IO\Zip
8 * @copyright Dennis Eichhorn
9 * @license   OMS License 2.0
10 * @version   1.0.0
11 * @link      https://jingga.app
12 */
13declare(strict_types=1);
14
15namespace phpOMS\Utils\IO\Zip;
16
17use phpOMS\System\File\FileUtils;
18use phpOMS\System\File\Local\Directory;
19
20/**
21 * Zip class for handling zip files.
22 *
23 * Providing basic zip support
24 *
25 * IMPORTANT:
26 * PharData seems to cache created files, which means even if the previously created file is deleted, it cannot create a new file with the same destination.
27 * bug? https://bugs.php.net/bug.php?id=75101
28 *
29 * @package phpOMS\Utils\IO\Zip
30 * @license OMS License 2.0
31 * @link    https://jingga.app
32 * @since   1.0.0
33 */
34class Tar implements ArchiveInterface
35{
36    /**
37     * {@inheritdoc}
38     */
39    public static function pack(string | array $sources, string $destination, bool $overwrite = false) : bool
40    {
41        $destination = FileUtils::absolute(\strtr($destination, '\\', '/'));
42        if ((!$overwrite && \is_file($destination))
43            || \is_dir($destination)
44        ) {
45            return false;
46        }
47
48        if (\is_string($sources)) {
49            $sources = [$sources => ''];
50        }
51
52        $tar = new \PharData($destination);
53
54        /**
55         * @var string $relative
56         */
57        foreach ($sources as $source => $relative) {
58            if (\is_int($source)) {
59                $source = $relative;
60            }
61
62            $source   = FileUtils::absolute(\strtr($source, '\\', '/'));
63            $relative = \strtr($relative, '\\', '/');
64
65            if (\is_dir($source)) {
66                /** @var string[] $files */
67                $files = new \RecursiveIteratorIterator(
68                    new \RecursiveDirectoryIterator($source, \FilesystemIterator::CURRENT_AS_PATHNAME),
69                    \RecursiveIteratorIterator::SELF_FIRST
70                );
71
72                foreach ($files as $file) {
73                    $file = \strtr($file, '\\', '/');
74
75                    /* Ignore . and .. */
76                    if (($pos = \mb_strrpos($file, '/')) === false
77                        || \in_array(\mb_substr($file, $pos + 1), ['.', '..'])
78                    ) {
79                        continue;
80                    }
81
82                    $absolute = \realpath($file);
83                    $absolute = \str_replace('\\', '/', (string) $absolute);
84                    $dir      = \ltrim(\rtrim($relative, '/\\') . '/' . \ltrim(\str_replace($source . '/', '', $absolute), '/\\'), '/\\');
85
86                    if (\is_dir($absolute)) {
87                        $tar->addEmptyDir($dir . '/');
88                    } elseif (\is_file($absolute)) {
89                        $tar->addFile($absolute, $dir);
90                    }
91                }
92            } elseif (\is_file($source)) {
93                $tar->addFile($source, $relative);
94            } else {
95                continue;
96            }
97        }
98
99        return true;
100    }
101
102    /**
103     * {@inheritdoc}
104     */
105    public static function unpack(string $source, string $destination) : bool
106    {
107        if (!\is_file($source)) {
108            return false;
109        }
110
111        if (!\is_dir($destination)) {
112            Directory::create($destination, recursive: true);
113        }
114
115        try {
116            $destination = \strtr($destination, '\\', '/');
117            $destination = \rtrim($destination, '/');
118            $tar         = new \PharData($source);
119
120            $tar->extractTo($destination . '/');
121
122            return true;
123        } catch (\Throwable $_) {
124            return false;
125        }
126    }
127}