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

SevenZip::createArchive()   B

Complexity

Conditions 7
Paths 19

Size

Total Lines 30
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
eloc 21
dl 0
loc 30
ccs 0
cts 16
cp 0
rs 8.6506
c 0
b 0
f 0
cc 7
nc 19
nop 5
crap 56
1
<?php
2
namespace wapmorgan\UnifiedArchive\Drivers;
3
4
use Exception;
5
use wapmorgan\UnifiedArchive\Archive7z;
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\UnsupportedOperationException;
13
use wapmorgan\UnifiedArchive\Formats;
14
15
class SevenZip extends BasicDriver
16
{
17
    /** @var Archive7z */
18
    protected $sevenZip;
19
20
    /**
21
     * @var string
22
     */
23
    protected $format;
24
25
    /**
26
     * @return array
27
     */
28 1
    public static function getSupportedFormats()
29
    {
30
        return [
31 1
            Formats::SEVEN_ZIP,
32
            Formats::ZIP,
33
            Formats::RAR,
34
            Formats::TAR,
35
            // disabled
36
//            Formats::TAR_GZIP,
37
//            Formats::TAR_BZIP,
38
            Formats::CAB,
39
            Formats::ISO,
40
            Formats::ARJ,
41
            Formats::LZMA,
42
            Formats::UEFI,
43
            Formats::GPT,
44
            Formats::MBR,
45
            Formats::MSI,
46
            Formats::DMG,
47
            Formats::RPM,
48
            Formats::DEB,
49
            Formats::UDF,
50
        ];
51
    }
52
53
    /**
54
     * @param string $format
55
     * @return bool
56
     * @throws \Archive7z\Exception
57
     */
58 3
    public static function checkFormatSupport($format)
59
    {
60 3
        $available = class_exists('\Archive7z\Archive7z') && Archive7z::getBinaryVersion() !== false;
61 3
        if (!$available)
62
            return false;
63
64
        // in 4.0.0 version it was supporting only 7z
65 3
        if (!Archive7z::supportsAllFormats())
66
            return $format === Formats::SEVEN_ZIP;
67
68
        switch ($format) {
69 3
            case Formats::SEVEN_ZIP:
70 3
            case Formats::ZIP:
71 2
            case Formats::RAR:
72 2
            case Formats::TAR:
73
//            case Formats::TAR_GZIP:
74
//            case Formats::TAR_BZIP:
75 1
            case Formats::CAB:
76 1
            case Formats::ISO:
77
            case Formats::ARJ:
78
            case Formats::LZMA:
79
            case Formats::UEFI:
80
            case Formats::GPT:
81
            case Formats::MBR:
82
            case Formats::MSI:
83
            case Formats::DMG:
84
            case Formats::RPM:
85
            case Formats::DEB:
86
            case Formats::UDF:
87 3
                return $available;
88
        }
89
    }
90
91
    /**
92
     * @inheritDoc
93
     */
94
    public static function getDescription()
95
    {
96
        return 'php-library and console program'
97
            .(class_exists('\Archive7z\Archive7z') && ($version = Archive7z::getBinaryVersion()) !== false
98
                ? ' ('.$version.')'
99
                : null);
100
    }
101
102
    /**
103
     * @inheritDoc
104
     */
105
    public static function getInstallationInstruction()
106
    {
107
        if (!class_exists('\Archive7z\Archive7z'))
108
            return 'install library `gemorroj/archive7z` and console program p7zip (7za)';
109
110
        if (Archive7z::getBinaryVersion() === false)
111
            return 'install console program p7zip (7za)';
112
113
        return null;
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119 6
    public function __construct($archiveFileName, $format, $password = null)
120
    {
121
        try {
122 6
            $this->format = $format;
123 6
            $this->sevenZip = new Archive7z($archiveFileName, null, null);
124 6
            if ($password !== null)
125 6
                $this->sevenZip->setPassword($password);
126
        } catch (\Archive7z\Exception $e) {
0 ignored issues
show
Bug introduced by
The type Archive7z\Exception 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...
127
            throw new Exception('Could not open 7Zip archive: '.$e->getMessage(), $e->getCode(), $e);
128
        }
129 6
    }
130
131
    /**
132
     * @return ArchiveInformation
133
     */
134 6
    public function getArchiveInformation()
135
    {
136 6
        $information = new ArchiveInformation();
137
138 6
        foreach ($this->sevenZip->getEntries() as $entry) {
139 6
            if ($entry->isDirectory()) {
140
                continue;
141
            }
142
143 6
            if (!isset($can_get_unix_path))
144 6
                $can_get_unix_path = method_exists($entry, 'getUnixPath');
145
146 6
            $information->files[] = $can_get_unix_path
147 6
                ? $entry->getUnixPath()
148
                : str_replace('\\', '/', $entry->getPath());
149 6
            $information->compressedFilesSize += (int)$entry->getPackedSize();
150 6
            $information->uncompressedFilesSize += (int)$entry->getSize();
151
        }
152 6
        return $information;
153
    }
154
155
    /**
156
     * @return array
157
     */
158
    public function getFileNames()
159
    {
160
        $files = [];
161
        foreach ($this->sevenZip->getEntries() as $entry) {
162
            if ($entry->isDirectory())
163
                continue;
164
            $files[] = $entry->getPath();
165
        }
166
        return $files;
167
    }
168
169
    /**
170
     * @param string $fileName
171
     *
172
     * @return bool
173
     */
174
    public function isFileExists($fileName)
175
    {
176
        return $this->sevenZip->getEntry($fileName) !== null;
177
    }
178
179
    /**
180
     * @param string $fileName
181
     *
182
     * @return ArchiveEntry|false
183
     */
184 1
    public function getFileData($fileName)
185
    {
186 1
        $entry = $this->sevenZip->getEntry($fileName);
187 1
        return new ArchiveEntry($fileName, $entry->getPackedSize(), $entry->getSize(),
188 1
            strtotime($entry->getModified()));
189
    }
190
191
    /**
192
     * @param string $fileName
193
     *
194
     * @return string|false
195
     */
196 1
    public function getFileContent($fileName)
197
    {
198 1
        $entry = $this->sevenZip->getEntry($fileName);
199 1
        return $entry->getContent();
200
    }
201
202
    /**
203
     * @param string $fileName
204
     *
205
     * @return bool|resource|string
206
     */
207 1
    public function getFileStream($fileName)
208
    {
209 1
        $entry = $this->sevenZip->getEntry($fileName);
210 1
        return self::wrapStringInStream($entry->getContent());
211
    }
212
213
    /**
214
     * @param string $outputFolder
215
     * @param array $files
216
     * @return int
217
     * @throws ArchiveExtractionException
218
     */
219
    public function extractFiles($outputFolder, array $files)
220
    {
221
        $count = 0;
222
        try {
223
            $this->sevenZip->setOutputDirectory($outputFolder);
224
225
            foreach ($files as $file) {
226
                $this->sevenZip->extractEntry($file);
227
                $count++;
228
            }
229
            return $count;
230
        } catch (Exception $e) {
231
            throw new ArchiveExtractionException('Could not extract archive: '.$e->getMessage(), $e->getCode(), $e);
232
        }
233
    }
234
235
    /**
236
     * @param string $outputFolder
237
     *
238
     * @return bool
239
     * @throws ArchiveExtractionException
240
     */
241
    public function extractArchive($outputFolder)
242
    {
243
        try {
244
            $this->sevenZip->setOutputDirectory($outputFolder);
245
            $this->sevenZip->extract();
246
            return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the return type mandated by wapmorgan\UnifiedArchive...river::extractArchive() of integer.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
247
        } catch (Exception $e) {
248
            throw new ArchiveExtractionException('Could not extract archive: '.$e->getMessage(), $e->getCode(), $e);
249
        }
250
    }
251
252
    /**
253
     * @param array $files
254
     * @return int Number of deleted files
255
     * @throws ArchiveModificationException
256
     */
257
    public function deleteFiles(array $files)
258
    {
259
        $count = 0;
260
        try {
261
            foreach ($files as $file) {
262
                $this->sevenZip->delEntry($file);
263
                $count++;
264
            }
265
            return $count;
266
        } catch (Exception $e) {
267
            throw new ArchiveModificationException('Could not modify archive: '.$e->getMessage(), $e->getCode(), $e);
268
        }
269
    }
270
271
    /**
272
     * @param array $files
273
     *
274
     * @return int
275
     * @throws ArchiveModificationException
276
     */
277
    public function addFiles(array $files)
278
    {
279
        $added_files = 0;
280
        try {
281
            foreach ($files as $localName => $filename) {
282
                if (!is_null($filename)) {
283
                    $this->sevenZip->addEntry($filename);
284
                    $this->sevenZip->renameEntry($filename, $localName);
285
                    $added_files++;
286
                }
287
            }
288
            return $added_files;
289
        } catch (Exception $e) {
290
            throw new ArchiveModificationException('Could not modify archive: '.$e->getMessage(), $e->getCode(), $e);
291
        }
292
    }
293
294
    /**
295
     * @param string $inArchiveName
296
     * @param string $content
297
     * @return bool|void
298
     * @throws ArchiveModificationException
299
     * @throws \Archive7z\Exception
300
     */
301
    public function addFileFromString($inArchiveName, $content)
302
    {
303
        $tmp_file = tempnam(sys_get_temp_dir(), 'ua');
304
        if (!$tmp_file)
305
            throw new ArchiveModificationException('Could not create temporarily file');
306
307
        file_put_contents($tmp_file, $content);
308
        $this->sevenZip->addEntry($tmp_file, true);
309
        $this->sevenZip->renameEntry($tmp_file, $inArchiveName);
310
        unlink($tmp_file);
311
        return true;
312
    }
313
314
    /**
315
     * @param array $files
316
     * @param string $archiveFileName
317
     * @param int $archiveFormat
318
     * @param int $compressionLevel
319
     * @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...
320
     * @return int
321
     * @throws ArchiveCreationException
322
     * @throws UnsupportedOperationException
323
     */
324
    public static function createArchive(array $files, $archiveFileName, $archiveFormat, $compressionLevel = self::COMPRESSION_AVERAGE, $password = null)
325
    {
326
        static $compressionLevelMap = [
327
            self::COMPRESSION_NONE => 0,
328
            self::COMPRESSION_WEAK => 2,
329
            self::COMPRESSION_AVERAGE => 4,
330
            self::COMPRESSION_STRONG => 7,
331
            self::COMPRESSION_MAXIMUM => 9,
332
        ];
333
334
        if ($password !== null && !static::canEncrypt($archiveFormat)) {
0 ignored issues
show
introduced by
The condition $password !== null is always false.
Loading history...
335
            throw new UnsupportedOperationException('SevenZip could not encrypt an archive of '.$archiveFormat.' format');
336
        }
337
338
        try {
339
            $seven_zip = new Archive7z($archiveFileName);
340
            if ($password !== null)
0 ignored issues
show
introduced by
The condition $password !== null is always false.
Loading history...
341
                $seven_zip->setPassword($password);
342
            $seven_zip->setCompressionLevel($compressionLevelMap[$compressionLevel]);
343
            foreach ($files as $localName => $filename) {
344
                if ($filename !== null) {
345
                    $seven_zip->addEntry($filename, true);
346
                    $seven_zip->renameEntry($filename, $localName);
347
                }
348
            }
349
            unset($seven_zip);
350
        } catch (Exception $e) {
351
            throw new ArchiveCreationException('Could not create archive: '.$e->getMessage(), $e->getCode(), $e);
352
        }
353
        return count($files);
354
    }
355
356
    /**
357
     * @param $format
358
     * @return bool
359
     * @throws \Archive7z\Exception
360
     */
361
    public static function canCreateArchive($format)
362
    {
363
        if (in_array($format, [
364
            Formats::SEVEN_ZIP,
365
            Formats::BZIP,
366
            Formats::GZIP,
367
            Formats::TAR,
368
            Formats::LZMA,
369
            Formats::ZIP]
370
        ))
371
            return self::canRenameFiles();
372
373
        return false;
374
    }
375
376
    /**
377
     * @param $format
378
     * @return bool
379
     * @throws \Archive7z\Exception
380
     */
381
    public static function canAddFiles($format)
382
    {
383
        return self::canCreateArchive($format);
384
    }
385
386
    /**
387
     * @return bool
388
     * @throws \Archive7z\Exception
389
     */
390
    protected static function canRenameFiles()
391
    {
392
        $version = Archive7z::getBinaryVersion();
393
        return $version !== false && version_compare('9.30', $version, '<=');
394
    }
395
396
    /**
397
     * @param $format
398
     * @return bool
399
     * @throws \Archive7z\Exception
400
     */
401
    public static function canDeleteFiles($format)
402
    {
403
        return self::canCreateArchive($format);
404
    }
405
406
    /**
407
     * @param $format
408
     * @return bool
409
     * @throws \Archive7z\Exception
410
     */
411
    public static function canEncrypt($format)
412
    {
413
        return in_array($format, [Formats::ZIP, Formats::SEVEN_ZIP]) && self::canRenameFiles();
414
    }
415
}