ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
ZipReader.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22
26
31final class ZipReader
32{
36 private const BASE = '/';
40 private const APPLICATION_OCTET_STREAM = 'application/octet-stream';
41 private array $ignored = ['.', '..', '__MACOSX', '.info', '.DS_Store', Zip::DOT_EMPTY];
42 private \ZipArchive $zip;
43 private ?array $structure = null;
44
45 public function __construct(
46 private FileStream $stream
47 ) {
48 $this->zip = new \ZipArchive();
49 if (!$this->zip->open($this->stream->getMetadata()['uri'], \ZipArchive::RDONLY)) {
50 throw new \InvalidArgumentException('Could not open ZIP-File');
51 }
52 }
53
54 public function getStructure(): array
55 {
56 if ($this->structure !== null) {
57 return $this->structure;
58 }
59
60 $structure = [];
61 for ($i = 0; $i < $this->zip->count(); $i++) {
62 $path_original = $this->zip->getNameIndex($i);
63 $path = '/' . ltrim($path_original, './');
64 if ($path === '/') {
65 continue;
66 }
67 $dirname = dirname($path);
68 $basename = basename($path_original);
69 if (in_array($basename, $this->ignored, true)) {
70 continue;
71 }
72
73 $is_dir = (str_ends_with($path, '/') || str_ends_with($path, '\\'));
74
75 $stats = $this->zip->statIndex($i, \ZipArchive::FL_UNCHANGED);
76
77 $mime_type = null;
78 $size = null;
79 $modified = $modified = (int) ($stats['mtime'] ?? 0);
80 if (!$is_dir) {
81 try {
82 $finfo = finfo_open(FILEINFO_MIME_TYPE);
83 // We only need the first few bytes to determine the mime-type this helps to reduce RAM-Usage
84 $stream = $this->zip->getStream($path_original);
85 $fread = fread($stream, 256);
86 $mime_type = finfo_buffer($finfo, $fread);
87 fclose($stream);
88 $size = (int) ($stats['size'] ?? 0);
89 } catch (\Throwable) {
90 // ignore
92 }
93
94 // make sure we have a directory for this file as well. if this is missing in the ZIP
95 $parent = dirname($path_original);
96 $structure[$parent] = [
97 'path' => $parent,
98 'dirname' => dirname($parent),
99 'basename' => basename($parent),
100 'is_dir' => true,
101 'mime_type' => null,
102 'size' => null,
103 'modified' => $modified,
104 ];
105 }
106
107 $structure[$path_original] = [
108 'path' => $path,
109 'dirname' => $dirname,
110 'basename' => $basename,
111 'is_dir' => $is_dir,
112 'mime_type' => $mime_type,
113 'size' => $size,
114 'modified' => $modified,
115 ];
116 }
117
118 return $this->structure = $structure;
119 }
120
124 public function getItem(string $path_inside_zip, ?array $structure = null): array
125 {
126 $structure ??= $this->getStructure();
127 $info = $structure[$path_inside_zip] ?? [];
128
129 //$stream = Streams::ofString($this->zip->getFromName($path_inside_zip));
130
131 $stream = Streams::ofFileInsideZIP(
132 $this->stream->getMetadata()['uri'],
133 $path_inside_zip
134 );
135
136 return [$stream, $info];
137 }
138
139}
Stream factory which enables the user to create streams without the knowledge of the concrete class.
Definition: Streams.php:32
static ofFileInsideZIP(string $path_to_zip, string $path_inside_zip)
Definition: Streams.php:84
getItem(string $path_inside_zip, ?array $structure=null)
Definition: ZipReader.php:124
$info
Definition: entry_point.php:21
The base interface for all filesystem streams.
Definition: FileStream.php:32
$path
Definition: ltiservices.php:30