Passed
Push — 0.1.x ( 9bc492...223229 )
by f
02:59
created

UnifiedArchive::canDeleteFiles()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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