Passed
Push — 0.1.x ( 81ff64...72f342 )
by f
01:32
created

Tar::createArchiveForPear()   C

Complexity

Conditions 12
Paths 70

Size

Total Lines 40
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 12
eloc 31
nc 70
nop 2
dl 0
loc 40
rs 6.9666
c 0
b 0
f 0

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\Formats;
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 Exception;
6
use FilesystemIterator;
7
use Phar;
8
use PharData;
9
use RecursiveIteratorIterator;
10
use wapmorgan\UnifiedArchive\ArchiveEntry;
11
use wapmorgan\UnifiedArchive\ArchiveInformation;
12
use wapmorgan\UnifiedArchive\UnsupportedOperationException;
13
14
/**
15
 * Tar format handler
16
 * @package wapmorgan\UnifiedArchive\Formats
17
 */
18
class Tar extends BasicFormat
19
{
20
    const TAR = 'tar';
21
    const TAR_GZIP = 'tgz';
22
    const TAR_BZIP = 'tbz2';
23
    const TAR_LZMA = 'txz';
24
    const TAR_LZW = 'tar.z';
25
26
    /** @var bool */
27
    static protected $enabledPearTar;
28
29
    /** @var bool */
30
    static protected $enabledPharData;
31
    /**
32
     * Checks system configuration for available Tar-manipulation libraries
33
     */
34
    protected static function checkRequirements()
35
    {
36
        if (self::$enabledPharData === null || self::$enabledPearTar === null) {
0 ignored issues
show
introduced by
The condition self::enabledPearTar === null is always false.
Loading history...
37
            self::$enabledPearTar = class_exists('\Archive_Tar');
38
            self::$enabledPharData = class_exists('\PharData');
39
        }
40
    }
41
42
    /**
43
     * Checks whether archive can be opened with current system configuration
44
     * @param $archiveFileName
45
     * @return boolean
46
     */
47
//    public static function canOpenArchive($archiveFileName)
48
//    {
49
//        self::checkRequirements();
50
//
51
//        $type = self::detectArchiveType($archiveFileName);
52
//        if ($type !== false) {
53
//            return self::canOpenType($type);
54
//        }
55
//
56
//        return false;
57
//    }
58
59
    /**
60
     * Detect archive type by its filename or content.
61
     * @param $archiveFileName
62
     * @param bool $contentCheck
63
     * @return string|boolean One of TarArchive type constants OR false if type is not detected
64
     */
65
    public static function detectArchiveType($archiveFileName, $contentCheck = true)
66
    {
67
        // by file name
68
        if (preg_match('~\.(?<ext>tar|tgz|tbz2|txz|tar\.(gz|bz2|xz|z))$~', strtolower($archiveFileName), $match)) {
69
            switch ($match['ext']) {
70
                case 'tar':
71
                    return self::TAR;
72
73
                case 'tgz':
74
                case 'tar.gz':
75
                    return self::TAR_GZIP;
76
77
                case 'tbz2':
78
                case 'tar.bz2':
79
                    return self::TAR_BZIP;
80
81
                case 'txz':
82
                case 'tar.xz':
83
                    return self::TAR_LZMA;
84
85
                case 'tar.z':
86
                    return self::TAR_LZW;
87
            }
88
        }
89
90
        // by content
91
        if ($contentCheck) {
92
            $mime_type = mime_content_type($archiveFileName);
93
            switch ($mime_type) {
94
                case 'application/x-tar':
95
                    return self::TAR;
96
                case 'application/x-gtar':
97
                    return self::TAR_GZIP;
98
            }
99
        }
100
101
        return false;
102
    }
103
104
    /**
105
     * Checks whether specific archive type can be opened with current system configuration
106
     * @param $type
107
     * @return boolean
108
     */
109
//    public static function canOpenType($type)
110
//    {
111
//        self::checkRequirements();
112
//        switch ($type) {
113
//            case self::TAR:
114
//                return self::$enabledPearTar || self::$enabledPharData;
115
//
116
//            case self::TAR_GZIP:
117
//                return (self::$enabledPearTar || self::$enabledPharData) && extension_loaded('zlib');
118
//
119
//            case self::TAR_BZIP:
120
//                return (self::$enabledPearTar || self::$enabledPharData) && extension_loaded('bz2');
121
//
122
//
123
//            case self::TAR_LZMA:
124
//                return self::$enabledPearTar && extension_loaded('lzma2');
125
//
126
//            case self::TAR_LZW:
127
//                return self::$enabledPearTar && LzwStreamWrapper::isBinaryAvailable();
128
//        }
129
//
130
//        return false;
131
//    }
132
133
    /**
134
     * @param array $files
135
     * @param string $archiveFileName
136
     * @return false|int
137
     * @throws Exception
138
     */
139
    public static function createArchive(array $files, $archiveFileName)
140
    {
141
        static::checkRequirements();
142
143
        if (static::$enabledPearTar)
144
            return static::createArchiveForPear($files, $archiveFileName);
145
146
        if (static::$enabledPharData)
147
            return static::createArchiveForPhar($files, $archiveFileName);
0 ignored issues
show
Bug Best Practice introduced by
The expression return static::createArc...iles, $archiveFileName) returns the type boolean which is incompatible with the documented return type false|integer.
Loading history...
148
149
        throw new Exception('Archive_Tar nor PharData not available');
150
    }
151
152
    /**
153
     * Creates an archive via Pear library
154
     * @param array $files
155
     * @param $archiveFileName
156
     * @return bool|int
157
     */
158
    protected static function createArchiveForPear(array $files, $archiveFileName)
159
    {
160
        $compression = null;
161
        switch (strtolower(pathinfo($archiveFileName, PATHINFO_EXTENSION))) {
162
            case 'gz':
163
            case 'tgz':
164
                $compression = 'gz';
165
                break;
166
            case 'bz2':
167
            case 'tbz2':
168
                $compression = 'bz2';
169
                break;
170
            case 'xz':
171
                $compression = 'lzma2';
172
                break;
173
            case 'z':
174
                $tar_aname = 'compress.lzw://' . $archiveFileName;
175
                break;
176
        }
177
178
        if (isset($tar_aname))
179
            $tar = new Archive_Tar($tar_aname, $compression);
180
        else
181
            $tar = new Archive_Tar($archiveFileName, $compression);
182
183
        foreach ($files  as $localName => $filename) {
184
            $remove_dir = dirname($filename);
185
            $add_dir = dirname($localName);
186
187
            if (is_null($filename)) {
188
                if ($tar->addString($localName, '') === false)
189
                    return false;
190
            } else {
191
                if ($tar->addModify($filename, $add_dir, $remove_dir)
192
                    === false) return false;
193
            }
194
        }
195
        $tar = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $tar is dead and can be removed.
Loading history...
196
197
        return count($files);
198
    }
199
200
    /**
201
     * Creates an archive via Phar library
202
     * @param array $files
203
     * @param $archiveFileName
204
     * @return bool
205
     */
206
    protected static function createArchiveForPhar(array $files, $archiveFileName)
207
    {
208
        if (preg_match('~^(.+)\.(tar\.(gz|bz2))$~i', $archiveFileName, $match)) {
209
            $ext = $match[2];
210
            $basename = $match[1];
211
        } else {
212
            $ext = pathinfo($archiveFileName, PATHINFO_EXTENSION);
213
            $basename = dirname($archiveFileName).'/'.basename($archiveFileName, '.'.$ext);
214
        }
215
        $tar = new PharData($basename.'.tar', 0, null, Phar::TAR);
216
217
        try {
218
            foreach ($files as $localName => $filename) {
219
                if (is_null($filename)) {
220
                    if (!in_array($localName, ['/', ''], true)) {
221
                        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...
222
                            return false;
223
                        }
224
                    }
225
                } else {
226
                    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...
227
                        return false;
228
                    }
229
                }
230
            }
231
        } catch (Exception $e) {
232
            return false;
233
        }
234
235
        switch (strtolower(pathinfo($archiveFileName, PATHINFO_EXTENSION))) {
236
            case 'gz':
237
            case 'tgz':
238
                $tar->compress(Phar::GZ, $ext);
239
                break;
240
            case 'bz2':
241
            case 'tbz2':
242
                $tar->compress(Phar::BZ2, $ext);
243
                break;
244
        }
245
        $tar = null;
0 ignored issues
show
Unused Code introduced by
The assignment to $tar is dead and can be removed.
Loading history...
246
247
        return count($files);
0 ignored issues
show
Bug Best Practice introduced by
The expression return count($files) returns the type integer which is incompatible with the documented return type boolean.
Loading history...
248
    }
249
250
    /** @var string Full path to archive */
251
    protected $archiveFileName;
252
253
    /** @var string Full path to archive */
254
    protected $archiveType;
255
256
    /** @var Archive_Tar|PharData */
257
    protected $tar;
258
259
    /** @var float Overall compression ratio of Tar archive when Archive_Tar is used */
260
    protected $pearCompressionRatio;
261
262
    /** @var array<string, integer> List of files and their index in listContent() result */
263
    protected $pearFilesIndex;
264
265
    /** @var int Flags for iterator */
266
    const PHAR_FLAGS = FilesystemIterator::UNIX_PATHS;
267
268
    /**
269
     * Tar format constructor.
270
     *
271
     * @param string $archiveFileName
272
     * @throws \Exception
273
     */
274
    public function __construct($archiveFileName)
275
    {
276
        static::checkRequirements();
277
278
        $this->archiveFileName = realpath($archiveFileName);
279
        $this->archiveType = static::detectArchiveType($this->archiveFileName);
0 ignored issues
show
Documentation Bug introduced by
It seems like static::detectArchiveType($this->archiveFileName) can also be of type false. However, the property $archiveType is declared as type string. 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...
280
        if ($this->archiveType === false)
281
            throw new \Exception('Could not detect type for archive '.$this->archiveFileName);
282
        $this->open($this->archiveType);
283
    }
284
285
    /**
286
     * Tar destructor
287
     */
288
    public function __destruct()
289
    {
290
        $this->tar = null;
291
    }
292
293
    /**
294
     * @param $archiveType
295
     * @throws Exception
296
     */
297
    protected function open($archiveType)
298
    {
299
        switch ($archiveType) {
300
            case self::TAR_GZIP:
301
                if (self::$enabledPharData) {
302
                    $this->tar = new PharData($this->archiveFileName, self::PHAR_FLAGS);
303
                } else {
304
                    $this->tar = new Archive_Tar($this->archiveFileName, 'gz');
305
                }
306
                break;
307
308
            case self::TAR_BZIP:
309
                if (self::$enabledPharData) {
310
                    $this->tar = new PharData($this->archiveFileName, self::PHAR_FLAGS);
311
                } else {
312
                    $this->tar = new Archive_Tar($this->archiveFileName, 'bz2');
313
                }
314
                break;
315
316
            case self::TAR_LZMA:
317
                if (!self::$enabledPharData) {
318
                    throw new Exception('Archive_Tar not available');
319
                }
320
                $this->tar = new Archive_Tar($this->archiveFileName, 'lzma2');
321
                break;
322
323
            case self::TAR_LZW:
324
                if (!self::$enabledPharData) {
325
                    throw new Exception('Archive_Tar not available');
326
                }
327
                $this->tar = new Archive_Tar('compress.lzw://' . $this->archiveFileName);
328
                break;
329
330
            default:
331
                if (self::$enabledPharData) {
332
                    $this->tar = new PharData($this->archiveFileName, self::PHAR_FLAGS, null, Phar::TAR);
333
                } else {
334
                    $this->tar = new Archive_Tar($this->archiveFileName);
335
                }
336
                break;
337
        }
338
    }
339
340
    /**
341
     * @return ArchiveInformation
342
     */
343
    public function getArchiveInformation()
344
    {
345
        $information = new ArchiveInformation();
346
        if ($this->tar instanceof Archive_Tar) {
347
            $this->pearFilesIndex = [];
348
349
            foreach ($this->tar->listContent() as $i => $file) {
0 ignored issues
show
Bug introduced by
The method listContent() does not exist on PharData. ( Ignorable by Annotation )

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

349
            foreach ($this->tar->/** @scrutinizer ignore-call */ listContent() as $i => $file) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
350
                // BUG workaround: http://pear.php.net/bugs/bug.php?id=20275
351
                if ($file['filename'] === 'pax_global_header') {
352
                    continue;
353
                }
354
                $information->files[] = $file['filename'];
355
                $information->uncompressedFilesSize += $file['size'];
356
                $this->pearFilesIndex[$file['filename']] = $i;
357
            }
358
359
            $information->uncompressedFilesSize = filesize($this->archiveFileName);
360
            $this->pearCompressionRatio = $information->uncompressedFilesSize != 0
361
                ? ceil($information->compressedFilesSize / $information->uncompressedFilesSize)
362
                : 1;
363
        }
364
        return $information;
365
    }
366
367
    /**
368
     * @return array
369
     */
370
    public function getFileNames()
371
    {
372
        return $this->tar instanceof Archive_Tar
373
            ? $this->getFileNamesForPear()
374
            : $this->getFileNamesForPhar();
375
    }
376
377
    /**
378
     * @param string $fileName
379
     * @return bool
380
     */
381
    public function isFileExists($fileName)
382
    {
383
        if ($this->tar instanceof Archive_Tar)
384
            return isset($this->pearFilesIndex[$fileName]);
385
386
        try {
387
            $this->tar->offsetGet($fileName);
388
            return true;
389
        } catch (Exception $e) {
390
            return false;
391
        }
392
    }
393
394
    /**
395
     * @param string $fileName
396
     * @return ArchiveEntry|false
397
     * @throws Exception
398
     */
399
    public function getFileData($fileName)
400
    {
401
        if ($this->tar instanceof Archive_Tar) {
402
            if (!isset($this->pearFilesIndex[$fileName]))
403
                throw new Exception('File '.$fileName.' is not found in archive files list');
404
405
            $index = $this->pearFilesIndex[$fileName];
406
407
            $files_list = $this->tar->listContent();
408
            if (!isset($files_list[$index]))
409
                throw new Exception('File '.$fileName.' is not found in Tar archive');
410
411
            $data = $files_list[$index];
412
            unset($files_list);
413
414
            return new ArchiveEntry($fileName, $data['size'] / $this->pearCompressionRatio,
415
                $data['size'], $data['mtime'], in_array(strtolower(pathinfo($this->archiveFileName,
416
                    PATHINFO_EXTENSION)), array('gz', 'bz2', 'xz', 'Z')));
417
        }
418
419
        /** @var \PharFileInfo $entry_info */
420
        $entry_info = $this->tar->offsetGet($fileName);
421
        return new ArchiveEntry($fileName, $entry_info->getSize(), filesize($entry_info->getPathname()),
422
            0, $entry_info->isCompressed());
423
    }
424
425
    /**
426
     * @param string $fileName
427
     * @return string|false
428
     * @throws Exception
429
     */
430
    public function getFileContent($fileName)
431
    {
432
        if ($this->tar instanceof Archive_Tar) {
433
            if (!isset($this->pearFilesIndex[$fileName]))
434
                throw new Exception('File '.$fileName.' is not found in archive files list');
435
436
            return $this->tar->extractInString($fileName);
0 ignored issues
show
Bug introduced by
The method extractInString() does not exist on PharData. ( Ignorable by Annotation )

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

436
            return $this->tar->/** @scrutinizer ignore-call */ extractInString($fileName);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
437
        }
438
439
        return $this->tar->offsetGet($fileName)->getContent();
440
    }
441
442
    /**
443
     * @param string $fileName
444
     * @return bool|resource|string
445
     * @throws Exception
446
     */
447
    public function getFileResource($fileName)
448
    {
449
        $resource = fopen('php://temp', 'r+');
450
        if ($this->tar instanceof Archive_Tar) {
451
            if (!isset($this->pearFilesIndex[$fileName]))
452
                throw new Exception('File '.$fileName.' is not found in archive files list');
453
454
            fwrite($resource, $this->tar->extractInString($fileName));
0 ignored issues
show
Bug introduced by
It seems like $resource can also be of type false; however, parameter $handle of fwrite() does only seem to accept resource, 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

454
            fwrite(/** @scrutinizer ignore-type */ $resource, $this->tar->extractInString($fileName));
Loading history...
455
        } else
456
            fwrite($resource, $this->tar->offsetGet($fileName)->getContent());
457
458
        rewind($resource);
0 ignored issues
show
Bug introduced by
It seems like $resource can also be of type false; however, parameter $handle of rewind() does only seem to accept resource, 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

458
        rewind(/** @scrutinizer ignore-type */ $resource);
Loading history...
459
        return $resource;
460
    }
461
462
    /**
463
     * @param string $outputFolder
464
     * @param array $files
465
     * @return false|int
466
     * @throws Exception
467
     */
468
    public function extractFiles($outputFolder, array $files)
469
    {
470
        if ($this->tar instanceof Archive_Tar) {
471
            $result = $this->tar->extractList($files, $outputFolder);
0 ignored issues
show
Bug introduced by
The method extractList() does not exist on PharData. Did you maybe mean extractTo()? ( Ignorable by Annotation )

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

471
            /** @scrutinizer ignore-call */ 
472
            $result = $this->tar->extractList($files, $outputFolder);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
472
        } else {
473
            $result = $this->tar->extractTo($outputFolder, $files, true);
474
        }
475
476
        if ($result === false) {
477
            throw new Exception('Error when extracting from '.$this->archiveFileName);
478
        }
479
480
        return count($files);
481
    }
482
483
    /**
484
     * @param string $outputFolder
485
     * @return false|int
486
     * @throws Exception
487
     */
488
    public function extractArchive($outputFolder)
489
    {
490
        if ($this->tar instanceof Archive_Tar) {
491
            $result = $this->tar->extract($outputFolder);
0 ignored issues
show
Bug introduced by
The method extract() does not exist on PharData. Did you maybe mean extractTo()? ( Ignorable by Annotation )

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

491
            /** @scrutinizer ignore-call */ 
492
            $result = $this->tar->extract($outputFolder);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
492
        } else {
493
            $result = $this->tar->extractTo($outputFolder, null, true);
494
        }
495
496
        if ($result === false) {
497
            throw new Exception('Error when extracting from '.$this->archiveFileName);
498
        }
499
500
        return 1;
501
    }
502
503
    /**
504
     * @param array $files
505
     * @return false|int
506
     * @throws UnsupportedOperationException
507
     * @throws Exception
508
     */
509
    public function deleteFiles(array $files)
510
    {
511
        if ($this->tar instanceof Archive_Tar)
512
            throw new UnsupportedOperationException();
513
514
        $deleted = 0;
515
516
        foreach ($files as $i => $file) {
517
            if ($this->tar->delete($file))
518
                $deleted++;
519
        }
520
521
        $this->tar = null;
522
        $this->open($this->archiveType);
523
524
        return $deleted;
525
    }
526
527
    /**
528
     * @param array $files
529
     * @return false|int
530
     * @throws Exception
531
     */
532
    public function addFiles(array $files)
533
    {
534
        $added = 0;
535
536
        if ($this->tar instanceof Archive_Tar) {
537
            foreach ($files as $localName => $filename) {
538
                $remove_dir = dirname($filename);
539
                $add_dir = dirname($localName);
540
                if (is_null($filename)) {
541
                    if ($this->tar->addString($localName, "") === false)
0 ignored issues
show
Bug introduced by
The method addString() does not exist on PharData. ( Ignorable by Annotation )

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

541
                    if ($this->tar->/** @scrutinizer ignore-call */ addString($localName, "") === false)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
542
                        return false;
543
                } else {
544
                    if ($this->tar->addModify($filename, $add_dir, $remove_dir) === false)
0 ignored issues
show
Bug introduced by
The method addModify() does not exist on PharData. ( Ignorable by Annotation )

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

544
                    if ($this->tar->/** @scrutinizer ignore-call */ addModify($filename, $add_dir, $remove_dir) === false)

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
545
                        return false;
546
                    $added++;
547
                }
548
            }
549
        } else {
550
            try {
551
                foreach ($files as $localName => $filename) {
552
                    if (is_null($filename)) {
553
                        $this->tar->addEmptyDir($localName);
554
                    } else {
555
                        $this->tar->addFile($filename, $localName);
556
                        $added++;
557
                    }
558
                }
559
            } catch (Exception $e) {
560
                return false;
561
            }
562
            $this->tar = null;
563
            // reopen to refresh files list properly
564
            $this->open($this->archiveType);
565
        }
566
567
        return $added;
568
    }
569
570
    /**
571
     * @return array
572
     */
573
    protected function getFileNamesForPear()
574
    {
575
        $files = [];
576
577
        $Content = $this->tar->listContent();
578
        foreach ($Content as $i => $file) {
579
            // BUG workaround: http://pear.php.net/bugs/bug.php?id=20275
580
            if ($file['filename'] === 'pax_global_header') {
581
                continue;
582
            }
583
            $files[] = $file['filename'];
584
        }
585
586
        return $files;
587
    }
588
589
    /**
590
     * @return array
591
     */
592
    protected function getFileNamesForPhar()
593
    {
594
        $files = [];
595
596
        $stream_path_length = strlen('phar://'.$this->archiveFileName.'/');
597
        foreach (new RecursiveIteratorIterator($this->tar) as $i => $file) {
598
            $files[] = substr($file->getPathname(), $stream_path_length);
599
        }
600
601
        return $files;
602
    }
603
}