Completed
Branch 0.1.x (de528d)
by f
03:18 queued 01:28
created

UnifiedArchive::createFilesList()   B

Complexity

Conditions 10
Paths 5

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 11.8232

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 10
eloc 18
c 3
b 0
f 0
nc 5
nop 1
dl 0
loc 30
ccs 14
cts 19
cp 0.7368
crap 11.8232
rs 7.6666

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace wapmorgan\UnifiedArchive;
3
4
use Exception;
5
use InvalidArgumentException;
6
use wapmorgan\UnifiedArchive\Formats\BasicFormat;
7
use wapmorgan\UnifiedArchive\Formats\Bzip;
8
use wapmorgan\UnifiedArchive\Formats\Cab;
9
use wapmorgan\UnifiedArchive\Formats\Gzip;
10
use wapmorgan\UnifiedArchive\Formats\Iso;
11
use wapmorgan\UnifiedArchive\Formats\Lzma;
12
use wapmorgan\UnifiedArchive\Formats\Rar;
13
use wapmorgan\UnifiedArchive\Formats\SevenZip;
14
use wapmorgan\UnifiedArchive\Formats\Tar;
15
use wapmorgan\UnifiedArchive\Formats\Zip;
16
17
/**
18
 * Class which represents archive in one of supported formats.
19
 */
20
class UnifiedArchive
21
{
22
    const VERSION = '0.1.2';
23
24
    const ZIP = 'zip';
25
    const SEVEN_ZIP = '7zip';
26
    const RAR = 'rar';
27
    const GZIP = 'gzip';
28
    const BZIP = 'bzip2';
29
    const LZMA = 'lzma2';
30
    const ISO = 'iso';
31
    const CAB = 'cab';
32
    const TAR = 'tar';
33
    const TAR_GZIP = 'tgz';
34
    const TAR_BZIP = 'tbz2';
35
    const TAR_LZMA = 'txz';
36
    const TAR_LZW = 'tar.z';
37
38
    /** @var array List of archive format handlers */
39
    protected static $formatHandlers = [
40
        self::ZIP => Zip::class,
41
        self::SEVEN_ZIP => SevenZip::class,
42
        self::RAR => Rar::class,
43
        self::GZIP => Gzip::class,
44
        self::BZIP => Bzip::class,
45
        self::LZMA => Lzma::class,
46
        self::ISO => Iso::class,
47
        self::CAB => Cab::class,
48
        self::TAR => Tar::class,
49
        self::TAR_GZIP => Tar::class,
50
        self::TAR_BZIP => Tar::class,
51
        self::TAR_LZMA => Tar::class,
52
        self::TAR_LZW => Tar::class,
53
    ];
54
55
    /** @var array List of archive formats with support state */
56
    static protected $enabledTypes = [];
57
58
    /** @var string Type of current archive */
59
    protected $type;
60
61
    /** @var BasicFormat Adapter for current archive */
62
    protected $archive;
63
64
    /** @var array List of files in current archive */
65
    protected $files;
66
67
    /** @var int Number of files */
68
    protected $filesQuantity;
69
70
    /** @var int Size of uncompressed files */
71
    protected $uncompressedFilesSize;
72
73
    /** @var int Size of compressed files */
74
    protected $compressedFilesSize;
75
76
    /** @var int Size of archive */
77
    protected $archiveSize;
78
79
    /**
80
     * Creates instance with right type
81
     *
82
     * @param  string $fileName Filename
83
     * @return UnifiedArchive|null Returns UnifiedArchive in case of successful reading of the file
84
     * @throws \Exception
85
     */
86 20
    public static function open($fileName)
87
    {
88 20
        self::checkRequirements();
89
90 20
        if (!file_exists($fileName) || !is_readable($fileName))
91
            throw new Exception('Could not open file: '.$fileName);
92
93 20
        $type = self::detectArchiveType($fileName);
94 20
        if (!self::canOpenType($type)) {
0 ignored issues
show
Bug introduced by
It seems like $type can also be of type false; however, parameter $type of wapmorgan\UnifiedArchive...dArchive::canOpenType() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

94
        if (!self::canOpenType(/** @scrutinizer ignore-type */ $type)) {
Loading history...
95
            return null;
96
        }
97
98 20
        return new self($fileName, $type);
0 ignored issues
show
Bug introduced by
It seems like $type can also be of type false; however, parameter $type of wapmorgan\UnifiedArchive...dArchive::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

98
        return new self($fileName, /** @scrutinizer ignore-type */ $type);
Loading history...
99
    }
100
101
    /**
102
     * Checks whether archive can be opened with current system configuration
103
     *
104
     * @param string $fileName
105
     * @return boolean
106
     */
107 18
    public static function canOpenArchive($fileName)
108
    {
109 18
        self::checkRequirements();
110
111 18
        $type = self::detectArchiveType($fileName);
112
113 18
        return $type !== false && self::canOpenType($type);
114
    }
115
116
    /**
117
     * Checks whether specific archive type can be opened with current system configuration
118
     *
119
     * @param string $type One of predefined archive types
120
     * @return boolean
121
     */
122 22
    public static function canOpenType($type)
123
    {
124 22
        self::checkRequirements();
125
126 22
        return isset(self::$enabledTypes[$type])
127 22
            ? self::$enabledTypes[$type]
128 22
            : false;
129
    }
130
131
    /**
132
     * @param string $type One of predefined archive types
133
     * @return bool
134
     */
135 2
    public static function canCreateType($type)
136
    {
137 2
        self::checkRequirements();
138 2
        return isset(self::$enabledTypes[$type])
139 2
            ? call_user_func([static::$formatHandlers[$type], 'canCreateArchive'])
140 2
            : false;
141
    }
142
143
    /**
144
     * Detect archive type by its filename or content
145
     *
146
     * @param string $fileName
147
     * @param bool $contentCheck
148
     * @return string|boolean One of UnifiedArchive type constants OR false if type is not detected
149
     */
150 33
    public static function detectArchiveType($fileName, $contentCheck = true)
151
    {
152
        // by file name
153 33
        $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));
154
155
        // by file name
156 33
        if (stripos($fileName, '.tar.') !== false && preg_match('~\.(?<ext>tar\.(gz|bz2|xz|z))$~', strtolower($fileName), $match)) {
157 9
            switch ($match['ext']) {
158 9
                case 'tar.gz':
159 4
                    return self::TAR_GZIP;
160 5
                case 'tar.bz2':
161 4
                    return self::TAR_BZIP;
162 1
                case 'tar.xz':
163 1
                    return self::TAR_LZMA;
164
                case 'tar.z':
165
                    return self::TAR_LZW;
166
            }
167
        }
168
169
        switch ($ext) {
170 24
            case 'zip':
171 6
                return self::ZIP;
172 18
            case '7z':
173 4
                return self::SEVEN_ZIP;
174 14
            case 'rar':
175 1
                return self::RAR;
176 13
            case 'gz':
177
                return self::GZIP;
178 13
            case 'bz2':
179
                return self::BZIP;
180 13
            case 'xz':
181
                return self::LZMA;
182 13
            case 'iso':
183 4
                return self::ISO;
184 9
            case 'cab':
185
                return self::CAB;
186 9
            case 'tar':
187 6
                return self::TAR;
188 3
            case 'tgz':
189 1
                return self::TAR_GZIP;
190 2
            case 'tbz2':
191 1
                return self::TAR_BZIP;
192 1
            case 'txz':
193 1
                return self::TAR_LZMA;
194
195
        }
196
197
        // by content
198
        if ($contentCheck) {
199
            $mime_type = mime_content_type($fileName);
200
            switch ($mime_type) {
201
                case 'application/zip':
202
                    return self::ZIP;
203
                case 'application/x-7z-compressed':
204
                    return self::SEVEN_ZIP;
205
                case 'application/x-rar':
206
                    return self::RAR;
207
                case 'application/zlib':
208
                    return self::GZIP;
209
                case 'application/x-bzip2':
210
                    return self::BZIP;
211
                case 'application/x-lzma':
212
                    return self::LZMA;
213
                case 'application/x-iso9660-image':
214
                    return self::ISO;
215
                case 'application/vnd.ms-cab-compressed':
216
                    return self::CAB;
217
                case 'application/x-tar':
218
                    return self::TAR;
219
                case 'application/x-gtar':
220
                    return self::TAR_GZIP;
221
222
            }
223
        }
224
225
        return false;
226
    }
227
228
    /**
229
     * Opens the file as one of supported formats
230
     *
231
     * @param string $fileName Filename
232
     * @param string $type Archive type.
233
     * @throws Exception If archive can not be opened
234
     */
235 20
    public function __construct($fileName, $type)
236
    {
237 20
        self::checkRequirements();
238
239 20
        $this->type = $type;
240 20
        $this->archiveSize = filesize($fileName);
241
242 20
        if (!isset(static::$formatHandlers[$type]))
243
            throw new Exception('Unsupported archive type: '.$type.' of archive '.$fileName);
244
245 20
        $handler_class = static::$formatHandlers[$type];
246
247 20
        $this->archive = new $handler_class($fileName);
248 20
        $this->scanArchive();
249 20
    }
250
251
    /**
252
     * Rescans array after modification
253
     */
254 20
    protected function scanArchive()
255
    {
256 20
        $information = $this->archive->getArchiveInformation();
257 20
        $this->files = $information->files;
258 20
        $this->compressedFilesSize = $information->compressedFilesSize;
259 20
        $this->uncompressedFilesSize = $information->uncompressedFilesSize;
260 20
        $this->filesQuantity = count($information->files);
261 20
    }
262
263
    /**
264
     * Closes archive
265
     */
266 20
    public function __destruct()
267
    {
268 20
        unset($this->archive);
269 20
    }
270
271
    /**
272
     * Returns an instance of class implementing PclZipOriginalInterface
273
     * interface.
274
     *
275
     * @return PclzipZipInterface Returns an instance of a class implementing PclZipOriginalInterface
276
     * @throws Exception
277
     */
278
    public function getPclZipInterface()
279
    {
280
        if ($this->type !== self::ZIP)
281
            throw new UnsupportedOperationException('Format '.$this->type.' does not support PclZip-interface');
282
283
        return new $this->archive->getPclZip();
0 ignored issues
show
Bug introduced by
The property getPclZip does not seem to exist on wapmorgan\UnifiedArchive\Formats\BasicFormat.
Loading history...
284
    }
285
286
    /**
287
     * Counts number of files
288
     *
289
     * @return int
290
     */
291 6
    public function countFiles()
292
    {
293 6
        return $this->filesQuantity;
294
    }
295
296
    /**
297
     * Counts size of all uncompressed data (bytes)
298
     *
299
     * @return int
300
     */
301 6
    public function countUncompressedFilesSize()
302
    {
303 6
        return $this->uncompressedFilesSize;
304
    }
305
306
    /**
307
     * Returns size of archive
308
     *
309
     * @return int
310
     */
311
    public function getArchiveSize()
312
    {
313
        return $this->archiveSize;
314
    }
315
316
    /**
317
     * Returns type of archive
318
     *
319
     * @return string
320
     */
321
    public function getArchiveType()
322
    {
323
        return $this->type;
324
    }
325
326
    /**
327
     * Counts size of all compressed data (in bytes)
328
     *
329
     * @return int
330
     */
331
    public function countCompressedFilesSize()
332
    {
333
        return $this->compressedFilesSize;
334
    }
335
336
    /**
337
     * Returns list of files
338
     *
339
     * @return array List of files
340
     */
341
    public function getFileNames()
342
    {
343
        return array_values($this->files);
344
    }
345
346
    /**
347
     * Checks that file exists in archive
348
     *
349
     * @param string $fileName
350
     * @return bool
351
     */
352 2
    public function isFileExists($fileName)
353
    {
354 2
        return in_array($fileName, $this->files, true);
355
    }
356
357
    /**
358
     * Returns file metadata
359
     *
360
     * @param string $fileName
361
     * @return ArchiveEntry|bool
362
     */
363 6
    public function getFileData($fileName)
364
    {
365 6
        if (!in_array($fileName, $this->files, true))
366
            return false;
367
368 6
        return $this->archive->getFileData($fileName);
369
    }
370
371
    /**
372
     * Returns file content
373
     *
374
     * @param string $fileName
375
     * @return bool|string
376
     * @throws \Exception
377
     */
378 8
    public function getFileContent($fileName)
379
    {
380 8
        if (!in_array($fileName, $this->files, true))
381
            return false;
382
383 8
        return $this->archive->getFileContent($fileName);
384
    }
385
386
    /**
387
     * Returns a resource for reading file from archive
388
     *
389
     * @param string $fileName
390
     * @return bool|resource
391
     */
392 6
    public function getFileResource($fileName)
393
    {
394 6
        if (!in_array($fileName, $this->files, true))
395
            return false;
396
397 6
        return $this->archive->getFileResource($fileName);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->archive->getFileResource($fileName) also could return the type string which is incompatible with the documented return type boolean|resource.
Loading history...
398
    }
399
400
    /**
401
     * Unpacks files to disk
402
     *
403
     * @param string $outputFolder Extraction output dir.
404
     * @param string|array|null $files One files or list of files or null to extract all content.
405
     * @param bool $expandFilesList Should be expanded paths like 'src/' to all files inside 'src/' dir or not.
406
     * @return false|int
407
     * @throws Exception If files can not be extracted
408
     */
409
    public function extractFiles($outputFolder, $files = null, $expandFilesList = false)
410
    {
411
        if ($files !== null) {
412
            if (is_string($files)) $files = [$files];
413
414
            if ($expandFilesList)
415
                $files = self::expandFileList($this->files, $files);
416
417
            return $this->archive->extractFiles($outputFolder, $files);
418
        } else {
419
            return $this->archive->extractArchive($outputFolder);
420
        }
421
    }
422
423
    /**
424
     * Updates existing archive by removing files from it
425
     *
426
     * Only 7zip and zip types support deletion.
427
     * @param string|string[] $fileOrFiles
428
     * @param bool $expandFilesList
429
     *
430
     * @return bool|int
431
     * @throws Exception
432
     */
433 2
    public function deleteFiles($fileOrFiles, $expandFilesList = false)
434
    {
435 2
        $fileOrFiles = is_string($fileOrFiles) ? [$fileOrFiles] : $fileOrFiles;
436
437 2
        if ($expandFilesList && $fileOrFiles !== null)
438
            $fileOrFiles = self::expandFileList($this->files, $fileOrFiles);
439
440 2
        $result = $this->archive->deleteFiles($fileOrFiles);
441 2
        $this->scanArchive();
442 2
        return $result;
443
    }
444
445
    /**
446
     * Updates existing archive by adding new files
447
     *
448
     * @param string[] $fileOrFiles See [[archiveFiles]] method for file list format.
449
     * @return int|bool False if failed, number of added files if success
450
     * @throws Exception
451
     */
452 2
    public function addFiles($fileOrFiles)
453
    {
454 2
        $files_list = self::createFilesList($fileOrFiles);
455 2
        if (empty($files_list))
456
            throw new InvalidArgumentException('Files list is empty!');
457 2
        $result = $this->archive->addFiles($files_list);
0 ignored issues
show
Bug introduced by
It seems like $files_list can also be of type boolean; however, parameter $files of wapmorgan\UnifiedArchive...BasicFormat::addFiles() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

457
        $result = $this->archive->addFiles(/** @scrutinizer ignore-type */ $files_list);
Loading history...
458 2
        $this->scanArchive();
459 2
        return $result;
460
    }
461
462
    /**
463
     * Adds file into archive
464
     *
465
     * @param string $file
466
     * @param string|null $inArchiveName If not passed, full path will be preserved.
467
     * @return bool
468
     * @throws Exception
469
     */
470 2
    public function addFile($file, $inArchiveName = null)
471
    {
472 2
        if (!is_file($file))
473
            throw new InvalidArgumentException($file.' is not a valid file to add in archive');
474
475 2
        return ($inArchiveName !== null
476 2
                ? $this->addFiles([$file => $inArchiveName])
477 2
                : $this->addFiles([$file])) === 1;
478
    }
479
480
    /**
481
     * Adds directory contents to archive
482
     *
483
     * @param string $directory
484
     * @param string|null $inArchivePath If not passed, full paths will be preserved.
485
     * @return bool
486
     * @throws Exception
487
     */
488
    public function addDirectory($directory, $inArchivePath = null)
489
    {
490
        if (!is_dir($directory) || !is_readable($directory))
491
            throw new InvalidArgumentException($directory.' is not a valid directory to add in archive');
492
493
        return ($inArchivePath !== null
494
                ? $this->addFiles([$directory => $inArchivePath])
495
                : $this->addFiles([$inArchivePath])) > 0;
496
    }
497
498
    /**
499
     * Creates an archive with passed files list
500
     *
501
     * @param string|string[]|array<string,string> $fileOrFiles List of files. Can be one of three formats:
502
     *                             1. A string containing path to file or directory.
503
     *                                  File will have it's basename.
504
     *                                  `UnifiedArchive::archiveFiles('/etc/php.ini', 'archive.zip)` will store
505
     * file with 'php.ini' name.
506
     *                                  Directory contents will be stored in archive root.
507
     *                                  `UnifiedArchive::archiveFiles('/var/log/', 'archive.zip')` will store all
508
     * directory contents in archive root.
509
     *                             2. An array with strings containing pats to files or directories.
510
     *                                  Files and directories will be stored with full paths.
511
     *                                  `UnifiedArchive::archiveFiles(['/etc/php.ini', '/var/log/'], 'archive.zip)`
512
     * will preserve full paths.
513
     *                             3. An array with strings where keys are strings.
514
     *                                  Files will have name from key.
515
     *                                  Directories contents will have prefix from key.
516
     *                                  `UnifiedArchive::archiveFiles(['doc.txt' => 'very_long_name_of_document.txt',
517
     *  'static' => '/var/www/html/static/'], 'archive.zip')`
518
     *
519
     * @param string $archiveName File name of archive. Type of archive will be determined via it's name.
520
     * @param bool $emulate If true, emulation mode is performed instead of real archiving.
521
     *
522
     * @return array|bool|int Count of stored files is returned.
523
     * @throws Exception
524
     */
525 2
    public static function archiveFiles($fileOrFiles, $archiveName, $emulate = false)
526
    {
527 2
        if (file_exists($archiveName))
528
            throw new Exception('Archive '.$archiveName.' already exists!');
529
530 2
        self::checkRequirements();
531
532 2
        $archiveType = self::detectArchiveType($archiveName, false);
533
        //        if (in_array($archiveType, [TarArchive::TAR, TarArchive::TAR_GZIP, TarArchive::TAR_BZIP, TarArchive::TAR_LZMA, TarArchive::TAR_LZW], true))
534
        //            return TarArchive::archiveFiles($fileOrFiles, $archiveName, $emulate);
535 2
        if ($archiveType === false)
536
            return false;
537
538 2
        $files_list = self::createFilesList($fileOrFiles);
539 2
        if (empty($files_list))
540
            throw new InvalidArgumentException('Files list is empty!');
541
542
        // fake creation: return archive data
543 2
        if ($emulate) {
544
            $totalSize = 0;
545
            foreach ($files_list as $fn) $totalSize += filesize($fn);
546
547
            return array(
548
                'totalSize' => $totalSize,
549
                'numberOfFiles' => count($files_list),
0 ignored issues
show
Bug introduced by
It seems like $files_list can also be of type boolean; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

549
                'numberOfFiles' => count(/** @scrutinizer ignore-type */ $files_list),
Loading history...
550
                'files' => $files_list,
551
                'type' => $archiveType,
552
            );
553
        }
554
555 2
        if (!isset(static::$formatHandlers[$archiveType]))
556
            throw new Exception('Unsupported archive type: '.$archiveType.' of archive '.$archiveName);
557
558 2
        $handler_class = static::$formatHandlers[$archiveType];
559
560 2
        return $handler_class::createArchive($files_list, $archiveName);
561
    }
562
563
    /**
564
     * Creates an archive with one file
565
     *
566
     * @param string $file
567
     * @param string $archiveName
568
     * @return bool
569
     * @throws \Exception
570
     */
571
    public static function archiveFile($file, $archiveName)
572
    {
573
        if (!is_file($file))
574
            throw new InvalidArgumentException($file.' is not a valid file to archive');
575
576
        return static::archiveFiles($file, $archiveName) === 1;
577
    }
578
579
    /**
580
     * Creates an archive with full directory contents
581
     *
582
     * @param string $directory
583
     * @param string $archiveName
584
     * @return bool
585
     * @throws Exception
586
     */
587
    public static function archiveDirectory($directory, $archiveName)
588
    {
589
        if (!is_dir($directory) || !is_readable($directory))
590
            throw new InvalidArgumentException($directory.' is not a valid directory to archive');
591
592
        return static::archiveFiles($directory, $archiveName) > 0;
593
    }
594
595
    /**
596
     * Tests system configuration
597
     */
598 22
    protected static function checkRequirements()
599
    {
600 22
        if (empty(self::$enabledTypes)) {
601 1
            self::$enabledTypes[self::ZIP] = extension_loaded('zip');
602 1
            self::$enabledTypes[self::SEVEN_ZIP] = class_exists('\Archive7z\Archive7z');
603 1
            self::$enabledTypes[self::RAR] = extension_loaded('rar');
604 1
            self::$enabledTypes[self::GZIP] = extension_loaded('zlib');
605 1
            self::$enabledTypes[self::BZIP] = extension_loaded('bz2');
606 1
            self::$enabledTypes[self::LZMA] = extension_loaded('xz');
607 1
            self::$enabledTypes[self::ISO] = class_exists('\CISOFile');
608 1
            self::$enabledTypes[self::CAB] = class_exists('\CabArchive');
609 1
            self::$enabledTypes[self::TAR] = class_exists('\Archive_Tar') || class_exists('\PharData');
610 1
            self::$enabledTypes[self::TAR_GZIP] = (class_exists('\Archive_Tar') || class_exists('\PharData')) && extension_loaded('zlib');
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: self::enabledTypes[self:...tension_loaded('zlib')), Probably Intended Meaning: self::enabledTypes[self:...tension_loaded('zlib'))
Loading history...
611 1
            self::$enabledTypes[self::TAR_BZIP] = (class_exists('\Archive_Tar') || class_exists('\PharData')) && extension_loaded('bz2');
0 ignored issues
show
introduced by
Consider adding parentheses for clarity. Current Interpretation: self::enabledTypes[self:...xtension_loaded('bz2')), Probably Intended Meaning: self::enabledTypes[self:...xtension_loaded('bz2'))
Loading history...
612 1
            self::$enabledTypes[self::TAR_LZMA] = class_exists('\Archive_Tar') && extension_loaded('lzma2');
613 1
            self::$enabledTypes[self::TAR_LZW] = class_exists('\Archive_Tar') && LzwStreamWrapper::isBinaryAvailable();
614
        }
615 22
    }
616
617
    /**
618
     * Deprecated method for extracting files
619
     *
620
     * @param string $outputFolder
621
     * @param string|array|null $files
622
     * @deprecated 0.1.0
623
     * @see extractFiles()
624
     * @return bool|int
625
     * @throws Exception
626
     */
627
    public function extractNode($outputFolder, $files = null)
628
    {
629
        return $this->extractFiles($outputFolder, $files);
630
    }
631
632
    /**
633
     * Deprecated method for archiving files
634
     *
635
     * @param string|array $filesOrFiles
636
     * @param string $archiveName
637
     * @deprecated 0.1.0
638
     * @see archiveFiles()
639
     * @return mixed
640
     * @throws Exception
641
     */
642
    public static function archiveNodes($filesOrFiles, $archiveName)
643
    {
644
        return static::archiveFiles($filesOrFiles, $archiveName);
645
    }
646
647
    /**
648
     * Expands files list
649
     *
650
     * @param $archiveFiles
651
     * @param $files
652
     * @return array
653
     */
654
    protected static function expandFileList($archiveFiles, $files)
655
    {
656
        $newFiles = [];
657
        foreach ($files as $file) {
658
            foreach ($archiveFiles as $archiveFile) {
659
                if (fnmatch($file.'*', $archiveFile))
660
                    $newFiles[] = $archiveFile;
661
            }
662
        }
663
        return $newFiles;
664
    }
665
666
    /**
667
     * @param string|array $nodes
668
     * @return array|bool
669
     */
670 4
    protected static function createFilesList($nodes)
671
    {
672 4
        $files = [];
673
674
        // passed an extended list
675 4
        if (is_array($nodes)) {
676 2
            foreach ($nodes as $source => $destination) {
677 2
                if (is_numeric($source))
678
                    $source = $destination;
679
680 2
                $destination = rtrim($destination, '/\\*');
681
682
                // if is directory
683 2
                if (is_dir($source))
684
                    self::importFilesFromDir(rtrim($source, '/\\*').'/*',
685
                        !empty($destination) ? $destination.'/' : null, true, $files);
686 2
                else if (is_file($source))
687 2
                    $files[$destination] = $source;
688
            }
689
690 2
        } else if (is_string($nodes)) { // passed one file or directory
0 ignored issues
show
introduced by
The condition is_string($nodes) is always true.
Loading history...
691
            // if is directory
692 2
            if (is_dir($nodes))
693 2
                self::importFilesFromDir(rtrim($nodes, '/\\*').'/*', null, true,
694 2
                    $files);
695
            else if (is_file($nodes))
696
                $files[basename($nodes)] = $nodes;
697
        }
698
699 4
        return $files;
700
    }
701
702
    /**
703
     * @param string $source
704
     * @param string|null $destination
705
     * @param bool $recursive
706
     * @param array $map
707
     */
708 2
    protected static function importFilesFromDir($source, $destination, $recursive, &$map)
709
    {
710
        // $map[$destination] = rtrim($source, '/*');
711
        // do not map root archive folder
712
713 2
        if ($destination !== null)
714 2
            $map[$destination] = null;
715
716 2
        foreach (glob($source, GLOB_MARK) as $node) {
717 2
            if (in_array(substr($node, -1), ['/', '\\'], true) && $recursive) {
718 2
                self::importFilesFromDir(str_replace('\\', '/', $node).'*',
719 2
                    $destination.basename($node).'/', $recursive, $map);
720 2
            } elseif (is_file($node) && is_readable($node)) {
721 2
                $map[$destination.basename($node)] = $node;
722
            }
723
        }
724 2
    }
725
726
    /**
727
     * @return bool
728
     */
729 2
    public function canAddFiles()
730
    {
731 2
        return call_user_func([static::$formatHandlers[$this->type], 'canAddFiles']);
732
    }
733
734
    /**
735
     * @return bool
736
     */
737 2
    public function canDeleteFiles()
738
    {
739 2
        return call_user_func([static::$formatHandlers[$this->type], 'canDeleteFiles']);
740
    }
741
}
742