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