Passed
Push — master ( 8538c8...876ab1 )
by f
40:12 queued 25:11
created

UnifiedArchive::getArchiveSize()   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 5
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 5
b 0
f 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 0
cp 0
crap 2
rs 10
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.7';
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
    /** @var BasicDriver */
51
    protected $driver;
52
53
    /** @var string|null */
54
    private $password;
55
56
    /**
57
     * Creates a UnifiedArchive instance for passed archive
58
     *
59
     * @param string $fileName Archive filename
60
     * @param array|null|string $abilities List of supported abilities by driver. If passed string, used as password.
61
     * @param string|null $password Password to open archive
62 23
     * @return UnifiedArchive|null Returns UnifiedArchive in case of successful reading of the file
63
     */
64 23
    public static function open($fileName, $abilities = [], $password = null)
65
    {
66
        if (!file_exists($fileName) || !is_readable($fileName)) {
67
            throw new InvalidArgumentException('Could not open file: ' . $fileName.' is not readable');
68 23
        }
69 23
70
        $format = Formats::detectArchiveFormat($fileName);
71
        if ($format === false) {
72
            return null;
73 23
        }
74
75
        if (!empty($abilities) && is_string($abilities)) {
76
            $password = $abilities;
77
            $abilities = [];
78
        }
79
80
        if (empty($abilities)) {
81
            $abilities = [BasicDriver::OPEN];
82 21
            if (!empty($password)) {
83
                $abilities[] = [BasicDriver::OPEN_ENCRYPTED];
84 21
            }
85 21
        }
86
        $driver = Formats::getFormatDriver($format, $abilities);
0 ignored issues
show
Bug introduced by
It seems like $format can also be of type true; however, parameter $format of wapmorgan\UnifiedArchive...mats::getFormatDriver() 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

86
        $driver = Formats::getFormatDriver(/** @scrutinizer ignore-type */ $format, $abilities);
Loading history...
Bug introduced by
It seems like $abilities can also be of type null; however, parameter $abilities of wapmorgan\UnifiedArchive...mats::getFormatDriver() 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

86
        $driver = Formats::getFormatDriver($format, /** @scrutinizer ignore-type */ $abilities);
Loading history...
87
        if ($driver === null) {
88
            return null;
89
        }
90
91
        return new static($fileName, $format, $driver, $password);
0 ignored issues
show
Bug introduced by
It seems like $format can also be of type true; however, parameter $format 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

91
        return new static($fileName, /** @scrutinizer ignore-type */ $format, $driver, $password);
Loading history...
92
    }
93
94
    /**
95 23
     * Checks whether archive can be opened with current system configuration
96
     *
97 23
     * @param string $fileName Archive filename
98 23
     * @return bool
99
     */
100
    public static function canOpen($fileName)
101
    {
102 23
        $format = Formats::detectArchiveFormat($fileName);
103 23
        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

103
        return $format !== false && Formats::canOpen(/** @scrutinizer ignore-type */ $format);
Loading history...
104 23
    }
105
106
    /**
107 23
     * Opens the file as one of supported formats
108 23
     *
109 23
     * @param string $fileName Archive filename
110
     * @param string $format Archive type
111
     * @param string|BasicDriver $driver
112
     * @param string|null $password
113
     */
114 23
    public function __construct($fileName, $format, $driver, $password = null)
115
    {
116 23
        $this->format = $format;
117 23
        $this->driver = $driver;
0 ignored issues
show
Documentation Bug introduced by
It seems like $driver can also be of type string. However, the property $driver is declared as type wapmorgan\UnifiedArchive\Drivers\BasicDriver. 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...
118 23
        $this->password = $password;
119 23
        $this->archiveSize = filesize($fileName);
120 23
121 23
        /** @var BasicDriver */
122
        $this->archive = new $driver($fileName, $format, $password);
123
        $this->scanArchive();
124
    }
125
126 23
    /**
127
     * Rescans array after modification
128 23
     */
129 23
    protected function scanArchive()
130
    {
131
        $information = $this->archive->getArchiveInformation();
132
        $this->files = $information->files;
133
        $this->compressedFilesSize = $information->compressedFilesSize;
134
        $this->uncompressedFilesSize = $information->uncompressedFilesSize;
135
        $this->filesQuantity = count($information->files);
136
    }
137
138
    /**
139
     * Closes archive
140
     */
141
    public function __destruct()
142
    {
143
        unset($this->archive);
144
    }
145 2
146
    /**
147 2
     * Returns an instance of class implementing PclZipOriginalInterface
148
     * interface.
149
     *
150
     * @return PclZipInterface Returns an instance of a class implementing PclZip-like interface
151
     */
152
    public function getPclZipInterface()
153
    {
154
        return new PclZipInterface($this);
155
    }
156
157
    /**
158
     * @return string
159
     */
160
    public function getDriverType()
161
    {
162
        return get_class($this->archive);
163
    }
164
165
    /**
166
     * @return BasicDriver
167
     */
168
    public function getDriver()
169
    {
170
        return $this->archive;
171
    }
172
173
    /**
174
     * Returns size of archive file in bytes
175
     *
176
     * @return int
177
     */
178
    public function getSize()
179
    {
180
        return $this->archiveSize;
181
    }
182
183
    /**
184
     * Returns type of archive
185
     *
186
     * @return string One of Format class constants
187
     */
188
    public function getFormat()
189
    {
190
        return $this->format;
191
    }
192
193
    /**
194
     * Returns mime type of archive
195
     *
196
     * @return string|false Mime Type
197
     */
198
    public function getMimeType()
199
    {
200
        return Formats::getFormatMimeType($this->format);
201
    }
202
203
    /**
204
     * @return string|null
205
     */
206
    public function getComment()
207
    {
208
        return $this->archive->getComment();
209
    }
210 7
211
    /**
212 7
     * @param string|null $comment
213
     * @return string|null
214
     */
215
    public function setComment($comment)
216
    {
217
        return $this->archive->setComment($comment);
218
    }
219 7
220
    /**
221 7
     * Counts number of files
222
     *
223
     * @return int
224
     */
225
    public function countFiles()
226
    {
227
        return $this->filesQuantity;
228
    }
229
230
    /**
231
     * * Counts cumulative size of all uncompressed data (bytes)
232
     * @return int
233
     */
234
    public function getOriginalSize()
235
    {
236
        return $this->uncompressedFilesSize;
237
    }
238
239 8
    /**
240
     * Counts cumulative size of all compressed data (in bytes)
241 8
     * @return int
242
     */
243
    public function getCompressedSize()
244
    {
245
        return $this->compressedFilesSize;
246
    }
247
248
    /**
249
     * Checks that file exists in archive
250
     *
251
     * @param string $fileName File name in archive
252 8
     * @return bool
253
     */
254 8
    public function hasFile($fileName)
255 8
    {
256
        return in_array($fileName, $this->files, true);
257
    }
258
259
    /**
260
     * Returns list of files, excluding folders.
261
     *
262
     * Paths is present in unix-style (with forward slash - /).
263
     *
264
     * @param string|null $filter
265
     * @return array List of files
266
     */
267
    public function getFileNames($filter = null)
268
    {
269
        if ($filter === null)
270
            return $this->files;
271
272 6
        $result = [];
273
        foreach ($this->files as $file) {
274 6
            if (fnmatch($filter, $file))
275
                $result[] = $file;
276
        }
277
        return $result;
278 6
    }
279
280
    /**
281
     * Returns file metadata of file in archive
282
     *
283
     * @param string $fileName File name in archive
284
     * @return ArchiveEntry
285
     * @throws NonExistentArchiveFileException
286
     */
287
    public function getFileData($fileName)
288 8
    {
289
        if (!in_array($fileName, $this->files, true)) {
290 8
            throw new NonExistentArchiveFileException('File ' . $fileName . ' does not exist in archive');
291
        }
292
293
        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...
294 8
    }
295
296
    /**
297
     * Returns full file content as string
298
     *
299
     * @param string $fileName File name in archive
300
     * @return string
301
     * @throws NonExistentArchiveFileException
302
     */
303
    public function getFileContent($fileName)
304 6
    {
305
        if (!in_array($fileName, $this->files, true)) {
306 6
            throw new NonExistentArchiveFileException('File ' . $fileName . ' does not exist in archive');
307
        }
308
309
        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...
310 6
    }
311
312
    /**
313
     * Returns a resource for reading file from archive
314
     *
315
     * @param string $fileName File name in archive
316
     * @return resource
317
     * @throws NonExistentArchiveFileException
318
     */
319
    public function getFileStream($fileName)
320
    {
321
        if (!in_array($fileName, $this->files, true)) {
322
            throw new NonExistentArchiveFileException('File ' . $fileName . ' does not exist in archive');
323
        }
324
325
        return $this->archive->getFileStream($fileName);
326
    }
327
328
    /**
329
     * Unpacks files to disk
330
     *
331
     * @param string $outputFolder Extraction output dir
332
     * @param string|array|null $files One file or files list or null to extract all content.
333
     * @param bool $expandFilesList Whether paths like 'src/' should be expanded to all files inside 'src/' dir or not.
334
     * @return int Number of extracted files
335
     * @throws EmptyFileListException
336
     * @throws ArchiveExtractionException
337
     */
338
    public function extractFiles($outputFolder, &$files = null, $expandFilesList = false)
339
    {
340
        if ($files !== null) {
341
            if (is_string($files)) {
342
                $files = [$files];
343
            }
344
345
            if ($expandFilesList) {
346
                $files = static::expandFileList($this->files, $files);
347
            }
348
349
            if (empty($files)) {
350
                throw new EmptyFileListException('Files list is empty!');
351
            }
352
353
            return $this->archive->extractFiles($outputFolder, $files);
354
        }
355
356 2
        return $this->archive->extractArchive($outputFolder);
357
    }
358 2
359
    /**
360 2
     * Updates existing archive by removing files from it
361
     *
362
     * Only 7zip and zip types support deletion.
363
     * @param string|string[] $fileOrFiles
364 2
     * @param bool $expandFilesList
365
     *
366
     * @return bool|int
367
     * @throws EmptyFileListException
368 2
     * @throws UnsupportedOperationException
369 2
     * @throws ArchiveModificationException
370
     */
371 2
    public function deleteFiles($fileOrFiles, $expandFilesList = false)
372
    {
373
        $fileOrFiles = is_string($fileOrFiles) ? [$fileOrFiles] : $fileOrFiles;
374
375
        if ($expandFilesList && $fileOrFiles !== null) {
376
            $fileOrFiles = static::expandFileList($this->files, $fileOrFiles);
377
        }
378
379
        if (empty($fileOrFiles)) {
380
            throw new EmptyFileListException('Files list is empty!');
381
        }
382
383 2
        $result = $this->archive->deleteFiles($fileOrFiles);
384
        $this->scanArchive();
385 2
386
        return $result;
387 2
    }
388
389
    /**
390 2
     * Updates existing archive by adding new files
391 2
     *
392 2
     * @param string[] $fileOrFiles See [[archiveFiles]] method for file list format.
393
     * @return int|bool Number of added files
394
     * @throws ArchiveModificationException
395
     * @throws EmptyFileListException
396
     * @throws UnsupportedOperationException
397
     */
398
    public function addFiles($fileOrFiles)
399
    {
400
        $files_list = static::createFilesList($fileOrFiles);
401
402
        if (empty($files_list))
403
            throw new EmptyFileListException('Files list is empty!');
404
405 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

405
        $result = $this->archive->addFiles(/** @scrutinizer ignore-type */ $files_list);
Loading history...
406
        $this->scanArchive();
407 2
        return $result;
408
    }
409
410 2
    /**
411 2
     * Adds file into archive
412 2
     *
413
     * @param string $file File name to be added
414
     * @param string|null $inArchiveName If not passed, full path will be preserved.
415
     * @return bool
416
     * @throws ArchiveModificationException
417
     * @throws EmptyFileListException
418
     * @throws UnsupportedOperationException
419
     */
420
    public function addFile($file, $inArchiveName = null)
421
    {
422
        if (!is_file($file))
423
            throw new InvalidArgumentException($file.' is not a valid file to add in archive');
424
425
        return ($inArchiveName !== null
426
                ? $this->addFiles([$inArchiveName => $file])
427
                : $this->addFiles([$file])) === 1;
428
    }
429
430
    /**
431
     * @param string $inArchiveName
432
     * @param string $content
433
     * @return bool
434
     * @throws ArchiveModificationException
435
     * @throws UnsupportedOperationException
436
     */
437
    public function addFileFromString($inArchiveName, $content)
438
    {
439
        $result = $this->archive->addFileFromString($inArchiveName, $content);
440
        $this->scanArchive();
441
        return $result;
442
    }
443
444
    /**
445
     * Adds directory contents to archive
446
     *
447
     * @param string $directory
448
     * @param string|null $inArchivePath If not passed, full paths will be preserved.
449
     * @return bool
450
     * @throws ArchiveModificationException
451
     * @throws EmptyFileListException
452
     * @throws UnsupportedOperationException
453
     */
454
    public function addDirectory($directory, $inArchivePath = null)
455
    {
456
        if (!is_dir($directory) || !is_readable($directory))
457
            throw new InvalidArgumentException($directory.' is not a valid directory to add in archive');
458
459
        return ($inArchivePath !== null
460
                ? $this->addFiles([$inArchivePath => $directory])
461
                : $this->addFiles([$inArchivePath])) > 0;
462 2
    }
463
464 2
    /**
465
     * @param string|null $filter
466 2
     * @return true|string[]
467
     * @throws NonExistentArchiveFileException
468
     */
469 2
    public function test($filter = null)
470
    {
471 2
        $hash_exists = function_exists('hash_update_stream') && in_array('crc32b', hash_algos(), true);
472
        $failed = [];
473
        foreach ($this->getFileNames($filter) as $fileName) {
474 2
            if ($hash_exists) {
475 2
                $ctx = hash_init('crc32b');
476 2
                hash_update_stream($ctx, $this->getFileStream($fileName));
477
                $actual_hash = hash_final($ctx);
478
            } else {
479
                $actual_hash = dechex(crc32($this->getFileContent($fileName)));
480 2
            }
481 2
            $expected_hash = strtolower($this->getFileData($fileName)->crc32);
0 ignored issues
show
Bug introduced by
It seems like $this->getFileData($fileName)->crc32 can also be of type null; however, parameter $string of strtolower() 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

481
            $expected_hash = strtolower(/** @scrutinizer ignore-type */ $this->getFileData($fileName)->crc32);
Loading history...
482 2
            if ($expected_hash !== $actual_hash) {
483 2
                $failed[] = $fileName;
484
            }
485
        }
486
        return !empty($failed) ? $failed : true;
487
    }
488
489
    /**
490
     * Prepare files list for archiving
491
     *
492
     * @param string|array $fileOrFiles File of list of files. See [[archiveFiles]] for details.
493
     * @param string $archiveName File name of archive. See [[archiveFiles]] for details.
494
     * @return array An array containing entries:
495
     * - totalSize (int) - size in bytes for all files
496
     * - numberOfFiles (int) - quantity of files
497
     * - files (array) - list of files prepared for archiving
498
     * - type (string) - prepared format for archive. One of class constants
499
     * @throws EmptyFileListException
500
     * @throws UnsupportedArchiveException
501
     */
502
    public static function prepareForArchiving($fileOrFiles, $archiveName)
503
    {
504
        $archiveType = Formats::detectArchiveFormat($archiveName, false);
505
506
        if ($archiveType === false)
507
            throw new UnsupportedArchiveException('Could not detect archive type for name "'.$archiveName.'"');
508
509
        $files_list = static::createFilesList($fileOrFiles);
510
511
        if (empty($files_list))
512
            throw new EmptyFileListException('Files list is empty!');
513
514
        $totalSize = 0;
515 2
        foreach ($files_list as $fn) {
516
            if ($fn !== null) {
517 2
                $totalSize += filesize($fn);
518
            }
519
        }
520 2
521
        return [
522 2
            'totalSize' => $totalSize,
523
            '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

523
            'numberOfFiles' => count(/** @scrutinizer ignore-type */ $files_list),
Loading history...
524
            'files' => $files_list,
525 2
            'type' => $archiveType,
526
        ];
527
    }
528
529 2
    /**
530
     * Creates an archive with passed files list
531 2
     *
532
     * @param string|string[]|array<string,string> $fileOrFiles List of files. Can be one of three formats:
533
     *                             1. A string containing path to file or directory.
534
     *                                  File will have it's basename.
535
     *                                  `UnifiedArchive::archiveFiles('/etc/php.ini', 'archive.zip)` will store
536
     * file with 'php.ini' name.
537
     *                                  Directory contents will be stored in archive root.
538
     *                                  `UnifiedArchive::archiveFiles('/var/log/', 'archive.zip')` will store all
539
     * directory contents in archive root.
540
     *                             2. An array with strings containing pats to files or directories.
541
     *                                  Files and directories will be stored with full paths.
542
     *                                  `UnifiedArchive::archiveFiles(['/etc/php.ini', '/var/log/'], 'archive.zip)`
543
     * will preserve full paths.
544
     *                             3. An array with strings where keys are strings.
545
     *                                  Files will have name from key.
546
     *                                  Directories contents will have prefix from key.
547
     *                                  `UnifiedArchive::archiveFiles(['doc.txt' => 'very_long_name_of_document.txt',
548
     *  'static' => '/var/www/html/static/'], 'archive.zip')`
549
     *
550
     * @param string $archiveName File name of archive. Type of archive will be determined by it's name.
551
     * @param int $compressionLevel Level of compression
552
     * @param string|null $password
553
     * @param callable|null $fileProgressCallable
554
     * @return int Count of stored files is returned.
555
     * @throws FileAlreadyExistsException
556
     * @throws UnsupportedOperationException
557
     */
558
    public static function archiveFiles(
559
        $fileOrFiles,
560
        $archiveName,
561
        $compressionLevel = BasicDriver::COMPRESSION_AVERAGE,
562
        $password = null,
563
        $fileProgressCallable = null
564
 )
565
    {
566
        if (file_exists($archiveName))
567
            throw new FileAlreadyExistsException('Archive '.$archiveName.' already exists!');
568
569
        $info = static::prepareForArchiving($fileOrFiles, $archiveName);
570
571
        $abilities = [BasicDriver::CREATE];
572
573
        if (!Formats::canCreate($info['type']))
574
            throw new UnsupportedArchiveException('Unsupported archive type: '.$info['type'].' of archive '.$archiveName);
575
576
        if ($password !== null && !Formats::canEncrypt($info['type']))
577
            throw new UnsupportedOperationException('Archive type '.$info['type'].' can not be encrypted');
578
        if ($password !== null) {
579
            $abilities[] = BasicDriver::CREATE_ENCRYPTED;
580
        }
581
582
        /** @var BasicDriver $driver */
583
        $driver = Formats::getFormatDriver($info['type'], $abilities);
584
        if ($driver === null) {
585
            throw new UnsupportedArchiveException('Unsupported archive type: ' . $info['type'] . ' of archive ');
586
        }
587
588
        return $driver::createArchive(
589
            $info['files'],
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

589
            /** @scrutinizer ignore-type */ $info['files'],
Loading history...
590
            $archiveName,
591
            $compressionLevel,
592
            $compressionLevel,
593
            $password,
0 ignored issues
show
Bug introduced by
It seems like $password can also be of type string; however, parameter $password of wapmorgan\UnifiedArchive...Driver::createArchive() does only seem to accept null, 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

593
            /** @scrutinizer ignore-type */ $password,
Loading history...
594
            $fileProgressCallable
595
        );
596 4
    }
597
598 4
    /**
599
     * Creates an archive with one file
600
     *
601 4
     * @param string $file
602 2
     * @param string $archiveName
603
     * @param int $compressionLevel Level of compression
604 2
     * @param string|null $password
605
     * @return bool
606
     * @throws FileAlreadyExistsException
607
     * @throws UnsupportedOperationException
608 2
     */
609
    public static function archiveFile($file, $archiveName, $compressionLevel = BasicDriver::COMPRESSION_AVERAGE, $password = null)
610
    {
611
        if (!is_file($file)) {
612
            throw new InvalidArgumentException($file . ' is not a valid file to archive');
613 2
        }
614
615
        return static::archiveFiles($file, $archiveName, $compressionLevel, $password) === 1;
616 2
    }
617
618
    /**
619 2
     * Creates an archive with full directory contents
620 2
     *
621
     * @param string $directory
622
     * @param string $archiveName
623 2
     * @param int $compressionLevel Level of compression
624
     * @param string|null $password
625 2
     * @return bool
626 2
     * @throws FileAlreadyExistsException
627 2
     * @throws UnsupportedOperationException
628
     */
629
    public static function archiveDirectory($directory, $archiveName, $compressionLevel = BasicDriver::COMPRESSION_AVERAGE, $password = null)
630
    {
631
        if (!is_dir($directory) || !is_readable($directory))
632 4
            throw new InvalidArgumentException($directory.' is not a valid directory to archive');
633
634
        return static::archiveFiles($directory, $archiveName, $compressionLevel, $password) > 0;
635
    }
636
637
    /**
638
     * Expands files list
639
     * @param $archiveFiles
640
     * @param $files
641 2
     * @return array
642
     */
643
    protected static function expandFileList($archiveFiles, $files)
644
    {
645
        $newFiles = [];
646 2
        foreach ($files as $file) {
647 2
            foreach ($archiveFiles as $archiveFile) {
648
                if (fnmatch($file.'*', $archiveFile)) {
649 2
                    $newFiles[] = $archiveFile;
650 2
                }
651 2
            }
652 2
        }
653 2
        return $newFiles;
654 2
    }
655
656
    /**
657 2
     * @param string|array $nodes
658
     * @return array|bool
659
     */
660
    protected static function createFilesList($nodes)
661
    {
662
        $files = [];
663
664
        // passed an extended list
665
        if (is_array($nodes)) {
666
            foreach ($nodes as $destination => $source) {
667
                // new format
668
                if (is_numeric($destination))
669
                    $destination = $source;
670
                else {
671
                    // old format
672
                    if (is_string($source) && !file_exists($source)) {
673
                        list($destination, $source) = [$source, $destination];
674
                    }
675
                }
676
677
                $destination = rtrim($destination, '/\\*');
678
679
                // few sources for directories
680
                if (is_array($source)) {
681
                    foreach ($source as $sourceItem) {
682
                        static::importFilesFromDir(
683
                            rtrim($sourceItem, '/\\*') . '/*',
684
                            !empty($destination) ? $destination . '/' : null,
685
                            true,
686
                            $files
687
                        );
688
                    }
689
                } else if (is_dir($source)) {
690
                    // one source for directories
691
                    static::importFilesFromDir(
692
                        rtrim($source, '/\\*') . '/*',
693
                        !empty($destination) ? $destination . '/' : null,
694
                        true,
695
                        $files
696
                    );
697
                } else if (is_file($source)) {
698
                    $files[$destination] = $source;
699
                }
700
            }
701
702
        } 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...
703
            // if is directory
704
            if (is_dir($nodes))
705
                static::importFilesFromDir(rtrim($nodes, '/\\*').'/*', null, true,
706
                    $files);
707
            else if (is_file($nodes))
708
                $files[basename($nodes)] = $nodes;
709
        }
710
711
        return $files;
712
    }
713
714
    /**
715
     * @param string $source
716
     * @param string|null $destination
717
     * @param bool $recursive
718
     * @param array $map
719
     */
720
    protected static function importFilesFromDir($source, $destination, $recursive, &$map)
721
    {
722
        // $map[$destination] = rtrim($source, '/*');
723
        // do not map root archive folder
724
725
        if ($destination !== null)
726
            $map[$destination] = null;
727
728
        foreach (glob($source, GLOB_MARK) as $node) {
729
            if (in_array(substr($node, -1), ['/', '\\'], true) && $recursive) {
730
                static::importFilesFromDir(str_replace('\\', '/', $node).'*',
731
                    $destination.basename($node).'/', $recursive, $map);
732
            } elseif (is_file($node) && is_readable($node)) {
733
                $map[$destination.basename($node)] = $node;
734
            }
735
        }
736
    }
737
738
    /**
739
     * @param mixed $offset
740
     * @return bool
741
     */
742
    #[\ReturnTypeWillChange]
743
    public function offsetExists($offset)
744
    {
745
        return $this->hasFile($offset);
746
    }
747
748
    /**
749
     * @param mixed $offset
750
     * @return mixed|string
751
     * @throws NonExistentArchiveFileException
752
     */
753
    #[\ReturnTypeWillChange]
754
    public function offsetGet($offset)
755
    {
756
        return $this->getFileData($offset);
757
    }
758
759
    /**
760
     * @param mixed $offset
761
     * @param mixed $value
762
     * @return bool|void
763
     * @throws ArchiveModificationException
764
     * @throws UnsupportedOperationException
765
     */
766
    #[\ReturnTypeWillChange]
767
    public function offsetSet($offset, $value)
768
    {
769
        return $this->addFileFromString($offset, $value);
770
    }
771
772
    /**
773
     * @param mixed $offset
774
     * @return bool|int|void
775
     * @throws ArchiveModificationException
776
     * @throws UnsupportedOperationException
777
     */
778
    #[\ReturnTypeWillChange]
779
    public function offsetUnset($offset)
780
    {
781
        return $this->deleteFiles($offset);
782
    }
783
784
    #[\ReturnTypeWillChange]
785
    public function key()
786
    {
787
        return $this->files[$this->filesIterator];
788
    }
789
790
    /**
791
     * @throws NonExistentArchiveFileException
792
     */
793
    #[\ReturnTypeWillChange]
794
    public function current()
795
    {
796
        return $this->getFileData($this->files[$this->filesIterator]);
797
    }
798
799
    #[\ReturnTypeWillChange]
800
    public function next()
801
    {
802
        $this->filesIterator++;
803
    }
804
805
    #[\ReturnTypeWillChange]
806
    public function valid()
807
    {
808
        return $this->filesIterator < $this->filesQuantity;
809
    }
810
811
    #[\ReturnTypeWillChange]
812
    public function rewind()
813
    {
814
        $this->filesIterator = 0;
815
    }
816
817
    #[\ReturnTypeWillChange]
818
    public function count()
819
    {
820
        return $this->filesQuantity;
821
    }
822
823
    // deprecated methods
824
    /**
825
     * Checks whether archive can be opened with current system configuration
826
     *
827
     * @param string $fileName Archive filename
828
     * @deprecated See {UnifiedArchive::canOpen()}
829
     * @return bool
830
     */
831
    public static function canOpenArchive($fileName)
832
    {
833
        return static::canOpen($fileName);
834
    }
835
836
    /**
837
     * Checks whether specific archive type can be opened with current system configuration
838
     *
839
     * @deprecated See {{Formats::canOpen()}}
840
     * @param string $type One of predefined archive types (class constants)
841
     * @return bool
842
     */
843
    public static function canOpenType($type)
844
    {
845
        return Formats::canOpen($type);
846
    }
847
848
    /**
849
     * Checks whether specified archive can be created
850
     *
851
     * @deprecated See {{Formats::canCreate()}}
852
     * @param string $type One of predefined archive types (class constants)
853
     * @return bool
854
     */
855
    public static function canCreateType($type)
856
    {
857
        return Formats::canCreate($type);
858
    }
859
860
    /**
861
     * Returns type of archive
862
     *
863
     * @deprecated See {{UnifiedArchive::getArchiveFormat()}}
864
     * @return string One of class constants
865
     */
866
    public function getArchiveType()
867
    {
868
        return $this->getFormat();
869
    }
870
871
    /**
872
     * Detect archive type by its filename or content
873
     *
874
     * @deprecated See {{Formats::detectArchiveFormat()}}
875
     * @param string $fileName Archive filename
876
     * @param bool $contentCheck Whether archive type can be detected by content
877
     * @return string|bool One of UnifiedArchive type constants OR false if type is not detected
878
     */
879
    public static function detectArchiveType($fileName, $contentCheck = true)
880
    {
881
        return Formats::detectArchiveFormat($fileName, $contentCheck);
882
    }
883
884
    /**
885
     * Returns a resource for reading file from archive
886
     *
887
     * @deprecated See {{UnifiedArchive::getFileStream}}
888
     * @param string $fileName File name in archive
889
     * @return resource
890
     * @throws NonExistentArchiveFileException
891
     */
892
    public function getFileResource($fileName)
893
    {
894
        return $this->getFileStream($fileName);
895
    }
896
897
    /**
898
     * Returns type of archive
899
     *
900
     * @deprecated See {{UnifiedArchive::getFormat}}
901
     * @return string One of class constants
902
     */
903
    public function getArchiveFormat()
904
    {
905
        return $this->getFormat();
906
    }
907
908
    /**
909
     * Checks that file exists in archive
910
     *
911
     * @deprecated See {{UnifiedArchive::hasFile}}
912
     * @param string $fileName File name in archive
913
     * @return bool
914
     */
915
    public function isFileExists($fileName)
916
    {
917
        return $this->hasFile($fileName);
918
    }
919
920
    /**
921
     * Returns size of archive file in bytes
922
     *
923
     * @deprecated See {{UnifiedArchive::getSize}}
924
     * @return int
925
     */
926
    public function getArchiveSize()
927
    {
928
        return $this->getSize();
929
    }
930
931
    /**
932
     * Counts cumulative size of all compressed data (in bytes)
933
     *
934
     * @deprecated See {{UnifiedArchive::getCompressedSize}}
935
     * @return int
936
     */
937
    public function countCompressedFilesSize()
938
    {
939
        return $this->getCompressedSize();
940
    }
941
942
    /**
943
     * Counts cumulative size of all uncompressed data (bytes)
944
     *
945
     * @deprecated See {{UnifiedArchive::getOriginalSize}}
946
     * @return int
947
     */
948
    public function countUncompressedFilesSize()
949
    {
950
        return $this->getOriginalSize();
951
    }
952
}
953