Passed
Push — master ( 77631b...eb0eba )
by f
01:48
created

UnifiedArchive   F

Complexity

Total Complexity 99

Size/Duplication

Total Lines 762
Duplicated Lines 0 %

Test Coverage

Coverage 58.6%

Importance

Changes 55
Bugs 2 Features 2
Metric Value
wmc 99
eloc 171
dl 0
loc 762
ccs 109
cts 186
cp 0.586
rs 2
c 55
b 2
f 2

45 Methods

Rating   Name   Duplication   Size   Complexity  
A scanArchive() 0 7 1
A open() 0 12 4
A __construct() 0 14 2
A __destruct() 0 3 1
A canOpen() 0 4 2
A setComment() 0 3 1
A countFiles() 0 3 1
A getPclZipInterface() 0 3 1
A getFormat() 0 3 1
A getSize() 0 3 1
A getDriver() 0 3 1
A getMimeType() 0 3 1
A getComment() 0 3 1
A canCreateType() 0 3 1
A getOriginalSize() 0 3 1
A deleteFiles() 0 16 5
A getArchiveFormat() 0 3 1
A getArchiveSize() 0 3 1
B importFilesFromDir() 0 14 7
A detectArchiveType() 0 3 1
A archiveDirectory() 0 6 3
A addFile() 0 8 3
A expandFileList() 0 11 4
A addDirectory() 0 8 4
A countUncompressedFilesSize() 0 3 1
A addFiles() 0 10 2
A isFileExists() 0 3 1
B createFilesList() 0 37 11
A getArchiveType() 0 3 1
A addFileFromString() 0 5 1
A getFileStream() 0 7 2
A getFileResource() 0 3 1
A getFileNames() 0 11 4
A canOpenArchive() 0 3 1
A archiveFile() 0 7 2
A hasFile() 0 3 1
A getFileData() 0 7 2
A canOpenType() 0 3 1
A getFileContent() 0 7 2
A countCompressedFilesSize() 0 3 1
A getCompressedSize() 0 3 1
A extractFiles() 0 19 5
A prepareForArchiving() 0 22 4
A archiveFiles() 0 17 5
A getDriverType() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like UnifiedArchive often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use UnifiedArchive, and based on these observations, apply Extract Interface, too.

1
<?php
2
namespace wapmorgan\UnifiedArchive;
3
4
use InvalidArgumentException;
5
use wapmorgan\UnifiedArchive\Drivers\BasicDriver;
6
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
7
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
8
use wapmorgan\UnifiedArchive\Exceptions\EmptyFileListException;
9
use wapmorgan\UnifiedArchive\Exceptions\FileAlreadyExistsException;
10
use wapmorgan\UnifiedArchive\Exceptions\NonExistentArchiveFileException;
11
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedArchiveException;
12
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
13
14
/**
15
 * Class which represents archive in one of supported formats.
16
 */
17
class UnifiedArchive
18
{
19
    const VERSION = '1.1.3';
20
21
    /** @var string Type of current archive */
22
    protected $format;
23
24
    /** @var BasicDriver Adapter for current archive */
25
    protected $archive;
26
27
    /** @var array List of files in current archive */
28
    protected $files;
29
30
    /** @var int Number of files in archive */
31
    protected $filesQuantity;
32
33
    /** @var int Cumulative size of uncompressed files */
34
    protected $uncompressedFilesSize;
35
36
    /** @var int Cumulative size of compressed files */
37
    protected $compressedFilesSize;
38
39
    /** @var int Total size of archive file */
40
    protected $archiveSize;
41
42
    /**
43
     * @var null
44
     */
45
    protected $password;
46
47
    /**
48
     * Creates a UnifiedArchive instance for passed archive
49
     *
50
     * @param string $fileName Archive filename
51
     * @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...
52
     * @return UnifiedArchive|null Returns UnifiedArchive in case of successful reading of the file
53
     * @throws UnsupportedOperationException
54
     */
55 23
    public static function open($fileName, $password = null)
56
    {
57 23
        if (!file_exists($fileName) || !is_readable($fileName)) {
58
            throw new InvalidArgumentException('Could not open file: ' . $fileName.' is not readable');
59
        }
60
61 23
        $format = Formats::detectArchiveFormat($fileName);
62 23
        if (!Formats::canOpen($format)) {
63
            return null;
64
        }
65
66 23
        return new static($fileName, $format, $password);
67
    }
68
69
    /**
70
     * Checks whether archive can be opened with current system configuration
71
     *
72
     * @param string $fileName Archive filename
73
     * @return bool
74
     */
75 21
    public static function canOpen($fileName)
76
    {
77 21
        $format = Formats::detectArchiveFormat($fileName);
78 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

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

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

474
            'numberOfFiles' => count(/** @scrutinizer ignore-type */ $files_list),
Loading history...
475 2
            'files' => $files_list,
476 2
            'type' => $archiveType,
477
        ];
478
    }
479
480
    /**
481
     * Creates an archive with passed files list
482
     *
483
     * @param string|string[]|array<string,string> $fileOrFiles List of files. Can be one of three formats:
484
     *                             1. A string containing path to file or directory.
485
     *                                  File will have it's basename.
486
     *                                  `UnifiedArchive::archiveFiles('/etc/php.ini', 'archive.zip)` will store
487
     * file with 'php.ini' name.
488
     *                                  Directory contents will be stored in archive root.
489
     *                                  `UnifiedArchive::archiveFiles('/var/log/', 'archive.zip')` will store all
490
     * directory contents in archive root.
491
     *                             2. An array with strings containing pats to files or directories.
492
     *                                  Files and directories will be stored with full paths.
493
     *                                  `UnifiedArchive::archiveFiles(['/etc/php.ini', '/var/log/'], 'archive.zip)`
494
     * will preserve full paths.
495
     *                             3. An array with strings where keys are strings.
496
     *                                  Files will have name from key.
497
     *                                  Directories contents will have prefix from key.
498
     *                                  `UnifiedArchive::archiveFiles(['doc.txt' => 'very_long_name_of_document.txt',
499
     *  'static' => '/var/www/html/static/'], 'archive.zip')`
500
     *
501
     * @param string $archiveName File name of archive. Type of archive will be determined by it's name.
502
     * @param int $compressionLevel Level of compression
503
     * @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...
504
     * @return int Count of stored files is returned.
505
     * @throws FileAlreadyExistsException
506
     * @throws UnsupportedOperationException
507
     */
508 2
    public static function archiveFiles($fileOrFiles, $archiveName, $compressionLevel = BasicDriver::COMPRESSION_AVERAGE, $password = null)
509
    {
510 2
        if (file_exists($archiveName))
511
            throw new FileAlreadyExistsException('Archive '.$archiveName.' already exists!');
512
513 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

513
        $info = static::prepareForArchiving(/** @scrutinizer ignore-type */ $fileOrFiles, $archiveName);
Loading history...
514
515 2
        if (!Formats::canCreate($info['type']))
516
            throw new UnsupportedArchiveException('Unsupported archive type: '.$info['type'].' of archive '.$archiveName);
517
518 2
        if ($password !== null && !Formats::canEncrypt($info['type']))
0 ignored issues
show
introduced by
The condition $password !== null is always false.
Loading history...
519
            throw new UnsupportedOperationException('Archive type '.$info['type'].' can not be encrypted');
520
521
        /** @var BasicDriver $driver */
522 2
        $driver = Formats::getFormatDriver($info['type'], true);
523
524 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

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