Passed
Push — master ( 9250d1...c59780 )
by f
02:24
created

UnifiedArchive::valid()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 3
ccs 0
cts 2
cp 0
rs 10
cc 1
nc 1
nop 0
crap 2
1
<?php
2
namespace wapmorgan\UnifiedArchive;
3
4
use ArrayAccess;
5
use Countable;
6
use InvalidArgumentException;
7
use Iterator;
8
use wapmorgan\UnifiedArchive\Drivers\BasicDriver;
9
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
10
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
11
use wapmorgan\UnifiedArchive\Exceptions\EmptyFileListException;
12
use wapmorgan\UnifiedArchive\Exceptions\FileAlreadyExistsException;
13
use wapmorgan\UnifiedArchive\Exceptions\NonExistentArchiveFileException;
14
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedArchiveException;
15
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
16
17
/**
18
 * Class which represents archive in one of supported formats.
19
 */
20
class UnifiedArchive implements ArrayAccess, Iterator, Countable
21
{
22
    const VERSION = '1.1.3';
23
24
    /** @var string Type of current archive */
25
    protected $format;
26
27
    /** @var BasicDriver Adapter for current archive */
28
    protected $archive;
29
30
    /** @var array List of files in current archive */
31
    protected $files;
32
33
    /**
34
     * @var int
35
     */
36
    protected $filesIterator = 0;
37
38
    /** @var int Number of files in archive */
39
    protected $filesQuantity;
40
41
    /** @var int Cumulative size of uncompressed files */
42
    protected $uncompressedFilesSize;
43
44
    /** @var int Cumulative size of compressed files */
45
    protected $compressedFilesSize;
46
47
    /** @var int Total size of archive file */
48
    protected $archiveSize;
49
50
    /**
51
     * @var null
52
     */
53
    protected $password;
54
55
    /**
56
     * Creates a UnifiedArchive instance for passed archive
57
     *
58
     * @param string $fileName Archive filename
59
     * @param null $password
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $password is correct as it would always require null to be passed?
Loading history...
60
     * @return UnifiedArchive|null Returns UnifiedArchive in case of successful reading of the file
61
     */
62 23
    public static function open($fileName, $password = null)
63
    {
64 23
        if (!file_exists($fileName) || !is_readable($fileName)) {
65
            throw new InvalidArgumentException('Could not open file: ' . $fileName.' is not readable');
66
        }
67
68 23
        $format = Formats::detectArchiveFormat($fileName);
69 23
        if (!Formats::canOpen($format)) {
70
            return null;
71
        }
72
73 23
        return new static($fileName, $format, $password);
74
    }
75
76
    /**
77
     * Checks whether archive can be opened with current system configuration
78
     *
79
     * @param string $fileName Archive filename
80
     * @return bool
81
     */
82 21
    public static function canOpen($fileName)
83
    {
84 21
        $format = Formats::detectArchiveFormat($fileName);
85 21
        return $format !== false && Formats::canOpen($format);
0 ignored issues
show
Bug introduced by
It seems like $format can also be of type true; however, parameter $format of wapmorgan\UnifiedArchive\Formats::canOpen() 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

85
        return $format !== false && Formats::canOpen(/** @scrutinizer ignore-type */ $format);
Loading history...
86
    }
87
88
    /**
89
     * Opens the file as one of supported formats
90
     *
91
     * @param string $fileName Archive filename
92
     * @param string $format Archive type
93
     * @param string|null $password
94
     */
95 23
    public function __construct($fileName, $format, $password = null)
96
    {
97 23
        $driver = Formats::getFormatDriver($format);
98 23
        if ($driver === false) {
99
            throw new \RuntimeException('Driver for '.$format.' ('.$fileName.') is not found');
100
        }
101
102 23
        $this->format = $format;
103 23
        $this->archiveSize = filesize($fileName);
104 23
        $this->password = $password;
0 ignored issues
show
Documentation Bug introduced by
It seems like $password can also be of type string. However, the property $password is declared as type null. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
105
106
        /** @var BasicDriver archive */
107 23
        $this->archive = new $driver($fileName, $format, $password);
108 23
        $this->scanArchive();
109 23
    }
110
111
    /**
112
     * Rescans array after modification
113
     */
114 23
    protected function scanArchive()
115
    {
116 23
        $information = $this->archive->getArchiveInformation();
117 23
        $this->files = $information->files;
118 23
        $this->compressedFilesSize = $information->compressedFilesSize;
119 23
        $this->uncompressedFilesSize = $information->uncompressedFilesSize;
120 23
        $this->filesQuantity = count($information->files);
121 23
    }
122
123
    /**
124
     * Closes archive
125
     */
126 23
    public function __destruct()
127
    {
128 23
        unset($this->archive);
129 23
    }
130
131
    /**
132
     * Returns an instance of class implementing PclZipOriginalInterface
133
     * interface.
134
     *
135
     * @return PclzipZipInterface Returns an instance of a class implementing PclZipOriginalInterface
136
     */
137
    public function getPclZipInterface()
138
    {
139
        return new PclzipZipInterface($this);
140
    }
141
142
    /**
143
     * @return string
144
     */
145 2
    public function getDriverType()
146
    {
147 2
        return get_class($this->archive);
148
    }
149
150
    /**
151
     * @return BasicDriver
152
     */
153
    public function getDriver()
154
    {
155
        return $this->archive;
156
    }
157
158
    /**
159
     * Returns size of archive file in bytes
160
     *
161
     * @return int
162
     */
163
    public function getSize()
164
    {
165
        return $this->archiveSize;
166
    }
167
168
    /**
169
     * Returns type of archive
170
     *
171
     * @return string One of Format class constants
172
     */
173
    public function getFormat()
174
    {
175
        return $this->format;
176
    }
177
178
    /**
179
     * Returns mime type of archive
180
     *
181
     * @return string|false Mime Type
182
     */
183
    public function getMimeType()
184
    {
185
        return Formats::getFormatMimeType($this->format);
186
    }
187
188
    /**
189
     * @return string|null
190
     */
191
    public function getComment()
192
    {
193
        return $this->archive->getComment();
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->archive->getComment() targeting wapmorgan\UnifiedArchive...sicDriver::getComment() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
194
    }
195
196
    /**
197
     * @param string|null $comment
198
     * @return string|null
199
     */
200
    public function setComment($comment)
201
    {
202
        return $this->archive->setComment($comment);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->archive->setComment($comment) targeting wapmorgan\UnifiedArchive...sicDriver::setComment() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
203
    }
204
205
    /**
206
     * Counts number of files
207
     *
208
     * @return int
209
     */
210 7
    public function countFiles()
211
    {
212 7
        return $this->filesQuantity;
213
    }
214
215
    /**
216
     * * Counts cumulative size of all uncompressed data (bytes)
217
     * @return int
218
     */
219 7
    public function getOriginalSize()
220
    {
221 7
        return $this->uncompressedFilesSize;
222
    }
223
224
    /**
225
     * Counts cumulative size of all compressed data (in bytes)
226
     * @return int
227
     */
228
    public function getCompressedSize()
229
    {
230
        return $this->compressedFilesSize;
231
    }
232
233
    /**
234
     * Checks that file exists in archive
235
     *
236
     * @param string $fileName File name in archive
237
     * @return bool
238
     */
239 8
    public function hasFile($fileName)
240
    {
241 8
        return in_array($fileName, $this->files, true);
242
    }
243
244
    /**
245
     * Returns list of files, excluding folders.
246
     *
247
     * Paths is present in unix-style (with forward slash - /).
248
     *
249
     * @param string|null $filter
250
     * @return array List of files
251
     */
252 8
    public function getFileNames($filter = null)
253
    {
254 8
        if ($filter === null)
255 8
            return $this->files;
256
257
        $result = [];
258
        foreach ($this->files as $file) {
259
            if (fnmatch($filter, $file))
260
                $result[] = $file;
261
        }
262
        return $result;
263
    }
264
265
    /**
266
     * Returns file metadata of file in archive
267
     *
268
     * @param string $fileName File name in archive
269
     * @return ArchiveEntry
270
     * @throws NonExistentArchiveFileException
271
     */
272 6
    public function getFileData($fileName)
273
    {
274 6
        if (!in_array($fileName, $this->files, true)) {
275
            throw new NonExistentArchiveFileException('File ' . $fileName . ' does not exist in archive');
276
        }
277
278 6
        return $this->archive->getFileData($fileName);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->archive->getFileData($fileName) could also return false which is incompatible with the documented return type wapmorgan\UnifiedArchive\ArchiveEntry. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
279
    }
280
281
    /**
282
     * Returns full file content as string
283
     *
284
     * @param string $fileName File name in archive
285
     * @return string
286
     * @throws NonExistentArchiveFileException
287
     */
288 8
    public function getFileContent($fileName)
289
    {
290 8
        if (!in_array($fileName, $this->files, true)) {
291
            throw new NonExistentArchiveFileException('File ' . $fileName . ' does not exist in archive');
292
        }
293
294 8
        return $this->archive->getFileContent($fileName);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->archive->getFileContent($fileName) could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
295
    }
296
297
    /**
298
     * Returns a resource for reading file from archive
299
     *
300
     * @param string $fileName File name in archive
301
     * @return resource
302
     * @throws NonExistentArchiveFileException
303
     */
304 6
    public function getFileStream($fileName)
305
    {
306 6
        if (!in_array($fileName, $this->files, true)) {
307
            throw new NonExistentArchiveFileException('File ' . $fileName . ' does not exist in archive');
308
        }
309
310 6
        return $this->archive->getFileStream($fileName);
311
    }
312
313
    /**
314
     * Unpacks files to disk
315
     *
316
     * @param string $outputFolder Extraction output dir
317
     * @param string|array|null $files One file or files list or null to extract all content.
318
     * @param bool $expandFilesList Whether paths like 'src/' should be expanded to all files inside 'src/' dir or not.
319
     * @return int Number of extracted files
320
     * @throws EmptyFileListException
321
     * @throws ArchiveExtractionException
322
     */
323
    public function extractFiles($outputFolder, $files = null, $expandFilesList = false)
324
    {
325
        if ($files !== null) {
326
            if (is_string($files)) {
327
                $files = [$files];
328
            }
329
330
            if ($expandFilesList) {
331
                $files = static::expandFileList($this->files, $files);
332
            }
333
334
            if (empty($files)) {
335
                throw new EmptyFileListException('Files list is empty!');
336
            }
337
338
            return $this->archive->extractFiles($outputFolder, $files);
339
        }
340
341
        return $this->archive->extractArchive($outputFolder);
342
    }
343
344
    /**
345
     * Updates existing archive by removing files from it
346
     *
347
     * Only 7zip and zip types support deletion.
348
     * @param string|string[] $fileOrFiles
349
     * @param bool $expandFilesList
350
     *
351
     * @return bool|int
352
     * @throws EmptyFileListException
353
     * @throws UnsupportedOperationException
354
     * @throws ArchiveModificationException
355
     */
356 2
    public function deleteFiles($fileOrFiles, $expandFilesList = false)
357
    {
358 2
        $fileOrFiles = is_string($fileOrFiles) ? [$fileOrFiles] : $fileOrFiles;
359
360 2
        if ($expandFilesList && $fileOrFiles !== null) {
361
            $fileOrFiles = static::expandFileList($this->files, $fileOrFiles);
362
        }
363
364 2
        if (empty($fileOrFiles)) {
365
            throw new EmptyFileListException('Files list is empty!');
366
        }
367
368 2
        $result = $this->archive->deleteFiles($fileOrFiles);
369 2
        $this->scanArchive();
370
371 2
        return $result;
372
    }
373
374
    /**
375
     * Updates existing archive by adding new files
376
     *
377
     * @param string[] $fileOrFiles See [[archiveFiles]] method for file list format.
378
     * @return int|bool Number of added files
379
     * @throws ArchiveModificationException
380
     * @throws EmptyFileListException
381
     * @throws UnsupportedOperationException
382
     */
383 2
    public function addFiles($fileOrFiles)
384
    {
385 2
        $files_list = static::createFilesList($fileOrFiles);
386
387 2
        if (empty($files_list))
388
            throw new EmptyFileListException('Files list is empty!');
389
390 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...BasicDriver::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

390
        $result = $this->archive->addFiles(/** @scrutinizer ignore-type */ $files_list);
Loading history...
391 2
        $this->scanArchive();
392 2
        return $result;
393
    }
394
395
    /**
396
     * Adds file into archive
397
     *
398
     * @param string $file File name to be added
399
     * @param string|null $inArchiveName If not passed, full path will be preserved.
400
     * @return bool
401
     * @throws ArchiveModificationException
402
     * @throws EmptyFileListException
403
     * @throws UnsupportedOperationException
404
     */
405 2
    public function addFile($file, $inArchiveName = null)
406
    {
407 2
        if (!is_file($file))
408
            throw new InvalidArgumentException($file.' is not a valid file to add in archive');
409
410 2
        return ($inArchiveName !== null
411 2
                ? $this->addFiles([$inArchiveName => $file])
412 2
                : $this->addFiles([$file])) === 1;
413
    }
414
415
    /**
416
     * @param string $inArchiveName
417
     * @param string $content
418
     * @return bool
419
     * @throws ArchiveModificationException
420
     * @throws UnsupportedOperationException
421
     */
422
    public function addFileFromString($inArchiveName, $content)
423
    {
424
        $result = $this->archive->addFileFromString($inArchiveName, $content);
425
        $this->scanArchive();
426
        return $result;
427
    }
428
429
    /**
430
     * Adds directory contents to archive
431
     *
432
     * @param string $directory
433
     * @param string|null $inArchivePath If not passed, full paths will be preserved.
434
     * @return bool
435
     * @throws ArchiveModificationException
436
     * @throws EmptyFileListException
437
     * @throws UnsupportedOperationException
438
     */
439
    public function addDirectory($directory, $inArchivePath = null)
440
    {
441
        if (!is_dir($directory) || !is_readable($directory))
442
            throw new InvalidArgumentException($directory.' is not a valid directory to add in archive');
443
444
        return ($inArchivePath !== null
445
                ? $this->addFiles([$inArchivePath => $directory])
446
                : $this->addFiles([$inArchivePath])) > 0;
447
    }
448
449
    /**
450
     * Prepare files list for archiving
451
     *
452
     * @param string $fileOrFiles File of list of files. See [[archiveFiles]] for details.
453
     * @param string $archiveName File name of archive. See [[archiveFiles]] for details.
454
     * @return array An array containing entries:
455
     * - totalSize (int) - size in bytes for all files
456
     * - numberOfFiles (int) - quantity of files
457
     * - files (array) - list of files prepared for archiving
458
     * - type (string) - prepared format for archive. One of class constants
459
     * @throws EmptyFileListException
460
     * @throws UnsupportedArchiveException
461
     */
462 2
    public static function prepareForArchiving($fileOrFiles, $archiveName)
463
    {
464 2
        $archiveType = Formats::detectArchiveFormat($archiveName, false);
465
466 2
        if ($archiveType === false)
467
            throw new UnsupportedArchiveException('Could not detect archive type for name "'.$archiveName.'"');
468
469 2
        $files_list = static::createFilesList($fileOrFiles);
470
471 2
        if (empty($files_list))
472
            throw new EmptyFileListException('Files list is empty!');
473
474 2
        $totalSize = 0;
475 2
        foreach ($files_list as $fn) {
476 2
            $totalSize += filesize($fn);
477
        }
478
479
        return [
480 2
            'totalSize' => $totalSize,
481 2
            'numberOfFiles' => count($files_list),
0 ignored issues
show
Bug introduced by
It seems like $files_list can also be of type boolean; however, parameter $value 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

481
            'numberOfFiles' => count(/** @scrutinizer ignore-type */ $files_list),
Loading history...
482 2
            'files' => $files_list,
483 2
            'type' => $archiveType,
484
        ];
485
    }
486
487
    /**
488
     * Creates an archive with passed files list
489
     *
490
     * @param string|string[]|array<string,string> $fileOrFiles List of files. Can be one of three formats:
491
     *                             1. A string containing path to file or directory.
492
     *                                  File will have it's basename.
493
     *                                  `UnifiedArchive::archiveFiles('/etc/php.ini', 'archive.zip)` will store
494
     * file with 'php.ini' name.
495
     *                                  Directory contents will be stored in archive root.
496
     *                                  `UnifiedArchive::archiveFiles('/var/log/', 'archive.zip')` will store all
497
     * directory contents in archive root.
498
     *                             2. An array with strings containing pats to files or directories.
499
     *                                  Files and directories will be stored with full paths.
500
     *                                  `UnifiedArchive::archiveFiles(['/etc/php.ini', '/var/log/'], 'archive.zip)`
501
     * will preserve full paths.
502
     *                             3. An array with strings where keys are strings.
503
     *                                  Files will have name from key.
504
     *                                  Directories contents will have prefix from key.
505
     *                                  `UnifiedArchive::archiveFiles(['doc.txt' => 'very_long_name_of_document.txt',
506
     *  'static' => '/var/www/html/static/'], 'archive.zip')`
507
     *
508
     * @param string $archiveName File name of archive. Type of archive will be determined by it's name.
509
     * @param int $compressionLevel Level of compression
510
     * @param null $password
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $password is correct as it would always require null to be passed?
Loading history...
511
     * @return int Count of stored files is returned.
512
     * @throws FileAlreadyExistsException
513
     * @throws UnsupportedOperationException
514
     */
515 2
    public static function archiveFiles($fileOrFiles, $archiveName, $compressionLevel = BasicDriver::COMPRESSION_AVERAGE, $password = null)
516
    {
517 2
        if (file_exists($archiveName))
518
            throw new FileAlreadyExistsException('Archive '.$archiveName.' already exists!');
519
520 2
        $info = static::prepareForArchiving($fileOrFiles, $archiveName);
0 ignored issues
show
Bug introduced by
It seems like $fileOrFiles can also be of type array<string,string> and string[]; however, parameter $fileOrFiles of wapmorgan\UnifiedArchive...::prepareForArchiving() 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

520
        $info = static::prepareForArchiving(/** @scrutinizer ignore-type */ $fileOrFiles, $archiveName);
Loading history...
521
522 2
        if (!Formats::canCreate($info['type']))
523
            throw new UnsupportedArchiveException('Unsupported archive type: '.$info['type'].' of archive '.$archiveName);
524
525 2
        if ($password !== null && !Formats::canEncrypt($info['type']))
0 ignored issues
show
introduced by
The condition $password !== null is always false.
Loading history...
526
            throw new UnsupportedOperationException('Archive type '.$info['type'].' can not be encrypted');
527
528
        /** @var BasicDriver $driver */
529 2
        $driver = Formats::getFormatDriver($info['type'], true);
530
531 2
        return $driver::createArchive($info['files'], $archiveName, $compressionLevel, $compressionLevel, $password);
0 ignored issues
show
Bug introduced by
It seems like $info['files'] can also be of type boolean; however, parameter $files of wapmorgan\UnifiedArchive...Driver::createArchive() 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

531
        return $driver::createArchive(/** @scrutinizer ignore-type */ $info['files'], $archiveName, $compressionLevel, $compressionLevel, $password);
Loading history...
532
    }
533
534
    /**
535
     * Creates an archive with one file
536
     *
537
     * @param string $file
538
     * @param string $archiveName
539
     * @param int $compressionLevel Level of compression
540
     * @param null $password
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $password is correct as it would always require null to be passed?
Loading history...
541
     * @return bool
542
     * @throws FileAlreadyExistsException
543
     * @throws UnsupportedOperationException
544
     */
545
    public static function archiveFile($file, $archiveName, $compressionLevel = BasicDriver::COMPRESSION_AVERAGE, $password = null)
546
    {
547
        if (!is_file($file)) {
548
            throw new InvalidArgumentException($file . ' is not a valid file to archive');
549
        }
550
551
        return static::archiveFiles($file, $archiveName, $compressionLevel, $password) === 1;
552
    }
553
554
    /**
555
     * Creates an archive with full directory contents
556
     *
557
     * @param string $directory
558
     * @param string $archiveName
559
     * @param int $compressionLevel Level of compression
560
     * @param null $password
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $password is correct as it would always require null to be passed?
Loading history...
561
     * @return bool
562
     * @throws FileAlreadyExistsException
563
     * @throws UnsupportedOperationException
564
     */
565
    public static function archiveDirectory($directory, $archiveName, $compressionLevel = BasicDriver::COMPRESSION_AVERAGE, $password = null)
566
    {
567
        if (!is_dir($directory) || !is_readable($directory))
568
            throw new InvalidArgumentException($directory.' is not a valid directory to archive');
569
570
        return static::archiveFiles($directory, $archiveName, $compressionLevel, $password) > 0;
571
    }
572
573
    /**
574
     * Expands files list
575
     * @param $archiveFiles
576
     * @param $files
577
     * @return array
578
     */
579
    protected static function expandFileList($archiveFiles, $files)
580
    {
581
        $newFiles = [];
582
        foreach ($files as $file) {
583
            foreach ($archiveFiles as $archiveFile) {
584
                if (fnmatch($file.'*', $archiveFile)) {
585
                    $newFiles[] = $archiveFile;
586
                }
587
            }
588
        }
589
        return $newFiles;
590
    }
591
592
    /**
593
     * @param string|array $nodes
594
     * @return array|bool
595
     */
596 4
    protected static function createFilesList($nodes)
597
    {
598 4
        $files = [];
599
600
        // passed an extended list
601 4
        if (is_array($nodes)) {
602 2
            foreach ($nodes as $destination => $source) {
603
                // new format
604 2
                if (is_numeric($destination))
605
                    $destination = $source;
606
                else {
607
                    // old format
608 2
                    if (!file_exists($source)) {
609
                        list($destination, $source) = [$source, $destination];
610
                    }
611
                }
612
613 2
                $destination = rtrim($destination, '/\\*');
614
615
                // if is directory
616 2
                if (is_dir($source))
617
                    static::importFilesFromDir(rtrim($source, '/\\*').'/*',
618
                        !empty($destination) ? $destination.'/' : null, true, $files);
619 2
                else if (is_file($source))
620 2
                    $files[$destination] = $source;
621
            }
622
623 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...
624
            // if is directory
625 2
            if (is_dir($nodes))
626 2
                static::importFilesFromDir(rtrim($nodes, '/\\*').'/*', null, true,
627 2
                    $files);
628
            else if (is_file($nodes))
629
                $files[basename($nodes)] = $nodes;
630
        }
631
632 4
        return $files;
633
    }
634
635
    /**
636
     * @param string $source
637
     * @param string|null $destination
638
     * @param bool $recursive
639
     * @param array $map
640
     */
641 2
    protected static function importFilesFromDir($source, $destination, $recursive, &$map)
642
    {
643
        // $map[$destination] = rtrim($source, '/*');
644
        // do not map root archive folder
645
646 2
        if ($destination !== null)
647 2
            $map[$destination] = null;
648
649 2
        foreach (glob($source, GLOB_MARK) as $node) {
650 2
            if (in_array(substr($node, -1), ['/', '\\'], true) && $recursive) {
651 2
                static::importFilesFromDir(str_replace('\\', '/', $node).'*',
652 2
                    $destination.basename($node).'/', $recursive, $map);
653 2
            } elseif (is_file($node) && is_readable($node)) {
654 2
                $map[$destination.basename($node)] = $node;
655
            }
656
        }
657 2
    }
658
659
    /**
660
     * Checks whether archive can be opened with current system configuration
661
     *
662
     * @param string $fileName Archive filename
663
     * @deprecated See {UnifiedArchive::canOpen()}
664
     * @return bool
665
     */
666
    public static function canOpenArchive($fileName)
667
    {
668
        return static::canOpen($fileName);
669
    }
670
671
    /**
672
     * Checks whether specific archive type can be opened with current system configuration
673
     *
674
     * @deprecated See {{Formats::canOpen()}}
675
     * @param string $type One of predefined archive types (class constants)
676
     * @return bool
677
     */
678
    public static function canOpenType($type)
679
    {
680
        return Formats::canOpen($type);
681
    }
682
683
    /**
684
     * Checks whether specified archive can be created
685
     *
686
     * @deprecated See {{Formats::canCreate()}}
687
     * @param string $type One of predefined archive types (class constants)
688
     * @return bool
689
     */
690
    public static function canCreateType($type)
691
    {
692
        return Formats::canCreate($type);
693
    }
694
695
    /**
696
     * Returns type of archive
697
     *
698
     * @deprecated See {{UnifiedArchive::getArchiveFormat()}}
699
     * @return string One of class constants
700
     */
701
    public function getArchiveType()
702
    {
703
        return $this->getFormat();
704
    }
705
706
    /**
707
     * Detect archive type by its filename or content
708
     *
709
     * @deprecated See {{Formats::detectArchiveFormat()}}
710
     * @param string $fileName Archive filename
711
     * @param bool $contentCheck Whether archive type can be detected by content
712
     * @return string|bool One of UnifiedArchive type constants OR false if type is not detected
713
     */
714
    public static function detectArchiveType($fileName, $contentCheck = true)
715
    {
716
        return Formats::detectArchiveFormat($fileName, $contentCheck);
717
    }
718
719
    /**
720
     * Returns a resource for reading file from archive
721
     *
722
     * @deprecated See {{UnifiedArchive::getFileStream}}
723
     * @param string $fileName File name in archive
724
     * @return resource
725
     * @throws NonExistentArchiveFileException
726
     */
727
    public function getFileResource($fileName)
728
    {
729
        return $this->getFileStream($fileName);
730
    }
731
732
    /**
733
     * Returns type of archive
734
     *
735
     * @deprecated See {{UnifiedArchive::getFormat}}
736
     * @return string One of class constants
737
     */
738
    public function getArchiveFormat()
739
    {
740
        return $this->getFormat();
741
    }
742
743
    /**
744
     * Checks that file exists in archive
745
     *
746
     * @deprecated See {{UnifiedArchive::hasFile}}
747
     * @param string $fileName File name in archive
748
     * @return bool
749
     */
750
    public function isFileExists($fileName)
751
    {
752
        return $this->hasFile($fileName);
753
    }
754
755
    /**
756
     * Returns size of archive file in bytes
757
     *
758
     * @deprecated See {{UnifiedArchive::getSize}}
759
     * @return int
760
     */
761
    public function getArchiveSize()
762
    {
763
        return $this->getSize();
764
    }
765
766
    /**
767
     * Counts cumulative size of all compressed data (in bytes)
768
     *
769
     * @deprecated See {{UnifiedArchive::getCompressedSize}}
770
     * @return int
771
     */
772
    public function countCompressedFilesSize()
773
    {
774
        return $this->getCompressedSize();
775
    }
776
777
    /**
778
     * Counts cumulative size of all uncompressed data (bytes)
779
     *
780
     * @deprecated See {{UnifiedArchive::getOriginalSize}}
781
     * @return int
782
     */
783
    public function countUncompressedFilesSize()
784
    {
785
        return $this->getOriginalSize();
786
    }
787
788
    /**
789
     * @param mixed $offset
790
     * @return bool
791
     */
792
    public function offsetExists($offset)
793
    {
794
        return $this->hasFile($offset);
795
    }
796
797
    /**
798
     * @param mixed $offset
799
     * @return mixed|string
800
     * @throws NonExistentArchiveFileException
801
     */
802
    public function offsetGet($offset)
803
    {
804
        return $this->getFileData($offset);
805
    }
806
807
    /**
808
     * @param mixed $offset
809
     * @param mixed $value
810
     * @return bool|void
811
     * @throws ArchiveModificationException
812
     * @throws UnsupportedOperationException
813
     */
814
    public function offsetSet($offset, $value)
815
    {
816
        return $this->addFileFromString($offset, $value);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->addFileFromString($offset, $value) returns the type boolean which is incompatible with the return type mandated by ArrayAccess::offsetSet() of void.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
817
    }
818
819
    /**
820
     * @param mixed $offset
821
     * @return bool|int|void
822
     * @throws ArchiveModificationException
823
     * @throws UnsupportedOperationException
824
     */
825
    public function offsetUnset($offset)
826
    {
827
        return $this->deleteFiles($offset);
828
    }
829
830
    public function key()
831
    {
832
        return $this->files[$this->filesIterator];
833
    }
834
835
    /**
836
     * @throws NonExistentArchiveFileException
837
     */
838
    public function current()
839
    {
840
        return $this->getFileData($this->files[$this->filesIterator]);
841
    }
842
843
    public function next()
844
    {
845
        $this->filesIterator++;
846
    }
847
848
    public function valid()
849
    {
850
        return $this->filesIterator < $this->filesQuantity;
851
    }
852
853
    public function rewind()
854
    {
855
        $this->filesIterator = 0;
856
    }
857
858
    public function count()
859
    {
860
        return $this->filesQuantity;
861
    }
862
}
863