Passed
Push — 1.1.x ( 3d3019...6d4a67 )
by f
02:55 queued 01:04
created

TarByPhar::createArchive()   C

Complexity

Conditions 13
Paths 53

Size

Total Lines 46
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 18.0493

Importance

Changes 0
Metric Value
eloc 31
c 0
b 0
f 0
dl 0
loc 46
ccs 20
cts 29
cp 0.6897
rs 6.6166
cc 13
nc 53
nop 4
crap 18.0493

How to fix   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 Exception;
5
use FilesystemIterator;
6
use Phar;
7
use PharData;
8
use PharFileInfo;
9
use RecursiveIteratorIterator;
10
use wapmorgan\UnifiedArchive\ArchiveEntry;
11
use wapmorgan\UnifiedArchive\ArchiveInformation;
12
use wapmorgan\UnifiedArchive\Drivers\BasicDriver;
13
use wapmorgan\UnifiedArchive\Exceptions\ArchiveCreationException;
14
use wapmorgan\UnifiedArchive\Exceptions\ArchiveExtractionException;
15
use wapmorgan\UnifiedArchive\Exceptions\ArchiveModificationException;
16
use wapmorgan\UnifiedArchive\Exceptions\UnsupportedOperationException;
17
use wapmorgan\UnifiedArchive\Formats;
18
19
class TarByPhar extends BasicDriver
20
{
21
    /**
22
     * @var false|string
23
     */
24
    protected $archiveFileName;
25
26
    /**
27
     * @var PharData
28
     */
29
    protected $tar;
30
31
    /**
32
     * @var int Flags for iterator
33
     */
34
    const PHAR_FLAGS = FilesystemIterator::UNIX_PATHS;
35
36
    /**
37
     * @return array
38
     */
39 1
    public static function getSupportedFormats()
40
    {
41
        return [
42 1
            Formats::TAR,
43
            Formats::TAR_GZIP,
44
            Formats::TAR_BZIP,
45
//            Formats::ZIP,
46
        ];
47
    }
48
49
    /**
50
     * @param $format
51
     * @return bool
52
     */
53 3
    public static function checkFormatSupport($format)
54
    {
55 3
        $availability = class_exists('\PharData');
56
        switch ($format) {
57 3
            case Formats::TAR:
58
//            case Formats::ZIP:
59 1
                return $availability;
60 2
            case Formats::TAR_GZIP:
61 1
                return $availability && extension_loaded('zlib');
62 1
            case Formats::TAR_BZIP:
63 1
                return $availability && extension_loaded('bz2');
64
        }
65
    }
66
67
    /**
68
     * @inheritDoc
69
     */
70
    public static function getDescription()
71
    {
72
        return 'adapter for ext-phar';
73
    }
74
75
    /**
76
     * @inheritDoc
77
     */
78
    public static function getInstallationInstruction()
79
    {
80
        return 'install `phar` extension and optionally php-extensions (zlib, bzip2)';
81
    }
82
83
    /**
84
     * @inheritDoc
85
     */
86 10
    public function __construct($archiveFileName, $format, $password = null)
87
    {
88 10
        $this->archiveFileName = realpath($archiveFileName);
89 10
        $this->open();
90 10
    }
91
92
    /**
93
     *
94
     */
95 10
    protected function open()
96
    {
97 10
        $this->tar = new PharData($this->archiveFileName, self::PHAR_FLAGS);
98 10
    }
99
100
    /**
101
     * @inheritDoc
102
     */
103 10
    public function getArchiveInformation()
104
    {
105 10
        $information = new ArchiveInformation();
106 10
        $stream_path_length = strlen('phar://'.$this->archiveFileName.'/');
107
        /**
108
         * @var string $i
109
         * @var PharFileInfo $file
110
         */
111 10
        foreach (new RecursiveIteratorIterator($this->tar) as $i => $file) {
112 10
            $information->files[] = substr($file->getPathname(), $stream_path_length);
113 10
            $information->compressedFilesSize += $file->getCompressedSize();
114 10
            $information->uncompressedFilesSize += filesize($file->getPathname());
115
        }
116 10
        return $information;
117
    }
118
119
    /**
120
     * @inheritDoc
121
     */
122
    public function getFileNames()
123
    {
124
        $files = [];
125
126
        $stream_path_length = strlen('phar://'.$this->archiveFileName.'/');
127
        foreach (new RecursiveIteratorIterator($this->tar) as $i => $file) {
128
            $files[] = substr($file->getPathname(), $stream_path_length);
129
        }
130
131
        return $files;
132
    }
133
134
    /**
135
     * @inheritDoc
136
     */
137
    public function isFileExists($fileName)
138
    {
139
        try {
140
            $this->tar->offsetGet($fileName);
141
            return true;
142
        } catch (Exception $e) {
143
            return false;
144
        }
145
    }
146
147
    /**
148
     * @inheritDoc
149
     */
150 3
    public function getFileData($fileName)
151
    {
152
        /** @var \PharFileInfo $entry_info */
153 3
        $entry_info = $this->tar->offsetGet($fileName);
154 3
        return new ArchiveEntry($fileName, $entry_info->getSize(), filesize($entry_info->getPathname()),
155 3
            0, $entry_info->isCompressed());
156
    }
157
158
    /**
159
     * @inheritDoc
160
     */
161 4
    public function getFileContent($fileName)
162
    {
163 4
        return $this->tar->offsetGet($fileName)->getContent();
164
    }
165
166
    /**
167
     * @inheritDoc
168
     */
169 3
    public function getFileStream($fileName)
170
    {
171 3
        return self::wrapStringInStream($this->tar->offsetGet($fileName)->getContent());
172
    }
173
174
    /**
175
     * @inheritDoc
176
     */
177
    public function extractFiles($outputFolder, array $files)
178
    {
179
        $result = $this->tar->extractTo($outputFolder, $files, true);
180
        if ($result === false) {
181
            throw new ArchiveExtractionException('Error when extracting from '.$this->archiveFileName);
182
        }
183
        return count($files);
184
    }
185
186
    /**
187
     * @inheritDoc
188
     */
189
    public function extractArchive($outputFolder)
190
    {
191
        $result = $this->tar->extractTo($outputFolder, null, true);
192
        if ($result === false) {
193
            throw new ArchiveExtractionException('Error when extracting from '.$this->archiveFileName);
194
        }
195
196
        return 1;
197
    }
198
199
    /**
200
     * @inheritDoc
201
     */
202 1
    public function deleteFiles(array $files)
203
    {
204 1
        $deleted = 0;
205
206 1
        foreach ($files as $i => $file) {
207 1
            if ($this->tar->delete($file))
208 1
                $deleted++;
209
        }
210
211 1
        $this->tar = null;
212 1
        $this->open();
213
214 1
        return $deleted;
215
    }
216
217
    /**
218
     * @inheritDoc
219
     */
220 1
    public function addFiles(array $files)
221
    {
222 1
        $added = 0;
223
        try {
224 1
            foreach ($files as $localName => $filename) {
225 1
                if (is_null($filename)) {
226
                    $this->tar->addEmptyDir($localName);
227
                } else {
228 1
                    $this->tar->addFile($filename, $localName);
229 1
                    $added++;
230
                }
231
            }
232
        } catch (Exception $e) {
233
            throw new ArchiveModificationException('Could not add file "'.$filename.'": '.$e->getMessage(), $e->getCode());
234
        }
235 1
        $this->tar = null;
236
        // reopen to refresh files list properly
237 1
        $this->open();
238 1
        return $added;
239
    }
240
241
    /**
242
     * @param $format
243
     * @return bool
244
     */
245 1
    public static function canCreateArchive($format)
246
    {
247 1
        return true;
248
    }
249
250
    /**
251
     * @param $format
252
     * @return bool
253
     */
254 1
    public static function canAddFiles($format)
255
    {
256 1
        return true;
257
    }
258
259
    /**
260
     * @param $format
261
     * @return bool
262
     */
263 1
    public static function canDeleteFiles($format)
264
    {
265 1
        return true;
266
    }
267
268
    /**
269
     * @param array $files
270
     * @param string $archiveFileName
271
     * @param int $compressionLevel
272
     * @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...
273
     * @return int
274
     * @throws ArchiveCreationException
275
     * @throws UnsupportedOperationException
276
     */
277 1
    public static function createArchive(array $files, $archiveFileName, $compressionLevel = self::COMPRESSION_AVERAGE, $password = null)
278
    {
279 1
        if ($password !== null) {
0 ignored issues
show
introduced by
The condition $password !== null is always false.
Loading history...
280
            throw new UnsupportedOperationException('One-file format ('.__CLASS__.') could not encrypt an archive');
281
        }
282
283 1
        if (preg_match('~^(.+)\.(tar\.(gz|bz2))$~i', $archiveFileName, $match)) {
284
            $ext = $match[2];
285
            $basename = $match[1];
286
        } else {
287 1
            $ext = pathinfo($archiveFileName, PATHINFO_EXTENSION);
288 1
            $basename = dirname($archiveFileName).'/'.basename($archiveFileName, '.'.$ext);
0 ignored issues
show
Bug introduced by
Are you sure $ext of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

288
            $basename = dirname($archiveFileName).'/'.basename($archiveFileName, '.'./** @scrutinizer ignore-type */ $ext);
Loading history...
289
        }
290 1
        $tar = new PharData($basename.'.tar', 0, null, Phar::TAR);
291
292
        try {
293 1
            foreach ($files as $localName => $filename) {
294 1
                if (is_null($filename)) {
295 1
                    if (!in_array($localName, ['/', ''], true)) {
296 1
                        if ($tar->addEmptyDir($localName) === false) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $tar->addEmptyDir($localName) targeting Phar::addEmptyDir() 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...
297 1
                            throw new ArchiveCreationException('Error when adding directory '.$localName.' to archive');
298
                        }
299
                    }
300
                } else {
301 1
                    if ($tar->addFile($filename, $localName) === false) {
0 ignored issues
show
Bug introduced by
Are you sure the usage of $tar->addFile($filename, $localName) targeting Phar::addFile() 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...
302 1
                        throw new ArchiveCreationException('Error when adding file '.$localName.' to archive');
303
                    }
304
                }
305
            }
306
        } catch (Exception $e) {
307
            throw new ArchiveCreationException('Error when creating archive: '.$e->getMessage(), $e->getCode(), $e);
308
        }
309
310 1
        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

310
        switch (strtolower(/** @scrutinizer ignore-type */ pathinfo($archiveFileName, PATHINFO_EXTENSION))) {
Loading history...
311 1
            case 'gz':
312 1
            case 'tgz':
313
                $tar->compress(Phar::GZ, $ext);
314
                break;
315 1
            case 'bz2':
316 1
            case 'tbz2':
317
                $tar->compress(Phar::BZ2, $ext);
318
                break;
319
        }
320 1
        $tar = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $tar is dead and can be removed.
Loading history...
321
322 1
        return count($files);
323
    }
324
325
    /**
326
     * @param string $inArchiveName
327
     * @param string $content
328
     * @return bool
329
     */
330
    public function addFileFromString($inArchiveName, $content)
331
    {
332
        $this->tar->addFromString($inArchiveName, $content);
333
        return true;
334
    }
335
}