Passed
Push — master ( e9611b...a3681d )
by f
13:07
created

TarByPear::createArchive()   C

Complexity

Conditions 16
Paths 100

Size

Total Lines 60
Code Lines 39

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 60.6693

Importance

Changes 0
Metric Value
cc 16
eloc 39
c 0
b 0
f 0
nc 100
nop 6
dl 0
loc 60
rs 5.5666
ccs 15
cts 34
cp 0.4412
crap 60.6693

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
namespace wapmorgan\UnifiedArchive\Drivers;
3
4
use Archive_Tar;
0 ignored issues
show
Bug introduced by
The type Archive_Tar was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
5
use Vtiful\Kernel\Format;
6
use wapmorgan\UnifiedArchive\ArchiveEntry;
7
use wapmorgan\UnifiedArchive\ArchiveInformation;
8
use wapmorgan\UnifiedArchive\Drivers\BasicDriver;
9
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
10
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
11
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
12
use wapmorgan\UnifiedArchive\Exceptions\NonExistentArchiveFileException;
13
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
14
use wapmorgan\UnifiedArchive\Formats;
15
use wapmorgan\UnifiedArchive\LzwStreamWrapper;
16
17
class TarByPear extends BasicDriver
18
{
19
    const TYPE = self::TYPE_PURE_PHP;
20
21
    /**
22
     * @var string Full path to archive
23
     */
24
    protected $archiveFileName;
25
26
    /**
27
     * @var Archive_Tar
28
     */
29
    protected $tar;
30
31
    /**
32
     * @var float Overall compression ratio of Tar archive when Archive_Tar is used
33
     */
34
    protected $pearCompressionRatio;
35
36
    /**
37
     * @var array<string, integer> List of files and their index in listContent() result
38
     */
39
    protected $pearFilesIndex;
40
41 1
    protected $pureFilesNumber;
42
43
    /**
44 1
     * @inheritDoc
45
     */
46
    public static function getDescription()
47
    {
48
        return 'php-library for tar';
49
    }
50
51
    public static function isInstalled()
52
    {
53
        return class_exists('\Archive_Tar');
54
    }
55
56
    /**
57 4
     * @inheritDoc
58
     */
59 4
    public static function getInstallationInstruction()
60 4
    {
61
        return 'install library [pear/archive_tar]: `composer require pear/archive_tar`' . "\n"  . ' and optionally php-extensions (zlib, bz2)';
62 4
    }
63 1
64
    /**
65 3
     * @return array
66 1
     */
67
    public static function getSupportedFormats()
68 2
    {
69 1
        return [
70
            Formats::TAR,
71 1
            Formats::TAR_GZIP,
72 1
            Formats::TAR_BZIP,
73
            Formats::TAR_LZMA,
74
            Formats::TAR_LZW,
75
        ];
76
    }
77
78
    /**
79
     * @param $format
80
     * @return array
81
     * @throws \Exception
82
     */
83
    public static function checkFormatSupport($format)
84
    {
85
        if (!static::isInstalled()) {
86
            return [];
87
        }
88
89
        $abilities = [
90
            BasicDriver::OPEN,
91
            BasicDriver::EXTRACT_CONTENT,
92
            BasicDriver::APPEND,
93
            BasicDriver::CREATE,
94
        ];
95
96
        switch ($format) {
97
            case Formats::TAR:
98
                return $abilities;
99
100
            case Formats::TAR_GZIP:
101
                if (!extension_loaded('zlib')) {
102
                    return [];
103
                }
104
                return $abilities;
105
106
            case Formats::TAR_BZIP:
107
                if (!extension_loaded('bz2')) {
108
                    return [];
109
                }
110
                return $abilities;
111
112
            case Formats::TAR_LZMA:
113
                if (!extension_loaded('xz')) {
114
                    return [];
115
                }
116
                return $abilities;
117
118
            case Formats::TAR_LZW:
119
                if (!LzwStreamWrapper::isBinaryAvailable()) {
120
                    return [];
121
                }
122
                return $abilities;
123
        }
124
    }
125
126
    /**
127
     * @param array $files
128
     * @param string $archiveFileName
129
     * @param int $archiveFormat
130
     * @param int $compressionLevel
131
     * @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...
132
     * @param $fileProgressCallable
133
     * @return int
134
     * @throws ArchiveCreationException
135
     * @throws UnsupportedOperationException
136
     */
137
    public static function createArchive(
138
        array $files,
139
        $archiveFileName,
140
        $archiveFormat,
141
        $compressionLevel = self::COMPRESSION_AVERAGE,
142
        $password = null,
143
        $fileProgressCallable = null
144
    )
145
    {
146
        if ($password !== null) {
0 ignored issues
show
introduced by
The condition $password !== null is always false.
Loading history...
147
            throw new UnsupportedOperationException('One-file format ('.__CLASS__.') could not encrypt an archive');
148
        }
149
150
        if ($fileProgressCallable !== null && !is_callable($fileProgressCallable)) {
151
            throw new ArchiveCreationException('File progress callable is not callable');
152
        }
153
154
        $compression = null;
155
        switch (strtolower(pathinfo($archiveFileName, PATHINFO_EXTENSION))) {
0 ignored issues
show
Bug introduced by
It seems like pathinfo($archiveFileNam...ers\PATHINFO_EXTENSION) can also be of type array; 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

155
        switch (strtolower(/** @scrutinizer ignore-type */ pathinfo($archiveFileName, PATHINFO_EXTENSION))) {
Loading history...
156 3
            case 'gz':
157
            case 'tgz':
158 3
                $compression = 'gz';
159 3
                break;
160 3
            case 'bz2':
161
            case 'tbz2':
162 3
                $compression = 'bz2';
163
                break;
164
            case 'xz':
165 3
                $compression = 'lzma2';
166
                break;
167
            case 'z':
168
                $tar_aname = 'compress.lzw://' . $archiveFileName;
169 3
                break;
170
        }
171
172
        if (isset($tar_aname))
173 3
            $tar = new Archive_Tar($tar_aname, $compression);
174 3
        else
175 3
            $tar = new Archive_Tar($archiveFileName, $compression);
176
177
        $current_file = 0;
178
        $total_files = count($files);
179
        foreach ($files as $localName => $filename) {
180
            $remove_dir = dirname($filename);
181
            $add_dir = dirname($localName);
182
183
            if (is_null($filename)) {
184
                if ($tar->addString($localName, '') === false)
185
                    throw new ArchiveCreationException('Error when adding directory '.$localName.' to archive');
186 3
            } else {
187
                if ($tar->addModify($filename, $add_dir, $remove_dir) === false)
188
                    throw new ArchiveCreationException('Error when adding file '.$filename.' to archive');
189
            }
190
            if ($fileProgressCallable !== null) {
191 3
                call_user_func_array($fileProgressCallable, [$current_file++, $total_files, $filename, $localName]);
192
            }
193 3
        }
194 3
        $tar = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $tar is dead and can be removed.
Loading history...
195
196 3
        return count($files);
197
    }
198 3
199
    /**
200
     * @inheritDoc
201
     */
202 3
    public function __construct($archiveFileName, $format, $password = null)
203 3
    {
204 3
        $this->archiveFileName = realpath($archiveFileName);
205 3
        $this->open($format);
206 3
    }
207
208
    protected function open($archiveType)
209 3
    {
210 3
        switch ($archiveType) {
211 3
            case Formats::TAR_GZIP:
212
                $this->tar = new Archive_Tar($this->archiveFileName, 'gz');
213 3
                break;
214
215
            case Formats::TAR_BZIP:
216
                $this->tar = new Archive_Tar($this->archiveFileName, 'bz2');
217
                break;
218
219
            case Formats::TAR_LZMA:
220
                $this->tar = new Archive_Tar($this->archiveFileName, 'lzma2');
221
                break;
222
223
            case Formats::TAR_LZW:
224
                LzwStreamWrapper::registerWrapper();
225
                $this->tar = new Archive_Tar('compress.lzw://' . $this->archiveFileName);
226
                break;
227
228
            default:
229
                $this->tar = new Archive_Tar($this->archiveFileName);
230
                break;
231
        }
232
    }
233
234
    /**
235
     * @inheritDoc
236
     */
237
    public function getArchiveInformation()
238
    {
239
        $information = new ArchiveInformation();
240
        $this->pearFilesIndex = [];
241
        $this->pureFilesNumber = 0;
242
243
        foreach ($this->tar->listContent() as $i => $file) {
244
            // BUG workaround: http://pear.php.net/bugs/bug.php?id=20275
245
            if ($file['filename'] === 'pax_global_header') {
246 1
                continue;
247
            }
248 1
            // skip directories
249
            if ($file['typeflag'] == '5' || substr($file['filename'], -1) === '/')
250
                continue;
251 1
            $information->files[] = $file['filename'];
252
            $information->uncompressedFilesSize += $file['size'];
253 1
            $this->pearFilesIndex[$file['filename']] = $i;
254 1
            $this->pureFilesNumber++;
255
        }
256
257 1
        $information->compressedFilesSize = filesize($this->archiveFileName);
258 1
        $this->pearCompressionRatio = $information->uncompressedFilesSize != 0
259
            ? ceil($information->compressedFilesSize / $information->uncompressedFilesSize)
260 1
            : 1;
261 1
        return $information;
262 1
    }
263
264
    /**
265
     * @inheritDoc
266
     */
267
    public function getFileNames()
268 1
    {
269
        $files = [];
270 1
271
        $Content = $this->tar->listContent();
272
        foreach ($Content as $i => $file) {
273 1
            // BUG workaround: http://pear.php.net/bugs/bug.php?id=20275
274
            if ($file['filename'] === 'pax_global_header') {
275
                continue;
276
            }
277
            $files[] = $file['filename'];
278
        }
279 1
280
        return $files;
281 1
    }
282
283
    /**
284 1
     * @inheritDoc
285
     */
286
    public function isFileExists($fileName)
287
    {
288
        return isset($this->pearFilesIndex[$fileName]);
289
    }
290
291
    /**
292
     * @inheritDoc
293
     */
294
    public function getFileData($fileName)
295
    {
296
        if (!isset($this->pearFilesIndex[$fileName]))
297
            throw new NonExistentArchiveFileException('File '.$fileName.' is not found in archive files list');
298
299
        $index = $this->pearFilesIndex[$fileName];
300
301
        $files_list = $this->tar->listContent();
302
        if (!isset($files_list[$index]))
303
            throw new NonExistentArchiveFileException('File '.$fileName.' is not found in Tar archive');
304
305
        $data = $files_list[$index];
306
        unset($files_list);
307
308
        return new ArchiveEntry($fileName, $data['size'] / $this->pearCompressionRatio,
0 ignored issues
show
Bug introduced by
$data['size'] / $this->pearCompressionRatio of type double is incompatible with the type integer expected by parameter $compressedSize of wapmorgan\UnifiedArchive...iveEntry::__construct(). ( Ignorable by Annotation )

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

308
        return new ArchiveEntry($fileName, /** @scrutinizer ignore-type */ $data['size'] / $this->pearCompressionRatio,
Loading history...
309
            $data['size'], $data['mtime'], in_array(strtolower(pathinfo($this->archiveFileName,
0 ignored issues
show
Bug introduced by
It seems like pathinfo($this->archiveF...ers\PATHINFO_EXTENSION) can also be of type array; 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

309
            $data['size'], $data['mtime'], in_array(strtolower(/** @scrutinizer ignore-type */ pathinfo($this->archiveFileName,
Loading history...
310
                PATHINFO_EXTENSION)), ['gz', 'bz2', 'xz', 'z']));
311
    }
312
313
    /**
314
     * @inheritDoc
315
     */
316
    public function getFileContent($fileName)
317
    {
318
        if (!isset($this->pearFilesIndex[$fileName]))
319
            throw new NonExistentArchiveFileException('File '.$fileName.' is not found in archive files list');
320
321
        return $this->tar->extractInString($fileName);
322
    }
323
324
    /**
325
     * @inheritDoc
326
     */
327
    public function getFileStream($fileName)
328
    {
329
        if (!isset($this->pearFilesIndex[$fileName]))
330
            throw new NonExistentArchiveFileException('File '.$fileName.' is not found in archive files list');
331
332
        return self::wrapStringInStream($this->tar->extractInString($fileName));
333
    }
334
335
    /**
336
     * @inheritDoc
337
     */
338
    public function extractFiles($outputFolder, array $files)
339
    {
340
        $result = $this->tar->extractList($files, $outputFolder);
341
        if ($result === false) {
342
            throw new ArchiveExtractionException('Error when extracting from '.$this->archiveFileName);
343
        }
344
345
        return count($files);
346
    }
347
348
    /**
349
     * @inheritDoc
350
     */
351
    public function extractArchive($outputFolder)
352
    {
353
        $result = $this->tar->extract($outputFolder);
354
        if ($result === false) {
355
            throw new ArchiveExtractionException('Error when extracting from '.$this->archiveFileName);
356
        }
357
358
        return $this->pureFilesNumber;
359
    }
360
361
    /**
362
     * @inheritDoc
363
     */
364
    public function addFiles(array $files)
365
    {
366
        $added = 0;
367
        foreach ($files as $localName => $filename) {
368
            $remove_dir = dirname($filename);
369
            $add_dir = dirname($localName);
370
            if (is_null($filename)) {
371
                if ($this->tar->addString($localName, "") === false) {
372
                    throw new ArchiveModificationException('Could not add directory "'.$filename.'": '.$this->tar->error_object->message, $this->tar->error_object->code);
373
                }
374
            } else {
375
                if ($this->tar->addModify($filename, $add_dir, $remove_dir) === false) {
376
                    throw new ArchiveModificationException('Could not add file "'.$filename.'": '.$this->tar->error_object->message, $this->tar->error_object->code);
377
                }
378
                $added++;
379
            }
380
        }
381
        return $added;
382
    }
383
384
    /**
385
     * @param string $inArchiveName
386
     * @param string $content
387
     * @return bool|true
388
     */
389
    public function addFileFromString($inArchiveName, $content)
390
    {
391
        return $this->tar->addString($inArchiveName, $content);
392
    }
393
}