Passed
Push — spaghetti ( dd673c...d276c8 )
by simpletoimplement
02:07
created

Archive::getZipErrorString()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php declare(strict_types = 1);
2
3
namespace Spaghetti\XLSXParser;
4
5
use FilesystemIterator;
6
use RecursiveDirectoryIterator;
7
use RecursiveIteratorIterator;
8
use ReflectionClass;
9
use RuntimeException;
10
use ZipArchive;
11
12
use function file_exists;
13
use function rmdir;
14
use function sprintf;
15
use function sys_get_temp_dir;
16
use function tempnam;
17
use function unlink;
18
19
/**
20
 * @internal
21
 */
22
final class Archive
23
{
24
    private string $tmpPath;
25
    private ?ZipArchive $zip = null;
26
27
    public function __construct(private readonly string $archivePath)
28
    {
29
        $this->tmpPath = tempnam(directory: sys_get_temp_dir(), prefix: 'spaghetti_xlsx_parser_archive');
30
        unlink(filename: $this->tmpPath);
31
    }
32
33
    public function __destruct()
34
    {
35
        $this->deleteTmp();
36
        $this->closeArchive();
37
    }
38
39
    public function extract(string $filePath): string
40
    {
41
        $tmpPath = sprintf('%s/%s', $this->tmpPath, $filePath);
42
43
        if (!file_exists(filename: $tmpPath)) {
44
            $this->getArchive()->extractTo(pathto: $this->tmpPath, files: $filePath);
45
        }
46
47
        return $tmpPath;
48
    }
49
50
    private function getArchive(): ZipArchive
51
    {
52
        if (null === $this->zip) {
53
            $this->zip = new ZipArchive();
54
            $errorCode = $this->zip->open(filename: $this->archivePath);
55
56
            if (true !== $errorCode) {
57
                $this->zip = null;
58
                throw new RuntimeException(message: 'Error opening file: ' . $this->getErrorMessage(errorCode: $errorCode));
59
            }
60
        }
61
62
        return $this->zip;
63
    }
64
65
    private function closeArchive(): void
66
    {
67
        if (null !== $this->zip) {
68
            $this->zip->close();
69
            $this->zip = null;
70
        }
71
    }
72
73
    private function deleteTmp(): void
74
    {
75
        if (!file_exists(filename: $this->tmpPath)) {
76
            return;
77
        }
78
79
        $files = new RecursiveIteratorIterator(
80
            iterator: new RecursiveDirectoryIterator(directory: $this->tmpPath, flags: FilesystemIterator::SKIP_DOTS),
81
            mode: RecursiveIteratorIterator::CHILD_FIRST,
82
        );
83
84
        foreach ($files as $file) {
85
            if ($file->isDir()) {
86
                rmdir(directory: $file->getRealPath());
87
                continue;
88
            }
89
90
            unlink(filename: $file->getRealPath());
91
        }
92
93
        rmdir(directory: $this->tmpPath);
94
    }
95
96
    private function getErrorMessage(int $errorCode): string
97
    {
98
        return sprintf('An error has occured: %s::%s (%d)', ZipArchive::class, $this->getZipErrorString(value: $errorCode), $errorCode);
99
    }
100
101
    private function getZipErrorString(int $value): string
102
    {
103
        $map = array_flip(array: (new ReflectionClass(objectOrClass: ZipArchive::class))->getConstants());
104
105
        return array_key_exists(key: $value, array: $map) ? $map[$value] : 'UNKNOWN';
106
    }
107
}
108