1
|
|
|
<?php namespace Comodojo\Zip; |
2
|
|
|
|
3
|
|
|
use \Comodojo\Foundation\Utils\UniqueId; |
4
|
|
|
use \Comodojo\Exception\ZipException; |
5
|
|
|
use \Countable; |
6
|
|
|
use \Exception; |
7
|
|
|
|
8
|
|
|
/** |
9
|
|
|
* Multiple Comodojo\Zip\Zip manager |
10
|
|
|
* |
11
|
|
|
* @package Comodojo Spare Parts |
12
|
|
|
* @author Marco Giovinazzi <[email protected]> |
13
|
|
|
* @license MIT |
14
|
|
|
* |
15
|
|
|
* LICENSE: |
16
|
|
|
* |
17
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
23
|
|
|
* THE SOFTWARE. |
24
|
|
|
*/ |
25
|
|
|
|
26
|
|
|
class ZipManager implements Countable { |
27
|
|
|
|
28
|
|
|
/** |
29
|
|
|
* Array of managed zip files |
30
|
|
|
* |
31
|
|
|
* @var array |
32
|
|
|
*/ |
33
|
|
|
private $zip_archives = []; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Count the number of Zip objects registered to the manager |
37
|
|
|
* |
38
|
|
|
* @return int |
39
|
|
|
*/ |
40
|
|
|
public function count(): int { |
41
|
|
|
return count($this->zip_archives); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* Add a Zip object to manager and return its id |
46
|
|
|
* |
47
|
|
|
* @param Zip $zip |
48
|
|
|
* |
49
|
|
|
* @return string |
50
|
|
|
*/ |
51
|
|
|
public function addZip(Zip $zip): string { |
52
|
|
|
|
53
|
|
|
$id = UniqueId::generate(32); |
54
|
|
|
$this->zip_archives[$id] = $zip; |
55
|
|
|
return $id; |
56
|
|
|
|
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* Remove a Zip object from manager |
61
|
|
|
* |
62
|
|
|
* @param Zip $zip |
63
|
|
|
* |
64
|
|
|
* @return bool |
65
|
|
|
* @throws ZipException |
66
|
|
|
*/ |
67
|
|
|
public function removeZip(Zip $zip): bool { |
68
|
|
|
|
69
|
|
|
$archive_key = array_search($zip, $this->zip_archives, true); |
70
|
|
|
if ( $archive_key === false ) { |
71
|
|
|
throw new ZipException("Archive not found"); |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
unset($this->zip_archives[$archive_key]); |
75
|
|
|
return true; |
76
|
|
|
|
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Remove a Zip object from manager by Zip id |
81
|
|
|
* |
82
|
|
|
* @param string $id |
83
|
|
|
* |
84
|
|
|
* @return bool |
85
|
|
|
* @throws ZipException |
86
|
|
|
*/ |
87
|
|
|
public function removeZipById(string $id): bool { |
88
|
|
|
|
89
|
|
|
if ( isset($this->zip_archives[$id]) === false ) { |
90
|
|
|
throw new ZipException("Archive: $id not found"); |
91
|
|
|
} |
92
|
|
|
unset($this->zip_archives[$id]); |
93
|
|
|
return true; |
94
|
|
|
|
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Get a list of all registered Zips filenames as an array |
99
|
|
|
* |
100
|
|
|
* @return array |
101
|
|
|
*/ |
102
|
|
View Code Duplication |
public function listZips(): array { |
|
|
|
|
103
|
|
|
|
104
|
|
|
return array_column( |
105
|
|
|
array_map(function($key, $archive) { |
106
|
|
|
return [ "key" => $key, "file" => $archive->getZipFile() ]; |
107
|
|
|
}, array_keys($this->zip_archives), $this->zip_archives), |
108
|
|
|
"file", "key"); |
109
|
|
|
|
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
/** |
113
|
|
|
* Get a Zip object by Id |
114
|
|
|
* |
115
|
|
|
* @param string $id The zip id |
116
|
|
|
* |
117
|
|
|
* @return Zip |
118
|
|
|
* @throws ZipException |
119
|
|
|
*/ |
120
|
|
|
public function getZip(string $id): Zip { |
121
|
|
|
|
122
|
|
|
if ( array_key_exists($id, $this->zip_archives) === false ) { |
123
|
|
|
throw new ZipException("Archive id $id not found"); |
124
|
|
|
} |
125
|
|
|
return $this->zip_archives[$id]; |
126
|
|
|
|
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* Set current base path (to add relative files to zip archive) |
131
|
|
|
* for all Zips |
132
|
|
|
* |
133
|
|
|
* @param string $path |
134
|
|
|
* |
135
|
|
|
* @return ZipManager |
136
|
|
|
* @throws ZipException |
137
|
|
|
*/ |
138
|
|
|
public function setPath(string $path): ZipManager { |
139
|
|
|
|
140
|
|
|
try { |
141
|
|
|
foreach ( $this->zip_archives as $archive ) { |
142
|
|
|
$archive->setPath($path); |
143
|
|
|
} |
144
|
|
|
return $this; |
145
|
|
|
} catch (ZipException $ze) { |
146
|
|
|
throw $ze; |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Get a list of paths used by Zips |
153
|
|
|
* |
154
|
|
|
* @return array |
155
|
|
|
*/ |
156
|
|
View Code Duplication |
public function getPath(): array { |
|
|
|
|
157
|
|
|
|
158
|
|
|
return array_column( |
159
|
|
|
array_map(function($key, $archive) { |
160
|
|
|
return [ "key" => $key, "path" => $archive->getPath() ]; |
161
|
|
|
}, array_keys($this->zip_archives), $this->zip_archives), |
162
|
|
|
"path", "key"); |
163
|
|
|
|
164
|
|
|
} |
165
|
|
|
|
166
|
|
|
/** |
167
|
|
|
* Set default file mask for all Zips |
168
|
|
|
* |
169
|
|
|
* @param int $mask |
170
|
|
|
* |
171
|
|
|
* @return ZipManager |
172
|
|
|
* @throws ZipException |
173
|
|
|
*/ |
174
|
|
|
public function setMask(int $mask): ZipManager { |
175
|
|
|
|
176
|
|
|
try { |
177
|
|
|
foreach ( $this->zip_archives as $archive ) { |
178
|
|
|
$archive->setMask($mask); |
179
|
|
|
} |
180
|
|
|
return $this; |
181
|
|
|
} catch (ZipException $ze) { |
182
|
|
|
throw $ze; |
183
|
|
|
} |
184
|
|
|
|
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* Get a list of masks from Zips |
189
|
|
|
* |
190
|
|
|
* @return array |
191
|
|
|
*/ |
192
|
|
View Code Duplication |
public function getMask(): array { |
|
|
|
|
193
|
|
|
|
194
|
|
|
return array_column( |
195
|
|
|
array_map(function($key, $archive) { |
196
|
|
|
return [ "key" => $key, "mask" => $archive->getMask() ]; |
197
|
|
|
}, array_keys($this->zip_archives), $this->zip_archives), |
198
|
|
|
"mask", "key"); |
199
|
|
|
|
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Get a list of files in Zips |
204
|
|
|
* |
205
|
|
|
* @return array |
206
|
|
|
* @throws ZipException |
207
|
|
|
*/ |
208
|
|
View Code Duplication |
public function listFiles(): array { |
|
|
|
|
209
|
|
|
|
210
|
|
|
try { |
211
|
|
|
return array_column( |
212
|
|
|
array_map(function($key, $archive) { |
213
|
|
|
return [ "key" => $key, "files" => $archive->listFiles() ]; |
214
|
|
|
}, array_keys($this->zip_archives), $this->zip_archives), |
215
|
|
|
"files", "key"); |
216
|
|
|
} catch (ZipException $ze) { |
217
|
|
|
throw $ze; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
/** |
223
|
|
|
* Extract Zips to common destination |
224
|
|
|
* |
225
|
|
|
* @param string $destination Destination path |
226
|
|
|
* @param bool $separate (optional) If true (default), files will be placed in different directories |
227
|
|
|
* @param mixed $files (optional) a filename or an array of filenames |
228
|
|
|
* |
229
|
|
|
* @return bool |
230
|
|
|
* @throws ZipException |
231
|
|
|
*/ |
232
|
|
|
public function extract( |
233
|
|
|
string $destination, |
234
|
|
|
bool $separate = true, |
235
|
|
|
$files = null |
236
|
|
|
): bool { |
237
|
|
|
|
238
|
|
|
try { |
239
|
|
|
foreach ( $this->zip_archives as $archive ) { |
240
|
|
|
|
241
|
|
|
$local_path = substr($destination, -1) == '/' ? $destination : $destination.'/'; |
242
|
|
|
$local_file = pathinfo($archive->getZipFile()); |
243
|
|
|
$local_destination = $separate ? ($local_path.$local_file['filename']) : $destination; |
244
|
|
|
|
245
|
|
|
$archive->extract($local_destination, $files); |
246
|
|
|
|
247
|
|
|
} |
248
|
|
|
return true; |
249
|
|
|
} catch (ZipException $ze) { |
250
|
|
|
throw $ze; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
} |
254
|
|
|
|
255
|
|
|
/** |
256
|
|
|
* Merge multiple Zips into one |
257
|
|
|
* |
258
|
|
|
* @param string $output_zip_file |
259
|
|
|
* Destination zip |
260
|
|
|
* @param bool $separate (optional) |
261
|
|
|
* If true (default), files will be placed in different directories |
262
|
|
|
* |
263
|
|
|
* @return bool |
264
|
|
|
* @throws ZipException |
265
|
|
|
*/ |
266
|
|
|
public function merge(string $output_zip_file, bool $separate = true): bool { |
267
|
|
|
|
268
|
|
|
$pathinfo = pathinfo($output_zip_file); |
269
|
|
|
$temporary_folder = $pathinfo['dirname']."/".ManagerTools::getTemporaryFolder(); |
270
|
|
|
|
271
|
|
|
try { |
272
|
|
|
|
273
|
|
|
$this->extract($temporary_folder, $separate); |
274
|
|
|
$zip = Zip::create($output_zip_file); |
275
|
|
|
$zip->add($temporary_folder, true)->close(); |
276
|
|
|
ManagerTools::recursiveUnlink($temporary_folder); |
277
|
|
|
return true; |
278
|
|
|
|
279
|
|
|
} catch (ZipException $ze) { |
280
|
|
|
throw $ze; |
281
|
|
|
} catch (Exception $e) { |
282
|
|
|
throw $e; |
283
|
|
|
} |
284
|
|
|
|
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
/** |
288
|
|
|
* Add a file to all registered Zips |
289
|
|
|
* |
290
|
|
|
* @param mixed $file_name_or_array |
291
|
|
|
* The filename to add or an array of filenames |
292
|
|
|
* @param bool $flatten_root_folder |
293
|
|
|
* (optional) If true, the Zip root folder will be flattened (default: false) |
294
|
|
|
* |
295
|
|
|
* @return ZipManager |
296
|
|
|
* @throws ZipException |
297
|
|
|
*/ |
298
|
|
|
public function add($file_name_or_array, bool $flatten_root_folder = false): ZipManager { |
299
|
|
|
|
300
|
|
|
try { |
301
|
|
|
|
302
|
|
|
foreach ( $this->zip_archives as $archive ) { |
303
|
|
|
$archive->add($file_name_or_array, $flatten_root_folder); |
304
|
|
|
} |
305
|
|
|
return $this; |
306
|
|
|
|
307
|
|
|
} catch (ZipException $ze) { |
308
|
|
|
throw $ze; |
309
|
|
|
} |
310
|
|
|
|
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* Delete a file from any registered Zip |
315
|
|
|
* |
316
|
|
|
* @param mixed $file_name_or_array |
317
|
|
|
* The filename to add or an array of filenames |
318
|
|
|
* |
319
|
|
|
* @return ZipManager |
320
|
|
|
* @throws ZipException |
321
|
|
|
*/ |
322
|
|
|
public function delete($file_name_or_array): ZipManager { |
323
|
|
|
|
324
|
|
|
try { |
325
|
|
|
|
326
|
|
|
foreach ( $this->zip_archives as $archive ) { |
327
|
|
|
$archive->delete($file_name_or_array); |
328
|
|
|
} |
329
|
|
|
return $this; |
330
|
|
|
|
331
|
|
|
} catch (ZipException $ze) { |
332
|
|
|
throw $ze; |
333
|
|
|
} |
334
|
|
|
|
335
|
|
|
} |
336
|
|
|
|
337
|
|
|
/** |
338
|
|
|
* Close all Zips |
339
|
|
|
* |
340
|
|
|
* @return bool |
341
|
|
|
* @throws ZipException |
342
|
|
|
*/ |
343
|
|
|
public function close(): bool { |
344
|
|
|
|
345
|
|
|
try { |
346
|
|
|
foreach ( $this->zip_archives as $archive ) { |
347
|
|
|
$archive->close(); |
348
|
|
|
} |
349
|
|
|
return true; |
350
|
|
|
} catch (ZipException $ze) { |
351
|
|
|
throw $ze; |
352
|
|
|
} |
353
|
|
|
|
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
} |
357
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.